4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
90 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
93 enableGarbageCollector : true,
96 * True to automatically purge event listeners after uncaching an element (defaults to false).
97 * Note: this only happens if enableGarbageCollector is true.
100 enableListenerCollection:false,
103 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
104 * the IE insecure content warning (defaults to javascript:false).
107 SSL_SECURE_URL : "javascript:false",
110 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
111 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
114 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
116 emptyFn : function(){},
119 * Copies all the properties of config to obj if they don't already exist.
120 * @param {Object} obj The receiver of the properties
121 * @param {Object} config The source of the properties
122 * @return {Object} returns obj
124 applyIf : function(o, c){
127 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134 * Applies event listeners to elements by selectors when the document is ready.
135 * The event name is specified with an @ suffix.
138 // add a listener for click on all anchors in element with id foo
139 '#foo a@click' : function(e, t){
143 // add the same listener to multiple selectors (separated by comma BEFORE the @)
144 '#foo a, #bar span.some-class@mouseover' : function(){
149 * @param {Object} obj The list of behaviors to apply
151 addBehaviors : function(o){
153 Roo.onReady(function(){
158 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
160 var parts = b.split('@');
161 if(parts[1]){ // for Object prototype breakers
164 cache[s] = Roo.select(s);
166 cache[s].on(parts[1], o[b]);
173 * Generates unique ids. If the element already has an id, it is unchanged
174 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
175 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
176 * @return {String} The generated Id.
178 id : function(el, prefix){
179 prefix = prefix || "roo-gen";
181 var id = prefix + (++idSeed);
182 return el ? (el.id ? el.id : (el.id = id)) : id;
187 * Extends one class with another class and optionally overrides members with the passed literal. This class
188 * also adds the function "override()" to the class that can be used to override
189 * members on an instance.
190 * @param {Object} subclass The class inheriting the functionality
191 * @param {Object} superclass The class being extended
192 * @param {Object} overrides (optional) A literal with members
197 var io = function(o){
202 return function(sb, sp, overrides){
203 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
206 sb = function(){sp.apply(this, arguments);};
208 var F = function(){}, sbp, spp = sp.prototype;
210 sbp = sb.prototype = new F();
214 if(spp.constructor == Object.prototype.constructor){
219 sb.override = function(o){
223 Roo.override(sb, overrides);
229 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
231 Roo.override(MyClass, {
232 newMethod1: function(){
235 newMethod2: function(foo){
240 * @param {Object} origclass The class to override
241 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
242 * containing one or more methods.
245 override : function(origclass, overrides){
247 var p = origclass.prototype;
248 for(var method in overrides){
249 p[method] = overrides[method];
254 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
256 Roo.namespace('Company', 'Company.data');
257 Company.Widget = function() { ... }
258 Company.data.CustomStore = function(config) { ... }
260 * @param {String} namespace1
261 * @param {String} namespace2
262 * @param {String} etc
265 namespace : function(){
266 var a=arguments, o=null, i, j, d, rt;
267 for (i=0; i<a.length; ++i) {
271 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
272 for (j=1; j<d.length; ++j) {
273 o[d[j]]=o[d[j]] || {};
279 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
281 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
282 Roo.factory(conf, Roo.data);
284 * @param {String} classname
285 * @param {String} namespace (optional)
289 factory : function(c, ns)
291 // no xtype, no ns or c.xns - or forced off by c.xns
292 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
295 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
296 if (c.constructor == ns[c.xtype]) {// already created...
300 if (Roo.debug) console.log("Roo.Factory(" + c.xtype + ")");
301 var ret = new ns[c.xtype](c);
305 c.xns = false; // prevent recursion..
310 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
314 urlEncode : function(o){
320 var ov = o[key], k = encodeURIComponent(key);
321 var type = typeof ov;
322 if(type == 'undefined'){
324 }else if(type != "function" && type != "object"){
325 buf.push(k, "=", encodeURIComponent(ov), "&");
326 }else if(ov instanceof Array){
328 for(var i = 0, len = ov.length; i < len; i++) {
329 buf.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
341 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
342 * @param {String} string
343 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
344 * @return {Object} A literal with members
346 urlDecode : function(string, overwrite){
347 if(!string || !string.length){
351 var pairs = string.split('&');
352 var pair, name, value;
353 for(var i = 0, len = pairs.length; i < len; i++){
354 pair = pairs[i].split('=');
355 name = decodeURIComponent(pair[0]);
356 value = decodeURIComponent(pair[1]);
357 if(overwrite !== true){
358 if(typeof obj[name] == "undefined"){
360 }else if(typeof obj[name] == "string"){
361 obj[name] = [obj[name]];
362 obj[name].push(value);
364 obj[name].push(value);
374 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
375 * passed array is not really an array, your function is called once with it.
376 * The supplied function is called with (Object item, Number index, Array allItems).
377 * @param {Array/NodeList/Mixed} array
378 * @param {Function} fn
379 * @param {Object} scope
381 each : function(array, fn, scope){
382 if(typeof array.length == "undefined" || typeof array == "string"){
385 for(var i = 0, len = array.length; i < len; i++){
386 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
391 combine : function(){
392 var as = arguments, l = as.length, r = [];
393 for(var i = 0; i < l; i++){
395 if(a instanceof Array){
397 }else if(a.length !== undefined && !a.substr){
398 r = r.concat(Array.prototype.slice.call(a, 0));
407 * Escapes the passed string for use in a regular expression
408 * @param {String} str
411 escapeRe : function(s) {
412 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
416 callback : function(cb, scope, args, delay){
417 if(typeof cb == "function"){
419 cb.defer(delay, scope, args || []);
421 cb.apply(scope, args || []);
427 * Return the dom node for the passed string (id), dom node, or Roo.Element
428 * @param {String/HTMLElement/Roo.Element} el
429 * @return HTMLElement
431 getDom : function(el){
435 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
439 * Shorthand for {@link Roo.ComponentMgr#get}
441 * @return Roo.Component
443 getCmp : function(id){
444 return Roo.ComponentMgr.get(id);
447 num : function(v, defaultValue){
448 if(typeof v != 'number'){
454 destroy : function(){
455 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
459 as.removeAllListeners();
463 if(typeof as.purgeListeners == 'function'){
466 if(typeof as.destroy == 'function'){
473 // inpired by a similar function in mootools library
475 * Returns the type of object that is passed in. If the object passed in is null or undefined it
476 * return false otherwise it returns one of the following values:<ul>
477 * <li><b>string</b>: If the object passed is a string</li>
478 * <li><b>number</b>: If the object passed is a number</li>
479 * <li><b>boolean</b>: If the object passed is a boolean value</li>
480 * <li><b>function</b>: If the object passed is a function reference</li>
481 * <li><b>object</b>: If the object passed is an object</li>
482 * <li><b>array</b>: If the object passed is an array</li>
483 * <li><b>regexp</b>: If the object passed is a regular expression</li>
484 * <li><b>element</b>: If the object passed is a DOM Element</li>
485 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
486 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
487 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
488 * @param {Mixed} object
492 if(o === undefined || o === null){
499 if(t == 'object' && o.nodeName) {
501 case 1: return 'element';
502 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
505 if(t == 'object' || t == 'function') {
506 switch(o.constructor) {
507 case Array: return 'array';
508 case RegExp: return 'regexp';
510 if(typeof o.length == 'number' && typeof o.item == 'function') {
518 * Returns true if the passed value is null, undefined or an empty string (optional).
519 * @param {Mixed} value The value to test
520 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
523 isEmpty : function(v, allowBlank){
524 return v === null || v === undefined || (!allowBlank ? v === '' : false);
538 isBorderBox : isBorderBox,
540 isWindows : isWindows,
547 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
548 * you may want to set this to true.
551 useShims : ((isIE && !isIE7) || (isGecko && isMac))
557 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
558 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
561 * Ext JS Library 1.1.1
562 * Copyright(c) 2006-2007, Ext JS, LLC.
564 * Originally Released Under LGPL - original licence link has changed is not relivant.
567 * <script type="text/javascript">
571 // wrappedn so fnCleanup is not in global scope...
573 function fnCleanUp() {
574 var p = Function.prototype;
575 delete p.createSequence;
577 delete p.createDelegate;
578 delete p.createCallback;
579 delete p.createInterceptor;
581 window.detachEvent("onunload", fnCleanUp);
583 window.attachEvent("onunload", fnCleanUp);
590 * These functions are available on every Function object (any JavaScript function).
592 Roo.apply(Function.prototype, {
594 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
595 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
596 * Will create a function that is bound to those 2 args.
597 * @return {Function} The new function
599 createCallback : function(/*args...*/){
600 // make args available, in function below
601 var args = arguments;
604 return method.apply(window, args);
609 * Creates a delegate (callback) that sets the scope to obj.
610 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
611 * Will create a function that is automatically scoped to this.
612 * @param {Object} obj (optional) The object for which the scope is set
613 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
614 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
615 * if a number the args are inserted at the specified position
616 * @return {Function} The new function
618 createDelegate : function(obj, args, appendArgs){
621 var callArgs = args || arguments;
622 if(appendArgs === true){
623 callArgs = Array.prototype.slice.call(arguments, 0);
624 callArgs = callArgs.concat(args);
625 }else if(typeof appendArgs == "number"){
626 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
627 var applyArgs = [appendArgs, 0].concat(args); // create method call params
628 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
630 return method.apply(obj || window, callArgs);
635 * Calls this function after the number of millseconds specified.
636 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
637 * @param {Object} obj (optional) The object for which the scope is set
638 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
639 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
640 * if a number the args are inserted at the specified position
641 * @return {Number} The timeout id that can be used with clearTimeout
643 defer : function(millis, obj, args, appendArgs){
644 var fn = this.createDelegate(obj, args, appendArgs);
646 return setTimeout(fn, millis);
652 * Create a combined function call sequence of the original function + the passed function.
653 * The resulting function returns the results of the original function.
654 * The passed fcn is called with the parameters of the original function
655 * @param {Function} fcn The function to sequence
656 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
657 * @return {Function} The new function
659 createSequence : function(fcn, scope){
660 if(typeof fcn != "function"){
665 var retval = method.apply(this || window, arguments);
666 fcn.apply(scope || this || window, arguments);
672 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
673 * The resulting function returns the results of the original function.
674 * The passed fcn is called with the parameters of the original function.
676 * @param {Function} fcn The function to call before the original
677 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
678 * @return {Function} The new function
680 createInterceptor : function(fcn, scope){
681 if(typeof fcn != "function"){
688 if(fcn.apply(scope || this || window, arguments) === false){
691 return method.apply(this || window, arguments);
697 * Ext JS Library 1.1.1
698 * Copyright(c) 2006-2007, Ext JS, LLC.
700 * Originally Released Under LGPL - original licence link has changed is not relivant.
703 * <script type="text/javascript">
706 Roo.applyIf(String, {
711 * Escapes the passed string for ' and \
712 * @param {String} string The string to escape
713 * @return {String} The escaped string
716 escape : function(string) {
717 return string.replace(/('|\\)/g, "\\$1");
721 * Pads the left side of a string with a specified character. This is especially useful
722 * for normalizing number and date strings. Example usage:
724 var s = String.leftPad('123', 5, '0');
725 // s now contains the string: '00123'
727 * @param {String} string The original string
728 * @param {Number} size The total length of the output string
729 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
730 * @return {String} The padded string
733 leftPad : function (val, size, ch) {
734 var result = new String(val);
735 if(ch === null || ch === undefined || ch === '') {
738 while (result.length < size) {
739 result = ch + result;
745 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
746 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
748 var cls = 'my-class', text = 'Some text';
749 var s = String.format('<div class="{0}">{1}</div>', cls, text);
750 // s now contains the string: '<div class="my-class">Some text</div>'
752 * @param {String} string The tokenized string to be formatted
753 * @param {String} value1 The value to replace token {0}
754 * @param {String} value2 Etc...
755 * @return {String} The formatted string
758 format : function(format){
759 var args = Array.prototype.slice.call(arguments, 1);
760 return format.replace(/\{(\d+)\}/g, function(m, i){
761 return Roo.util.Format.htmlEncode(args[i]);
767 * Utility function that allows you to easily switch a string between two alternating values. The passed value
768 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
769 * they are already different, the first value passed in is returned. Note that this method returns the new value
770 * but does not change the current string.
772 // alternate sort directions
773 sort = sort.toggle('ASC', 'DESC');
775 // instead of conditional logic:
776 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
778 * @param {String} value The value to compare to the current string
779 * @param {String} other The new value to use if the string already equals the first value passed in
780 * @return {String} The new value
783 String.prototype.toggle = function(value, other){
784 return this == value ? other : value;
787 * Ext JS Library 1.1.1
788 * Copyright(c) 2006-2007, Ext JS, LLC.
790 * Originally Released Under LGPL - original licence link has changed is not relivant.
793 * <script type="text/javascript">
799 Roo.applyIf(Number.prototype, {
801 * Checks whether or not the current number is within a desired range. If the number is already within the
802 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
803 * exceeded. Note that this method returns the constrained value but does not change the current number.
804 * @param {Number} min The minimum number in the range
805 * @param {Number} max The maximum number in the range
806 * @return {Number} The constrained value if outside the range, otherwise the current value
808 constrain : function(min, max){
809 return Math.min(Math.max(this, min), max);
813 * Ext JS Library 1.1.1
814 * Copyright(c) 2006-2007, Ext JS, LLC.
816 * Originally Released Under LGPL - original licence link has changed is not relivant.
819 * <script type="text/javascript">
824 Roo.applyIf(Array.prototype, {
826 * Checks whether or not the specified object exists in the array.
827 * @param {Object} o The object to check for
828 * @return {Number} The index of o in the array (or -1 if it is not found)
830 indexOf : function(o){
831 for (var i = 0, len = this.length; i < len; i++){
832 if(this[i] == o) return i;
838 * Removes the specified object from the array. If the object is not found nothing happens.
839 * @param {Object} o The object to remove
841 remove : function(o){
842 var index = this.indexOf(o);
844 this.splice(index, 1);
848 * Map (JS 1.6 compatibility)
849 * @param {Function} function to call
851 map : function(fun /*, thisp*/)
853 var len = this.length >>> 0;
854 if (typeof fun != "function")
855 throw new TypeError();
857 var res = new Array(len);
858 var thisp = arguments[1];
859 for (var i = 0; i < len; i++)
862 res[i] = fun.call(thisp, this[i], i, this);
872 if (!Array.prototype.map)
877 * Ext JS Library 1.1.1
878 * Copyright(c) 2006-2007, Ext JS, LLC.
880 * Originally Released Under LGPL - original licence link has changed is not relivant.
883 * <script type="text/javascript">
889 * The date parsing and format syntax is a subset of
890 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
891 * supported will provide results equivalent to their PHP versions.
893 * Following is the list of all currently supported formats:
896 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
898 Format Output Description
899 ------ ---------- --------------------------------------------------------------
900 d 10 Day of the month, 2 digits with leading zeros
901 D Wed A textual representation of a day, three letters
902 j 10 Day of the month without leading zeros
903 l Wednesday A full textual representation of the day of the week
904 S th English ordinal day of month suffix, 2 chars (use with j)
905 w 3 Numeric representation of the day of the week
906 z 9 The julian date, or day of the year (0-365)
907 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
908 F January A full textual representation of the month
909 m 01 Numeric representation of a month, with leading zeros
910 M Jan Month name abbreviation, three letters
911 n 1 Numeric representation of a month, without leading zeros
912 t 31 Number of days in the given month
913 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
914 Y 2007 A full numeric representation of a year, 4 digits
915 y 07 A two digit representation of a year
916 a pm Lowercase Ante meridiem and Post meridiem
917 A PM Uppercase Ante meridiem and Post meridiem
918 g 3 12-hour format of an hour without leading zeros
919 G 15 24-hour format of an hour without leading zeros
920 h 03 12-hour format of an hour with leading zeros
921 H 15 24-hour format of an hour with leading zeros
922 i 05 Minutes with leading zeros
923 s 01 Seconds, with leading zeros
924 O -0600 Difference to Greenwich time (GMT) in hours
925 T CST Timezone setting of the machine running the code
926 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
929 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
931 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
932 document.write(dt.format('Y-m-d')); //2007-01-10
933 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
934 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
937 * Here are some standard date/time patterns that you might find helpful. They
938 * are not part of the source of Date.js, but to use them you can simply copy this
939 * block of code into any script that is included after Date.js and they will also become
940 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
943 ISO8601Long:"Y-m-d H:i:s",
944 ISO8601Short:"Y-m-d",
946 LongDate: "l, F d, Y",
947 FullDateTime: "l, F d, Y g:i:s A",
951 SortableDateTime: "Y-m-d\\TH:i:s",
952 UniversalSortableDateTime: "Y-m-d H:i:sO",
960 document.write(dt.format(Date.patterns.ShortDate));
965 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
966 * They generate precompiled functions from date formats instead of parsing and
967 * processing the pattern every time you format a date. These functions are available
968 * on every Date object (any javascript function).
970 * The original article and download are here:
971 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
978 Returns the number of milliseconds between this date and date
979 @param {Date} date (optional) Defaults to now
980 @return {Number} The diff in milliseconds
981 @member Date getElapsed
983 Date.prototype.getElapsed = function(date) {
984 return Math.abs((date || new Date()).getTime()-this.getTime());
986 // was in date file..
990 Date.parseFunctions = {count:0};
992 Date.parseRegexes = [];
994 Date.formatFunctions = {count:0};
997 Date.prototype.dateFormat = function(format) {
998 if (Date.formatFunctions[format] == null) {
999 Date.createNewFormat(format);
1001 var func = Date.formatFunctions[format];
1002 return this[func]();
1007 * Formats a date given the supplied format string
1008 * @param {String} format The format string
1009 * @return {String} The formatted date
1012 Date.prototype.format = Date.prototype.dateFormat;
1015 Date.createNewFormat = function(format) {
1016 var funcName = "format" + Date.formatFunctions.count++;
1017 Date.formatFunctions[format] = funcName;
1018 var code = "Date.prototype." + funcName + " = function(){return ";
1019 var special = false;
1021 for (var i = 0; i < format.length; ++i) {
1022 ch = format.charAt(i);
1023 if (!special && ch == "\\") {
1028 code += "'" + String.escape(ch) + "' + ";
1031 code += Date.getFormatCode(ch);
1034 /** eval:var:zzzzzzzzzzzzz */
1035 eval(code.substring(0, code.length - 3) + ";}");
1039 Date.getFormatCode = function(character) {
1040 switch (character) {
1042 return "String.leftPad(this.getDate(), 2, '0') + ";
1044 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1046 return "this.getDate() + ";
1048 return "Date.dayNames[this.getDay()] + ";
1050 return "this.getSuffix() + ";
1052 return "this.getDay() + ";
1054 return "this.getDayOfYear() + ";
1056 return "this.getWeekOfYear() + ";
1058 return "Date.monthNames[this.getMonth()] + ";
1060 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1062 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1064 return "(this.getMonth() + 1) + ";
1066 return "this.getDaysInMonth() + ";
1068 return "(this.isLeapYear() ? 1 : 0) + ";
1070 return "this.getFullYear() + ";
1072 return "('' + this.getFullYear()).substring(2, 4) + ";
1074 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1076 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1078 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1080 return "this.getHours() + ";
1082 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1084 return "String.leftPad(this.getHours(), 2, '0') + ";
1086 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1088 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1090 return "this.getGMTOffset() + ";
1092 return "this.getTimezone() + ";
1094 return "(this.getTimezoneOffset() * -60) + ";
1096 return "'" + String.escape(character) + "' + ";
1101 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1102 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1103 * the date format that is not specified will default to the current date value for that part. Time parts can also
1104 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1105 * string or the parse operation will fail.
1108 //dt = Fri May 25 2007 (current date)
1109 var dt = new Date();
1111 //dt = Thu May 25 2006 (today's month/day in 2006)
1112 dt = Date.parseDate("2006", "Y");
1114 //dt = Sun Jan 15 2006 (all date parts specified)
1115 dt = Date.parseDate("2006-1-15", "Y-m-d");
1117 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1118 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1120 * @param {String} input The unparsed date as a string
1121 * @param {String} format The format the date is in
1122 * @return {Date} The parsed date
1125 Date.parseDate = function(input, format) {
1126 if (Date.parseFunctions[format] == null) {
1127 Date.createParser(format);
1129 var func = Date.parseFunctions[format];
1130 return Date[func](input);
1135 Date.createParser = function(format) {
1136 var funcName = "parse" + Date.parseFunctions.count++;
1137 var regexNum = Date.parseRegexes.length;
1138 var currentGroup = 1;
1139 Date.parseFunctions[format] = funcName;
1141 var code = "Date." + funcName + " = function(input){\n"
1142 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1143 + "var d = new Date();\n"
1144 + "y = d.getFullYear();\n"
1145 + "m = d.getMonth();\n"
1146 + "d = d.getDate();\n"
1147 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1148 + "if (results && results.length > 0) {";
1151 var special = false;
1153 for (var i = 0; i < format.length; ++i) {
1154 ch = format.charAt(i);
1155 if (!special && ch == "\\") {
1160 regex += String.escape(ch);
1163 var obj = Date.formatCodeToRegex(ch, currentGroup);
1164 currentGroup += obj.g;
1166 if (obj.g && obj.c) {
1172 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1173 + "{v = new Date(y, m, d, h, i, s);}\n"
1174 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1175 + "{v = new Date(y, m, d, h, i);}\n"
1176 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1177 + "{v = new Date(y, m, d, h);}\n"
1178 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1179 + "{v = new Date(y, m, d);}\n"
1180 + "else if (y >= 0 && m >= 0)\n"
1181 + "{v = new Date(y, m);}\n"
1182 + "else if (y >= 0)\n"
1183 + "{v = new Date(y);}\n"
1184 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1185 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1186 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1189 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1190 /** eval:var:zzzzzzzzzzzzz */
1195 Date.formatCodeToRegex = function(character, currentGroup) {
1196 switch (character) {
1200 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1203 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1204 s:"(\\d{1,2})"}; // day of month without leading zeroes
1207 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1208 s:"(\\d{2})"}; // day of month with leading zeroes
1212 s:"(?:" + Date.dayNames.join("|") + ")"};
1216 s:"(?:st|nd|rd|th)"};
1231 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1232 s:"(" + Date.monthNames.join("|") + ")"};
1235 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1236 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1239 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1240 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1243 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1244 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1255 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1259 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1260 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1264 c:"if (results[" + currentGroup + "] == 'am') {\n"
1265 + "if (h == 12) { h = 0; }\n"
1266 + "} else { if (h < 12) { h += 12; }}",
1270 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1271 + "if (h == 12) { h = 0; }\n"
1272 + "} else { if (h < 12) { h += 12; }}",
1277 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1278 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1282 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1283 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1286 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1290 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1295 "o = results[", currentGroup, "];\n",
1296 "var sn = o.substring(0,1);\n", // get + / - sign
1297 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1298 "var mn = o.substring(3,5) % 60;\n", // get minutes
1299 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1300 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1306 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1309 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1310 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1311 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1315 s:String.escape(character)};
1320 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1321 * @return {String} The abbreviated timezone name (e.g. 'CST')
1323 Date.prototype.getTimezone = function() {
1324 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1328 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1329 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1331 Date.prototype.getGMTOffset = function() {
1332 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1333 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1334 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1338 * Get the numeric day number of the year, adjusted for leap year.
1339 * @return {Number} 0 through 364 (365 in leap years)
1341 Date.prototype.getDayOfYear = function() {
1343 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1344 for (var i = 0; i < this.getMonth(); ++i) {
1345 num += Date.daysInMonth[i];
1347 return num + this.getDate() - 1;
1351 * Get the string representation of the numeric week number of the year
1352 * (equivalent to the format specifier 'W').
1353 * @return {String} '00' through '52'
1355 Date.prototype.getWeekOfYear = function() {
1356 // Skip to Thursday of this week
1357 var now = this.getDayOfYear() + (4 - this.getDay());
1358 // Find the first Thursday of the year
1359 var jan1 = new Date(this.getFullYear(), 0, 1);
1360 var then = (7 - jan1.getDay() + 4);
1361 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1365 * Whether or not the current date is in a leap year.
1366 * @return {Boolean} True if the current date is in a leap year, else false
1368 Date.prototype.isLeapYear = function() {
1369 var year = this.getFullYear();
1370 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1374 * Get the first day of the current month, adjusted for leap year. The returned value
1375 * is the numeric day index within the week (0-6) which can be used in conjunction with
1376 * the {@link #monthNames} array to retrieve the textual day name.
1379 var dt = new Date('1/10/2007');
1380 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1382 * @return {Number} The day number (0-6)
1384 Date.prototype.getFirstDayOfMonth = function() {
1385 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1386 return (day < 0) ? (day + 7) : day;
1390 * Get the last day of the current month, adjusted for leap year. The returned value
1391 * is the numeric day index within the week (0-6) which can be used in conjunction with
1392 * the {@link #monthNames} array to retrieve the textual day name.
1395 var dt = new Date('1/10/2007');
1396 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1398 * @return {Number} The day number (0-6)
1400 Date.prototype.getLastDayOfMonth = function() {
1401 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1402 return (day < 0) ? (day + 7) : day;
1407 * Get the first date of this date's month
1410 Date.prototype.getFirstDateOfMonth = function() {
1411 return new Date(this.getFullYear(), this.getMonth(), 1);
1415 * Get the last date of this date's month
1418 Date.prototype.getLastDateOfMonth = function() {
1419 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1422 * Get the number of days in the current month, adjusted for leap year.
1423 * @return {Number} The number of days in the month
1425 Date.prototype.getDaysInMonth = function() {
1426 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1427 return Date.daysInMonth[this.getMonth()];
1431 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1432 * @return {String} 'st, 'nd', 'rd' or 'th'
1434 Date.prototype.getSuffix = function() {
1435 switch (this.getDate()) {
1452 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1455 * An array of textual month names.
1456 * Override these values for international dates, for example...
1457 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1476 * An array of textual day names.
1477 * Override these values for international dates, for example...
1478 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1494 Date.monthNumbers = {
1509 * Creates and returns a new Date instance with the exact same date value as the called instance.
1510 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1511 * variable will also be changed. When the intention is to create a new variable that will not
1512 * modify the original instance, you should create a clone.
1514 * Example of correctly cloning a date:
1517 var orig = new Date('10/1/2006');
1520 document.write(orig); //returns 'Thu Oct 05 2006'!
1523 var orig = new Date('10/1/2006');
1524 var copy = orig.clone();
1526 document.write(orig); //returns 'Thu Oct 01 2006'
1528 * @return {Date} The new Date instance
1530 Date.prototype.clone = function() {
1531 return new Date(this.getTime());
1535 * Clears any time information from this date
1536 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1537 @return {Date} this or the clone
1539 Date.prototype.clearTime = function(clone){
1541 return this.clone().clearTime();
1546 this.setMilliseconds(0);
1551 // safari setMonth is broken
1553 Date.brokenSetMonth = Date.prototype.setMonth;
1554 Date.prototype.setMonth = function(num){
1556 var n = Math.ceil(-num);
1557 var back_year = Math.ceil(n/12);
1558 var month = (n % 12) ? 12 - n % 12 : 0 ;
1559 this.setFullYear(this.getFullYear() - back_year);
1560 return Date.brokenSetMonth.call(this, month);
1562 return Date.brokenSetMonth.apply(this, arguments);
1567 /** Date interval constant
1571 /** Date interval constant
1575 /** Date interval constant
1579 /** Date interval constant
1583 /** Date interval constant
1587 /** Date interval constant
1591 /** Date interval constant
1597 * Provides a convenient method of performing basic date arithmetic. This method
1598 * does not modify the Date instance being called - it creates and returns
1599 * a new Date instance containing the resulting date value.
1604 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1605 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1607 //Negative values will subtract correctly:
1608 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1609 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1611 //You can even chain several calls together in one line!
1612 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1613 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1616 * @param {String} interval A valid date interval enum value
1617 * @param {Number} value The amount to add to the current date
1618 * @return {Date} The new Date instance
1620 Date.prototype.add = function(interval, value){
1621 var d = this.clone();
1622 if (!interval || value === 0) return d;
1623 switch(interval.toLowerCase()){
1625 d.setMilliseconds(this.getMilliseconds() + value);
1628 d.setSeconds(this.getSeconds() + value);
1631 d.setMinutes(this.getMinutes() + value);
1634 d.setHours(this.getHours() + value);
1637 d.setDate(this.getDate() + value);
1640 var day = this.getDate();
1642 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1645 d.setMonth(this.getMonth() + value);
1648 d.setFullYear(this.getFullYear() + value);
1654 * Ext JS Library 1.1.1
1655 * Copyright(c) 2006-2007, Ext JS, LLC.
1657 * Originally Released Under LGPL - original licence link has changed is not relivant.
1660 * <script type="text/javascript">
1664 getViewWidth : function(full) {
1665 return full ? this.getDocumentWidth() : this.getViewportWidth();
1668 getViewHeight : function(full) {
1669 return full ? this.getDocumentHeight() : this.getViewportHeight();
1672 getDocumentHeight: function() {
1673 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1674 return Math.max(scrollHeight, this.getViewportHeight());
1677 getDocumentWidth: function() {
1678 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1679 return Math.max(scrollWidth, this.getViewportWidth());
1682 getViewportHeight: function() {
1683 var height = self.innerHeight;
1684 var mode = document.compatMode;
1686 if ((mode || Roo.isIE) && !Roo.isOpera) {
1687 height = (mode == "CSS1Compat") ?
1688 document.documentElement.clientHeight :
1689 document.body.clientHeight;
1695 getViewportWidth: function() {
1696 var width = self.innerWidth;
1697 var mode = document.compatMode;
1699 if (mode || Roo.isIE) {
1700 width = (mode == "CSS1Compat") ?
1701 document.documentElement.clientWidth :
1702 document.body.clientWidth;
1707 isAncestor : function(p, c) {
1714 if (p.contains && !Roo.isSafari) {
1715 return p.contains(c);
1716 } else if (p.compareDocumentPosition) {
1717 return !!(p.compareDocumentPosition(c) & 16);
1719 var parent = c.parentNode;
1724 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1727 parent = parent.parentNode;
1733 getRegion : function(el) {
1734 return Roo.lib.Region.getRegion(el);
1737 getY : function(el) {
1738 return this.getXY(el)[1];
1741 getX : function(el) {
1742 return this.getXY(el)[0];
1745 getXY : function(el) {
1746 var p, pe, b, scroll, bd = document.body;
1747 el = Roo.getDom(el);
1748 var fly = Roo.lib.AnimBase.fly;
1749 if (el.getBoundingClientRect) {
1750 b = el.getBoundingClientRect();
1751 scroll = fly(document).getScroll();
1752 return [b.left + scroll.left, b.top + scroll.top];
1758 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1765 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1772 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1773 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1780 if (p != el && pe.getStyle('overflow') != 'visible') {
1788 if (Roo.isSafari && hasAbsolute) {
1793 if (Roo.isGecko && !hasAbsolute) {
1795 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1796 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1800 while (p && p != bd) {
1801 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1813 setXY : function(el, xy) {
1814 el = Roo.fly(el, '_setXY');
1816 var pts = el.translatePoints(xy);
1817 if (xy[0] !== false) {
1818 el.dom.style.left = pts.left + "px";
1820 if (xy[1] !== false) {
1821 el.dom.style.top = pts.top + "px";
1825 setX : function(el, x) {
1826 this.setXY(el, [x, false]);
1829 setY : function(el, y) {
1830 this.setXY(el, [false, y]);
1834 * Portions of this file are based on pieces of Yahoo User Interface Library
1835 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1836 * YUI licensed under the BSD License:
1837 * http://developer.yahoo.net/yui/license.txt
1838 * <script type="text/javascript">
1842 Roo.lib.Event = function() {
1843 var loadComplete = false;
1845 var unloadListeners = [];
1847 var onAvailStack = [];
1849 var lastError = null;
1862 startInterval: function() {
1863 if (!this._interval) {
1865 var callback = function() {
1866 self._tryPreloadAttach();
1868 this._interval = setInterval(callback, this.POLL_INTERVAL);
1873 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1874 onAvailStack.push({ id: p_id,
1877 override: p_override,
1878 checkReady: false });
1880 retryCount = this.POLL_RETRYS;
1881 this.startInterval();
1885 addListener: function(el, eventName, fn) {
1886 el = Roo.getDom(el);
1891 if ("unload" == eventName) {
1892 unloadListeners[unloadListeners.length] =
1893 [el, eventName, fn];
1897 var wrappedFn = function(e) {
1898 return fn(Roo.lib.Event.getEvent(e));
1901 var li = [el, eventName, fn, wrappedFn];
1903 var index = listeners.length;
1904 listeners[index] = li;
1906 this.doAdd(el, eventName, wrappedFn, false);
1912 removeListener: function(el, eventName, fn) {
1915 el = Roo.getDom(el);
1918 return this.purgeElement(el, false, eventName);
1922 if ("unload" == eventName) {
1924 for (i = 0,len = unloadListeners.length; i < len; i++) {
1925 var li = unloadListeners[i];
1928 li[1] == eventName &&
1930 unloadListeners.splice(i, 1);
1938 var cacheItem = null;
1941 var index = arguments[3];
1943 if ("undefined" == typeof index) {
1944 index = this._getCacheIndex(el, eventName, fn);
1948 cacheItem = listeners[index];
1951 if (!el || !cacheItem) {
1955 this.doRemove(el, eventName, cacheItem[this.WFN], false);
1957 delete listeners[index][this.WFN];
1958 delete listeners[index][this.FN];
1959 listeners.splice(index, 1);
1966 getTarget: function(ev, resolveTextNode) {
1967 ev = ev.browserEvent || ev;
1968 var t = ev.target || ev.srcElement;
1969 return this.resolveTextNode(t);
1973 resolveTextNode: function(node) {
1974 if (Roo.isSafari && node && 3 == node.nodeType) {
1975 return node.parentNode;
1982 getPageX: function(ev) {
1983 ev = ev.browserEvent || ev;
1985 if (!x && 0 !== x) {
1986 x = ev.clientX || 0;
1989 x += this.getScroll()[1];
1997 getPageY: function(ev) {
1998 ev = ev.browserEvent || ev;
2000 if (!y && 0 !== y) {
2001 y = ev.clientY || 0;
2004 y += this.getScroll()[0];
2013 getXY: function(ev) {
2014 ev = ev.browserEvent || ev;
2015 return [this.getPageX(ev), this.getPageY(ev)];
2019 getRelatedTarget: function(ev) {
2020 ev = ev.browserEvent || ev;
2021 var t = ev.relatedTarget;
2023 if (ev.type == "mouseout") {
2025 } else if (ev.type == "mouseover") {
2030 return this.resolveTextNode(t);
2034 getTime: function(ev) {
2035 ev = ev.browserEvent || ev;
2037 var t = new Date().getTime();
2041 this.lastError = ex;
2050 stopEvent: function(ev) {
2051 this.stopPropagation(ev);
2052 this.preventDefault(ev);
2056 stopPropagation: function(ev) {
2057 ev = ev.browserEvent || ev;
2058 if (ev.stopPropagation) {
2059 ev.stopPropagation();
2061 ev.cancelBubble = true;
2066 preventDefault: function(ev) {
2067 ev = ev.browserEvent || ev;
2068 if(ev.preventDefault) {
2069 ev.preventDefault();
2071 ev.returnValue = false;
2076 getEvent: function(e) {
2077 var ev = e || window.event;
2079 var c = this.getEvent.caller;
2081 ev = c.arguments[0];
2082 if (ev && Event == ev.constructor) {
2092 getCharCode: function(ev) {
2093 ev = ev.browserEvent || ev;
2094 return ev.charCode || ev.keyCode || 0;
2098 _getCacheIndex: function(el, eventName, fn) {
2099 for (var i = 0,len = listeners.length; i < len; ++i) {
2100 var li = listeners[i];
2102 li[this.FN] == fn &&
2103 li[this.EL] == el &&
2104 li[this.TYPE] == eventName) {
2116 getEl: function(id) {
2117 return document.getElementById(id);
2121 clearCache: function() {
2125 _load: function(e) {
2126 loadComplete = true;
2127 var EU = Roo.lib.Event;
2131 EU.doRemove(window, "load", EU._load);
2136 _tryPreloadAttach: function() {
2145 var tryAgain = !loadComplete;
2147 tryAgain = (retryCount > 0);
2152 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2153 var item = onAvailStack[i];
2155 var el = this.getEl(item.id);
2158 if (!item.checkReady ||
2161 (document && document.body)) {
2164 if (item.override) {
2165 if (item.override === true) {
2168 scope = item.override;
2171 item.fn.call(scope, item.obj);
2172 onAvailStack[i] = null;
2175 notAvail.push(item);
2180 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2184 this.startInterval();
2186 clearInterval(this._interval);
2187 this._interval = null;
2190 this.locked = false;
2197 purgeElement: function(el, recurse, eventName) {
2198 var elListeners = this.getListeners(el, eventName);
2200 for (var i = 0,len = elListeners.length; i < len; ++i) {
2201 var l = elListeners[i];
2202 this.removeListener(el, l.type, l.fn);
2206 if (recurse && el && el.childNodes) {
2207 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2208 this.purgeElement(el.childNodes[i], recurse, eventName);
2214 getListeners: function(el, eventName) {
2215 var results = [], searchLists;
2217 searchLists = [listeners, unloadListeners];
2218 } else if (eventName == "unload") {
2219 searchLists = [unloadListeners];
2221 searchLists = [listeners];
2224 for (var j = 0; j < searchLists.length; ++j) {
2225 var searchList = searchLists[j];
2226 if (searchList && searchList.length > 0) {
2227 for (var i = 0,len = searchList.length; i < len; ++i) {
2228 var l = searchList[i];
2229 if (l && l[this.EL] === el &&
2230 (!eventName || eventName === l[this.TYPE])) {
2235 adjust: l[this.ADJ_SCOPE],
2243 return (results.length) ? results : null;
2247 _unload: function(e) {
2249 var EU = Roo.lib.Event, i, j, l, len, index;
2251 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2252 l = unloadListeners[i];
2255 if (l[EU.ADJ_SCOPE]) {
2256 if (l[EU.ADJ_SCOPE] === true) {
2259 scope = l[EU.ADJ_SCOPE];
2262 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2263 unloadListeners[i] = null;
2269 unloadListeners = null;
2271 if (listeners && listeners.length > 0) {
2272 j = listeners.length;
2275 l = listeners[index];
2277 EU.removeListener(l[EU.EL], l[EU.TYPE],
2287 EU.doRemove(window, "unload", EU._unload);
2292 getScroll: function() {
2293 var dd = document.documentElement, db = document.body;
2294 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2295 return [dd.scrollTop, dd.scrollLeft];
2297 return [db.scrollTop, db.scrollLeft];
2304 doAdd: function () {
2305 if (window.addEventListener) {
2306 return function(el, eventName, fn, capture) {
2307 el.addEventListener(eventName, fn, (capture));
2309 } else if (window.attachEvent) {
2310 return function(el, eventName, fn, capture) {
2311 el.attachEvent("on" + eventName, fn);
2320 doRemove: function() {
2321 if (window.removeEventListener) {
2322 return function (el, eventName, fn, capture) {
2323 el.removeEventListener(eventName, fn, (capture));
2325 } else if (window.detachEvent) {
2326 return function (el, eventName, fn) {
2327 el.detachEvent("on" + eventName, fn);
2339 var E = Roo.lib.Event;
2340 E.on = E.addListener;
2341 E.un = E.removeListener;
2343 if (document && document.body) {
2346 E.doAdd(window, "load", E._load);
2348 E.doAdd(window, "unload", E._unload);
2349 E._tryPreloadAttach();
2353 * Portions of this file are based on pieces of Yahoo User Interface Library
2354 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2355 * YUI licensed under the BSD License:
2356 * http://developer.yahoo.net/yui/license.txt
2357 * <script type="text/javascript">
2364 request : function(method, uri, cb, data, options) {
2366 var hs = options.headers;
2369 if(hs.hasOwnProperty(h)){
2370 this.initHeader(h, hs[h], false);
2374 if(options.xmlData){
2375 this.initHeader('Content-Type', 'text/xml', false);
2377 data = options.xmlData;
2381 return this.asyncRequest(method, uri, cb, data);
2384 serializeForm : function(form) {
2385 if(typeof form == 'string') {
2386 form = (document.getElementById(form) || document.forms[form]);
2389 var el, name, val, disabled, data = '', hasSubmit = false;
2390 for (var i = 0; i < form.elements.length; i++) {
2391 el = form.elements[i];
2392 disabled = form.elements[i].disabled;
2393 name = form.elements[i].name;
2394 val = form.elements[i].value;
2396 if (!disabled && name){
2400 case 'select-multiple':
2401 for (var j = 0; j < el.options.length; j++) {
2402 if (el.options[j].selected) {
2404 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2407 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2415 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2428 if(hasSubmit == false) {
2429 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2434 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2439 data = data.substr(0, data.length - 1);
2447 useDefaultHeader:true,
2449 defaultPostHeader:'application/x-www-form-urlencoded',
2451 useDefaultXhrHeader:true,
2453 defaultXhrHeader:'XMLHttpRequest',
2455 hasDefaultHeaders:true,
2467 setProgId:function(id)
2469 this.activeX.unshift(id);
2472 setDefaultPostHeader:function(b)
2474 this.useDefaultHeader = b;
2477 setDefaultXhrHeader:function(b)
2479 this.useDefaultXhrHeader = b;
2482 setPollingInterval:function(i)
2484 if (typeof i == 'number' && isFinite(i)) {
2485 this.pollInterval = i;
2489 createXhrObject:function(transactionId)
2495 http = new XMLHttpRequest();
2497 obj = { conn:http, tId:transactionId };
2501 for (var i = 0; i < this.activeX.length; ++i) {
2505 http = new ActiveXObject(this.activeX[i]);
2507 obj = { conn:http, tId:transactionId };
2520 getConnectionObject:function()
2523 var tId = this.transactionId;
2527 o = this.createXhrObject(tId);
2529 this.transactionId++;
2540 asyncRequest:function(method, uri, callback, postData)
2542 var o = this.getConnectionObject();
2548 o.conn.open(method, uri, true);
2550 if (this.useDefaultXhrHeader) {
2551 if (!this.defaultHeaders['X-Requested-With']) {
2552 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2556 if(postData && this.useDefaultHeader){
2557 this.initHeader('Content-Type', this.defaultPostHeader);
2560 if (this.hasDefaultHeaders || this.hasHeaders) {
2564 this.handleReadyState(o, callback);
2565 o.conn.send(postData || null);
2571 handleReadyState:function(o, callback)
2575 if (callback && callback.timeout) {
2576 this.timeout[o.tId] = window.setTimeout(function() {
2577 oConn.abort(o, callback, true);
2578 }, callback.timeout);
2581 this.poll[o.tId] = window.setInterval(
2583 if (o.conn && o.conn.readyState == 4) {
2584 window.clearInterval(oConn.poll[o.tId]);
2585 delete oConn.poll[o.tId];
2587 if(callback && callback.timeout) {
2588 window.clearTimeout(oConn.timeout[o.tId]);
2589 delete oConn.timeout[o.tId];
2592 oConn.handleTransactionResponse(o, callback);
2595 , this.pollInterval);
2598 handleTransactionResponse:function(o, callback, isAbort)
2602 this.releaseObject(o);
2606 var httpStatus, responseObject;
2610 if (o.conn.status !== undefined && o.conn.status != 0) {
2611 httpStatus = o.conn.status;
2623 if (httpStatus >= 200 && httpStatus < 300) {
2624 responseObject = this.createResponseObject(o, callback.argument);
2625 if (callback.success) {
2626 if (!callback.scope) {
2627 callback.success(responseObject);
2632 callback.success.apply(callback.scope, [responseObject]);
2637 switch (httpStatus) {
2645 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2646 if (callback.failure) {
2647 if (!callback.scope) {
2648 callback.failure(responseObject);
2651 callback.failure.apply(callback.scope, [responseObject]);
2656 responseObject = this.createResponseObject(o, callback.argument);
2657 if (callback.failure) {
2658 if (!callback.scope) {
2659 callback.failure(responseObject);
2662 callback.failure.apply(callback.scope, [responseObject]);
2668 this.releaseObject(o);
2669 responseObject = null;
2672 createResponseObject:function(o, callbackArg)
2679 var headerStr = o.conn.getAllResponseHeaders();
2680 var header = headerStr.split('\n');
2681 for (var i = 0; i < header.length; i++) {
2682 var delimitPos = header[i].indexOf(':');
2683 if (delimitPos != -1) {
2684 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2692 obj.status = o.conn.status;
2693 obj.statusText = o.conn.statusText;
2694 obj.getResponseHeader = headerObj;
2695 obj.getAllResponseHeaders = headerStr;
2696 obj.responseText = o.conn.responseText;
2697 obj.responseXML = o.conn.responseXML;
2699 if (typeof callbackArg !== undefined) {
2700 obj.argument = callbackArg;
2706 createExceptionObject:function(tId, callbackArg, isAbort)
2709 var COMM_ERROR = 'communication failure';
2710 var ABORT_CODE = -1;
2711 var ABORT_ERROR = 'transaction aborted';
2717 obj.status = ABORT_CODE;
2718 obj.statusText = ABORT_ERROR;
2721 obj.status = COMM_CODE;
2722 obj.statusText = COMM_ERROR;
2726 obj.argument = callbackArg;
2732 initHeader:function(label, value, isDefault)
2734 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2736 if (headerObj[label] === undefined) {
2737 headerObj[label] = value;
2742 headerObj[label] = value + "," + headerObj[label];
2746 this.hasDefaultHeaders = true;
2749 this.hasHeaders = true;
2754 setHeader:function(o)
2756 if (this.hasDefaultHeaders) {
2757 for (var prop in this.defaultHeaders) {
2758 if (this.defaultHeaders.hasOwnProperty(prop)) {
2759 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2764 if (this.hasHeaders) {
2765 for (var prop in this.headers) {
2766 if (this.headers.hasOwnProperty(prop)) {
2767 o.conn.setRequestHeader(prop, this.headers[prop]);
2771 this.hasHeaders = false;
2775 resetDefaultHeaders:function() {
2776 delete this.defaultHeaders;
2777 this.defaultHeaders = {};
2778 this.hasDefaultHeaders = false;
2781 abort:function(o, callback, isTimeout)
2783 if(this.isCallInProgress(o)) {
2785 window.clearInterval(this.poll[o.tId]);
2786 delete this.poll[o.tId];
2788 delete this.timeout[o.tId];
2791 this.handleTransactionResponse(o, callback, true);
2801 isCallInProgress:function(o)
2804 return o.conn.readyState != 4 && o.conn.readyState != 0;
2813 releaseObject:function(o)
2822 'MSXML2.XMLHTTP.3.0',
2830 * Portions of this file are based on pieces of Yahoo User Interface Library
2831 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2832 * YUI licensed under the BSD License:
2833 * http://developer.yahoo.net/yui/license.txt
2834 * <script type="text/javascript">
2838 Roo.lib.Region = function(t, r, b, l) {
2848 Roo.lib.Region.prototype = {
2849 contains : function(region) {
2850 return ( region.left >= this.left &&
2851 region.right <= this.right &&
2852 region.top >= this.top &&
2853 region.bottom <= this.bottom );
2857 getArea : function() {
2858 return ( (this.bottom - this.top) * (this.right - this.left) );
2861 intersect : function(region) {
2862 var t = Math.max(this.top, region.top);
2863 var r = Math.min(this.right, region.right);
2864 var b = Math.min(this.bottom, region.bottom);
2865 var l = Math.max(this.left, region.left);
2867 if (b >= t && r >= l) {
2868 return new Roo.lib.Region(t, r, b, l);
2873 union : function(region) {
2874 var t = Math.min(this.top, region.top);
2875 var r = Math.max(this.right, region.right);
2876 var b = Math.max(this.bottom, region.bottom);
2877 var l = Math.min(this.left, region.left);
2879 return new Roo.lib.Region(t, r, b, l);
2882 adjust : function(t, l, b, r) {
2891 Roo.lib.Region.getRegion = function(el) {
2892 var p = Roo.lib.Dom.getXY(el);
2895 var r = p[0] + el.offsetWidth;
2896 var b = p[1] + el.offsetHeight;
2899 return new Roo.lib.Region(t, r, b, l);
2902 * Portions of this file are based on pieces of Yahoo User Interface Library
2903 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2904 * YUI licensed under the BSD License:
2905 * http://developer.yahoo.net/yui/license.txt
2906 * <script type="text/javascript">
2909 //@@dep Roo.lib.Region
2912 Roo.lib.Point = function(x, y) {
2913 if (x instanceof Array) {
2917 this.x = this.right = this.left = this[0] = x;
2918 this.y = this.top = this.bottom = this[1] = y;
2921 Roo.lib.Point.prototype = new Roo.lib.Region();
2923 * Portions of this file are based on pieces of Yahoo User Interface Library
2924 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2925 * YUI licensed under the BSD License:
2926 * http://developer.yahoo.net/yui/license.txt
2927 * <script type="text/javascript">
2934 scroll : function(el, args, duration, easing, cb, scope) {
2935 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2938 motion : function(el, args, duration, easing, cb, scope) {
2939 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2942 color : function(el, args, duration, easing, cb, scope) {
2943 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2946 run : function(el, args, duration, easing, cb, scope, type) {
2947 type = type || Roo.lib.AnimBase;
2948 if (typeof easing == "string") {
2949 easing = Roo.lib.Easing[easing];
2951 var anim = new type(el, args, duration, easing);
2952 anim.animateX(function() {
2953 Roo.callback(cb, scope);
2959 * Portions of this file are based on pieces of Yahoo User Interface Library
2960 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2961 * YUI licensed under the BSD License:
2962 * http://developer.yahoo.net/yui/license.txt
2963 * <script type="text/javascript">
2971 if (!libFlyweight) {
2972 libFlyweight = new Roo.Element.Flyweight();
2974 libFlyweight.dom = el;
2975 return libFlyweight;
2978 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2982 Roo.lib.AnimBase = function(el, attributes, duration, method) {
2984 this.init(el, attributes, duration, method);
2988 Roo.lib.AnimBase.fly = fly;
2992 Roo.lib.AnimBase.prototype = {
2994 toString: function() {
2995 var el = this.getEl();
2996 var id = el.id || el.tagName;
2997 return ("Anim " + id);
3001 noNegatives: /width|height|opacity|padding/i,
3002 offsetAttribute: /^((width|height)|(top|left))$/,
3003 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3004 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3008 doMethod: function(attr, start, end) {
3009 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3013 setAttribute: function(attr, val, unit) {
3014 if (this.patterns.noNegatives.test(attr)) {
3015 val = (val > 0) ? val : 0;
3018 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3022 getAttribute: function(attr) {
3023 var el = this.getEl();
3024 var val = fly(el).getStyle(attr);
3026 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3027 return parseFloat(val);
3030 var a = this.patterns.offsetAttribute.exec(attr) || [];
3031 var pos = !!( a[3] );
3032 var box = !!( a[2] );
3035 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3036 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3045 getDefaultUnit: function(attr) {
3046 if (this.patterns.defaultUnit.test(attr)) {
3053 animateX : function(callback, scope) {
3054 var f = function() {
3055 this.onComplete.removeListener(f);
3056 if (typeof callback == "function") {
3057 callback.call(scope || this, this);
3060 this.onComplete.addListener(f, this);
3065 setRuntimeAttribute: function(attr) {
3068 var attributes = this.attributes;
3070 this.runtimeAttributes[attr] = {};
3072 var isset = function(prop) {
3073 return (typeof prop !== 'undefined');
3076 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3080 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3083 if (isset(attributes[attr]['to'])) {
3084 end = attributes[attr]['to'];
3085 } else if (isset(attributes[attr]['by'])) {
3086 if (start.constructor == Array) {
3088 for (var i = 0, len = start.length; i < len; ++i) {
3089 end[i] = start[i] + attributes[attr]['by'][i];
3092 end = start + attributes[attr]['by'];
3096 this.runtimeAttributes[attr].start = start;
3097 this.runtimeAttributes[attr].end = end;
3100 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3104 init: function(el, attributes, duration, method) {
3106 var isAnimated = false;
3109 var startTime = null;
3112 var actualFrames = 0;
3115 el = Roo.getDom(el);
3118 this.attributes = attributes || {};
3121 this.duration = duration || 1;
3124 this.method = method || Roo.lib.Easing.easeNone;
3127 this.useSeconds = true;
3130 this.currentFrame = 0;
3133 this.totalFrames = Roo.lib.AnimMgr.fps;
3136 this.getEl = function() {
3141 this.isAnimated = function() {
3146 this.getStartTime = function() {
3150 this.runtimeAttributes = {};
3153 this.animate = function() {
3154 if (this.isAnimated()) {
3158 this.currentFrame = 0;
3160 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3162 Roo.lib.AnimMgr.registerElement(this);
3166 this.stop = function(finish) {
3168 this.currentFrame = this.totalFrames;
3169 this._onTween.fire();
3171 Roo.lib.AnimMgr.stop(this);
3174 var onStart = function() {
3175 this.onStart.fire();
3177 this.runtimeAttributes = {};
3178 for (var attr in this.attributes) {
3179 this.setRuntimeAttribute(attr);
3184 startTime = new Date();
3188 var onTween = function() {
3190 duration: new Date() - this.getStartTime(),
3191 currentFrame: this.currentFrame
3194 data.toString = function() {
3196 'duration: ' + data.duration +
3197 ', currentFrame: ' + data.currentFrame
3201 this.onTween.fire(data);
3203 var runtimeAttributes = this.runtimeAttributes;
3205 for (var attr in runtimeAttributes) {
3206 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3212 var onComplete = function() {
3213 var actual_duration = (new Date() - startTime) / 1000 ;
3216 duration: actual_duration,
3217 frames: actualFrames,
3218 fps: actualFrames / actual_duration
3221 data.toString = function() {
3223 'duration: ' + data.duration +
3224 ', frames: ' + data.frames +
3225 ', fps: ' + data.fps
3231 this.onComplete.fire(data);
3235 this._onStart = new Roo.util.Event(this);
3236 this.onStart = new Roo.util.Event(this);
3237 this.onTween = new Roo.util.Event(this);
3238 this._onTween = new Roo.util.Event(this);
3239 this.onComplete = new Roo.util.Event(this);
3240 this._onComplete = new Roo.util.Event(this);
3241 this._onStart.addListener(onStart);
3242 this._onTween.addListener(onTween);
3243 this._onComplete.addListener(onComplete);
3248 * Portions of this file are based on pieces of Yahoo User Interface Library
3249 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3250 * YUI licensed under the BSD License:
3251 * http://developer.yahoo.net/yui/license.txt
3252 * <script type="text/javascript">
3256 Roo.lib.AnimMgr = new function() {
3273 this.registerElement = function(tween) {
3274 queue[queue.length] = tween;
3276 tween._onStart.fire();
3281 this.unRegister = function(tween, index) {
3282 tween._onComplete.fire();
3283 index = index || getIndex(tween);
3285 queue.splice(index, 1);
3289 if (tweenCount <= 0) {
3295 this.start = function() {
3296 if (thread === null) {
3297 thread = setInterval(this.run, this.delay);
3302 this.stop = function(tween) {
3304 clearInterval(thread);
3306 for (var i = 0, len = queue.length; i < len; ++i) {
3307 if (queue[0].isAnimated()) {
3308 this.unRegister(queue[0], 0);
3317 this.unRegister(tween);
3322 this.run = function() {
3323 for (var i = 0, len = queue.length; i < len; ++i) {
3324 var tween = queue[i];
3325 if (!tween || !tween.isAnimated()) {
3329 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3331 tween.currentFrame += 1;
3333 if (tween.useSeconds) {
3334 correctFrame(tween);
3336 tween._onTween.fire();
3339 Roo.lib.AnimMgr.stop(tween, i);
3344 var getIndex = function(anim) {
3345 for (var i = 0, len = queue.length; i < len; ++i) {
3346 if (queue[i] == anim) {
3354 var correctFrame = function(tween) {
3355 var frames = tween.totalFrames;
3356 var frame = tween.currentFrame;
3357 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3358 var elapsed = (new Date() - tween.getStartTime());
3361 if (elapsed < tween.duration * 1000) {
3362 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3364 tweak = frames - (frame + 1);
3366 if (tweak > 0 && isFinite(tweak)) {
3367 if (tween.currentFrame + tweak >= frames) {
3368 tweak = frames - (frame + 1);
3371 tween.currentFrame += tweak;
3375 * Portions of this file are based on pieces of Yahoo User Interface Library
3376 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3377 * YUI licensed under the BSD License:
3378 * http://developer.yahoo.net/yui/license.txt
3379 * <script type="text/javascript">
3382 Roo.lib.Bezier = new function() {
3384 this.getPosition = function(points, t) {
3385 var n = points.length;
3388 for (var i = 0; i < n; ++i) {
3389 tmp[i] = [points[i][0], points[i][1]];
3392 for (var j = 1; j < n; ++j) {
3393 for (i = 0; i < n - j; ++i) {
3394 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3395 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3399 return [ tmp[0][0], tmp[0][1] ];
3403 * Portions of this file are based on pieces of Yahoo User Interface Library
3404 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3405 * YUI licensed under the BSD License:
3406 * http://developer.yahoo.net/yui/license.txt
3407 * <script type="text/javascript">
3412 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3413 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3416 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3418 var fly = Roo.lib.AnimBase.fly;
3420 var superclass = Y.ColorAnim.superclass;
3421 var proto = Y.ColorAnim.prototype;
3423 proto.toString = function() {
3424 var el = this.getEl();
3425 var id = el.id || el.tagName;
3426 return ("ColorAnim " + id);
3429 proto.patterns.color = /color$/i;
3430 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3431 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3432 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3433 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3436 proto.parseColor = function(s) {
3437 if (s.length == 3) {
3441 var c = this.patterns.hex.exec(s);
3442 if (c && c.length == 4) {
3443 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3446 c = this.patterns.rgb.exec(s);
3447 if (c && c.length == 4) {
3448 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3451 c = this.patterns.hex3.exec(s);
3452 if (c && c.length == 4) {
3453 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3458 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3459 proto.getAttribute = function(attr) {
3460 var el = this.getEl();
3461 if (this.patterns.color.test(attr)) {
3462 var val = fly(el).getStyle(attr);
3464 if (this.patterns.transparent.test(val)) {
3465 var parent = el.parentNode;
3466 val = fly(parent).getStyle(attr);
3468 while (parent && this.patterns.transparent.test(val)) {
3469 parent = parent.parentNode;
3470 val = fly(parent).getStyle(attr);
3471 if (parent.tagName.toUpperCase() == 'HTML') {
3477 val = superclass.getAttribute.call(this, attr);
3482 proto.getAttribute = function(attr) {
3483 var el = this.getEl();
3484 if (this.patterns.color.test(attr)) {
3485 var val = fly(el).getStyle(attr);
3487 if (this.patterns.transparent.test(val)) {
3488 var parent = el.parentNode;
3489 val = fly(parent).getStyle(attr);
3491 while (parent && this.patterns.transparent.test(val)) {
3492 parent = parent.parentNode;
3493 val = fly(parent).getStyle(attr);
3494 if (parent.tagName.toUpperCase() == 'HTML') {
3500 val = superclass.getAttribute.call(this, attr);
3506 proto.doMethod = function(attr, start, end) {
3509 if (this.patterns.color.test(attr)) {
3511 for (var i = 0, len = start.length; i < len; ++i) {
3512 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3515 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3518 val = superclass.doMethod.call(this, attr, start, end);
3524 proto.setRuntimeAttribute = function(attr) {
3525 superclass.setRuntimeAttribute.call(this, attr);
3527 if (this.patterns.color.test(attr)) {
3528 var attributes = this.attributes;
3529 var start = this.parseColor(this.runtimeAttributes[attr].start);
3530 var end = this.parseColor(this.runtimeAttributes[attr].end);
3532 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3533 end = this.parseColor(attributes[attr].by);
3535 for (var i = 0, len = start.length; i < len; ++i) {
3536 end[i] = start[i] + end[i];
3540 this.runtimeAttributes[attr].start = start;
3541 this.runtimeAttributes[attr].end = end;
3547 * Portions of this file are based on pieces of Yahoo User Interface Library
3548 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3549 * YUI licensed under the BSD License:
3550 * http://developer.yahoo.net/yui/license.txt
3551 * <script type="text/javascript">
3557 easeNone: function (t, b, c, d) {
3558 return c * t / d + b;
3562 easeIn: function (t, b, c, d) {
3563 return c * (t /= d) * t + b;
3567 easeOut: function (t, b, c, d) {
3568 return -c * (t /= d) * (t - 2) + b;
3572 easeBoth: function (t, b, c, d) {
3573 if ((t /= d / 2) < 1) {
3574 return c / 2 * t * t + b;
3577 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3581 easeInStrong: function (t, b, c, d) {
3582 return c * (t /= d) * t * t * t + b;
3586 easeOutStrong: function (t, b, c, d) {
3587 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3591 easeBothStrong: function (t, b, c, d) {
3592 if ((t /= d / 2) < 1) {
3593 return c / 2 * t * t * t * t + b;
3596 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3601 elasticIn: function (t, b, c, d, a, p) {
3605 if ((t /= d) == 1) {
3612 if (!a || a < Math.abs(c)) {
3617 var s = p / (2 * Math.PI) * Math.asin(c / a);
3620 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3624 elasticOut: function (t, b, c, d, a, p) {
3628 if ((t /= d) == 1) {
3635 if (!a || a < Math.abs(c)) {
3640 var s = p / (2 * Math.PI) * Math.asin(c / a);
3643 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3647 elasticBoth: function (t, b, c, d, a, p) {
3652 if ((t /= d / 2) == 2) {
3660 if (!a || a < Math.abs(c)) {
3665 var s = p / (2 * Math.PI) * Math.asin(c / a);
3669 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3670 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3672 return a * Math.pow(2, -10 * (t -= 1)) *
3673 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3678 backIn: function (t, b, c, d, s) {
3679 if (typeof s == 'undefined') {
3682 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3686 backOut: function (t, b, c, d, s) {
3687 if (typeof s == 'undefined') {
3690 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3694 backBoth: function (t, b, c, d, s) {
3695 if (typeof s == 'undefined') {
3699 if ((t /= d / 2 ) < 1) {
3700 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3702 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3706 bounceIn: function (t, b, c, d) {
3707 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3711 bounceOut: function (t, b, c, d) {
3712 if ((t /= d) < (1 / 2.75)) {
3713 return c * (7.5625 * t * t) + b;
3714 } else if (t < (2 / 2.75)) {
3715 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3716 } else if (t < (2.5 / 2.75)) {
3717 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3719 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3723 bounceBoth: function (t, b, c, d) {
3725 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3727 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3730 * Portions of this file are based on pieces of Yahoo User Interface Library
3731 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3732 * YUI licensed under the BSD License:
3733 * http://developer.yahoo.net/yui/license.txt
3734 * <script type="text/javascript">
3738 Roo.lib.Motion = function(el, attributes, duration, method) {
3740 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3744 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3748 var superclass = Y.Motion.superclass;
3749 var proto = Y.Motion.prototype;
3751 proto.toString = function() {
3752 var el = this.getEl();
3753 var id = el.id || el.tagName;
3754 return ("Motion " + id);
3757 proto.patterns.points = /^points$/i;
3759 proto.setAttribute = function(attr, val, unit) {
3760 if (this.patterns.points.test(attr)) {
3761 unit = unit || 'px';
3762 superclass.setAttribute.call(this, 'left', val[0], unit);
3763 superclass.setAttribute.call(this, 'top', val[1], unit);
3765 superclass.setAttribute.call(this, attr, val, unit);
3769 proto.getAttribute = function(attr) {
3770 if (this.patterns.points.test(attr)) {
3772 superclass.getAttribute.call(this, 'left'),
3773 superclass.getAttribute.call(this, 'top')
3776 val = superclass.getAttribute.call(this, attr);
3782 proto.doMethod = function(attr, start, end) {
3785 if (this.patterns.points.test(attr)) {
3786 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3787 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3789 val = superclass.doMethod.call(this, attr, start, end);
3794 proto.setRuntimeAttribute = function(attr) {
3795 if (this.patterns.points.test(attr)) {
3796 var el = this.getEl();
3797 var attributes = this.attributes;
3799 var control = attributes['points']['control'] || [];
3803 if (control.length > 0 && !(control[0] instanceof Array)) {
3804 control = [control];
3807 for (i = 0,len = control.length; i < len; ++i) {
3808 tmp[i] = control[i];
3813 Roo.fly(el).position();
3815 if (isset(attributes['points']['from'])) {
3816 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3819 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3822 start = this.getAttribute('points');
3825 if (isset(attributes['points']['to'])) {
3826 end = translateValues.call(this, attributes['points']['to'], start);
3828 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3829 for (i = 0,len = control.length; i < len; ++i) {
3830 control[i] = translateValues.call(this, control[i], start);
3834 } else if (isset(attributes['points']['by'])) {
3835 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3837 for (i = 0,len = control.length; i < len; ++i) {
3838 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3842 this.runtimeAttributes[attr] = [start];
3844 if (control.length > 0) {
3845 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3848 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3851 superclass.setRuntimeAttribute.call(this, attr);
3855 var translateValues = function(val, start) {
3856 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3857 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3862 var isset = function(prop) {
3863 return (typeof prop !== 'undefined');
3867 * Portions of this file are based on pieces of Yahoo User Interface Library
3868 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3869 * YUI licensed under the BSD License:
3870 * http://developer.yahoo.net/yui/license.txt
3871 * <script type="text/javascript">
3875 Roo.lib.Scroll = function(el, attributes, duration, method) {
3877 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3881 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3885 var superclass = Y.Scroll.superclass;
3886 var proto = Y.Scroll.prototype;
3888 proto.toString = function() {
3889 var el = this.getEl();
3890 var id = el.id || el.tagName;
3891 return ("Scroll " + id);
3894 proto.doMethod = function(attr, start, end) {
3897 if (attr == 'scroll') {
3899 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3900 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3904 val = superclass.doMethod.call(this, attr, start, end);
3909 proto.getAttribute = function(attr) {
3911 var el = this.getEl();
3913 if (attr == 'scroll') {
3914 val = [ el.scrollLeft, el.scrollTop ];
3916 val = superclass.getAttribute.call(this, attr);
3922 proto.setAttribute = function(attr, val, unit) {
3923 var el = this.getEl();
3925 if (attr == 'scroll') {
3926 el.scrollLeft = val[0];
3927 el.scrollTop = val[1];
3929 superclass.setAttribute.call(this, attr, val, unit);
3935 * Ext JS Library 1.1.1
3936 * Copyright(c) 2006-2007, Ext JS, LLC.
3938 * Originally Released Under LGPL - original licence link has changed is not relivant.
3941 * <script type="text/javascript">
3946 * @class Roo.DomHelper
3947 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3948 * 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>.
3951 Roo.DomHelper = function(){
3952 var tempTableEl = null;
3953 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3954 var tableRe = /^table|tbody|tr|td$/i;
3956 // build as innerHTML where available
3958 var createHtml = function(o){
3959 if(typeof o == 'string'){
3968 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3969 if(attr == "style"){
3971 if(typeof s == "function"){
3974 if(typeof s == "string"){
3975 b += ' style="' + s + '"';
3976 }else if(typeof s == "object"){
3979 if(typeof s[key] != "function"){
3980 b += key + ":" + s[key] + ";";
3987 b += ' class="' + o["cls"] + '"';
3988 }else if(attr == "htmlFor"){
3989 b += ' for="' + o["htmlFor"] + '"';
3991 b += " " + attr + '="' + o[attr] + '"';
3995 if(emptyTags.test(o.tag)){
3999 var cn = o.children || o.cn;
4001 //http://bugs.kde.org/show_bug.cgi?id=71506
4002 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4003 for(var i = 0, len = cn.length; i < len; i++) {
4004 b += createHtml(cn[i], b);
4007 b += createHtml(cn, b);
4013 b += "</" + o.tag + ">";
4020 var createDom = function(o, parentNode){
4022 // defininition craeted..
4024 if (o.ns && o.ns != 'html') {
4026 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4027 xmlns[o.ns] = o.xmlns;
4030 if (typeof(xmlns[o.ns]) == 'undefined') {
4031 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4037 if (typeof(o) == 'string') {
4038 return parentNode.appendChild(document.createTextNode(o));
4040 o.tag = o.tag || div;
4041 if (o.ns && Roo.isIE) {
4043 o.tag = o.ns + ':' + o.tag;
4046 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4047 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4050 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4051 attr == "style" || typeof o[attr] == "function") continue;
4053 if(attr=="cls" && Roo.isIE){
4054 el.className = o["cls"];
4056 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4057 else el[attr] = o[attr];
4060 Roo.DomHelper.applyStyles(el, o.style);
4061 var cn = o.children || o.cn;
4063 //http://bugs.kde.org/show_bug.cgi?id=71506
4064 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4065 for(var i = 0, len = cn.length; i < len; i++) {
4066 createDom(cn[i], el);
4073 el.innerHTML = o.html;
4076 parentNode.appendChild(el);
4081 var ieTable = function(depth, s, h, e){
4082 tempTableEl.innerHTML = [s, h, e].join('');
4083 var i = -1, el = tempTableEl;
4090 // kill repeat to save bytes
4094 tbe = '</tbody>'+te,
4100 * Nasty code for IE's broken table implementation
4102 var insertIntoTable = function(tag, where, el, html){
4104 tempTableEl = document.createElement('div');
4109 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4112 if(where == 'beforebegin'){
4116 before = el.nextSibling;
4119 node = ieTable(4, trs, html, tre);
4121 else if(tag == 'tr'){
4122 if(where == 'beforebegin'){
4125 node = ieTable(3, tbs, html, tbe);
4126 } else if(where == 'afterend'){
4127 before = el.nextSibling;
4129 node = ieTable(3, tbs, html, tbe);
4130 } else{ // INTO a TR
4131 if(where == 'afterbegin'){
4132 before = el.firstChild;
4134 node = ieTable(4, trs, html, tre);
4136 } else if(tag == 'tbody'){
4137 if(where == 'beforebegin'){
4140 node = ieTable(2, ts, html, te);
4141 } else if(where == 'afterend'){
4142 before = el.nextSibling;
4144 node = ieTable(2, ts, html, te);
4146 if(where == 'afterbegin'){
4147 before = el.firstChild;
4149 node = ieTable(3, tbs, html, tbe);
4152 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4155 if(where == 'afterbegin'){
4156 before = el.firstChild;
4158 node = ieTable(2, ts, html, te);
4160 el.insertBefore(node, before);
4165 /** True to force the use of DOM instead of html fragments @type Boolean */
4169 * Returns the markup for the passed Element(s) config
4170 * @param {Object} o The Dom object spec (and children)
4173 markup : function(o){
4174 return createHtml(o);
4178 * Applies a style specification to an element
4179 * @param {String/HTMLElement} el The element to apply styles to
4180 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4181 * a function which returns such a specification.
4183 applyStyles : function(el, styles){
4186 if(typeof styles == "string"){
4187 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4189 while ((matches = re.exec(styles)) != null){
4190 el.setStyle(matches[1], matches[2]);
4192 }else if (typeof styles == "object"){
4193 for (var style in styles){
4194 el.setStyle(style, styles[style]);
4196 }else if (typeof styles == "function"){
4197 Roo.DomHelper.applyStyles(el, styles.call());
4203 * Inserts an HTML fragment into the Dom
4204 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4205 * @param {HTMLElement} el The context element
4206 * @param {String} html The HTML fragmenet
4207 * @return {HTMLElement} The new node
4209 insertHtml : function(where, el, html){
4210 where = where.toLowerCase();
4211 if(el.insertAdjacentHTML){
4212 if(tableRe.test(el.tagName)){
4214 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4220 el.insertAdjacentHTML('BeforeBegin', html);
4221 return el.previousSibling;
4223 el.insertAdjacentHTML('AfterBegin', html);
4224 return el.firstChild;
4226 el.insertAdjacentHTML('BeforeEnd', html);
4227 return el.lastChild;
4229 el.insertAdjacentHTML('AfterEnd', html);
4230 return el.nextSibling;
4232 throw 'Illegal insertion point -> "' + where + '"';
4234 var range = el.ownerDocument.createRange();
4238 range.setStartBefore(el);
4239 frag = range.createContextualFragment(html);
4240 el.parentNode.insertBefore(frag, el);
4241 return el.previousSibling;
4244 range.setStartBefore(el.firstChild);
4245 frag = range.createContextualFragment(html);
4246 el.insertBefore(frag, el.firstChild);
4247 return el.firstChild;
4249 el.innerHTML = html;
4250 return el.firstChild;
4254 range.setStartAfter(el.lastChild);
4255 frag = range.createContextualFragment(html);
4256 el.appendChild(frag);
4257 return el.lastChild;
4259 el.innerHTML = html;
4260 return el.lastChild;
4263 range.setStartAfter(el);
4264 frag = range.createContextualFragment(html);
4265 el.parentNode.insertBefore(frag, el.nextSibling);
4266 return el.nextSibling;
4268 throw 'Illegal insertion point -> "' + where + '"';
4272 * Creates new Dom element(s) and inserts them before el
4273 * @param {String/HTMLElement/Element} el The context element
4274 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4275 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4276 * @return {HTMLElement/Roo.Element} The new node
4278 insertBefore : function(el, o, returnElement){
4279 return this.doInsert(el, o, returnElement, "beforeBegin");
4283 * Creates new Dom element(s) and inserts them after el
4284 * @param {String/HTMLElement/Element} el The context element
4285 * @param {Object} o The Dom object spec (and children)
4286 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4287 * @return {HTMLElement/Roo.Element} The new node
4289 insertAfter : function(el, o, returnElement){
4290 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4294 * Creates new Dom element(s) and inserts them as the first child of el
4295 * @param {String/HTMLElement/Element} el The context element
4296 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4297 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4298 * @return {HTMLElement/Roo.Element} The new node
4300 insertFirst : function(el, o, returnElement){
4301 return this.doInsert(el, o, returnElement, "afterBegin");
4305 doInsert : function(el, o, returnElement, pos, sibling){
4306 el = Roo.getDom(el);
4308 if(this.useDom || o.ns){
4309 newNode = createDom(o, null);
4310 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4312 var html = createHtml(o);
4313 newNode = this.insertHtml(pos, el, html);
4315 return returnElement ? Roo.get(newNode, true) : newNode;
4319 * Creates new Dom element(s) and appends them to el
4320 * @param {String/HTMLElement/Element} el The context element
4321 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4322 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4323 * @return {HTMLElement/Roo.Element} The new node
4325 append : function(el, o, returnElement){
4326 el = Roo.getDom(el);
4328 if(this.useDom || o.ns){
4329 newNode = createDom(o, null);
4330 el.appendChild(newNode);
4332 var html = createHtml(o);
4333 newNode = this.insertHtml("beforeEnd", el, html);
4335 return returnElement ? Roo.get(newNode, true) : newNode;
4339 * Creates new Dom element(s) and overwrites the contents of el with them
4340 * @param {String/HTMLElement/Element} el The context element
4341 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4342 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4343 * @return {HTMLElement/Roo.Element} The new node
4345 overwrite : function(el, o, returnElement){
4346 el = Roo.getDom(el);
4349 while (el.childNodes.length) {
4350 el.removeChild(el.firstChild);
4354 el.innerHTML = createHtml(o);
4357 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4361 * Creates a new Roo.DomHelper.Template from the Dom object spec
4362 * @param {Object} o The Dom object spec (and children)
4363 * @return {Roo.DomHelper.Template} The new template
4365 createTemplate : function(o){
4366 var html = createHtml(o);
4367 return new Roo.Template(html);
4373 * Ext JS Library 1.1.1
4374 * Copyright(c) 2006-2007, Ext JS, LLC.
4376 * Originally Released Under LGPL - original licence link has changed is not relivant.
4379 * <script type="text/javascript">
4383 * @class Roo.Template
4384 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4385 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4388 var t = new Roo.Template(
4389 '<div name="{id}">',
4390 '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
4393 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4395 * 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>.
4397 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4399 Roo.Template = function(html){
4400 if(html instanceof Array){
4401 html = html.join("");
4402 }else if(arguments.length > 1){
4403 html = Array.prototype.join.call(arguments, "");
4409 Roo.Template.prototype = {
4411 * Returns an HTML fragment of this template with the specified values applied.
4412 * @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'})
4413 * @return {String} The HTML fragment
4415 applyTemplate : function(values){
4417 return this.compiled(values);
4419 var useF = this.disableFormats !== true;
4420 var fm = Roo.util.Format, tpl = this;
4421 var fn = function(m, name, format, args){
4423 if(format.substr(0, 5) == "this."){
4424 return tpl.call(format.substr(5), values[name], values);
4427 // quoted values are required for strings in compiled templates,
4428 // but for non compiled we need to strip them
4429 // quoted reversed for jsmin
4430 var re = /^\s*['"](.*)["']\s*$/;
4431 args = args.split(',');
4432 for(var i = 0, len = args.length; i < len; i++){
4433 args[i] = args[i].replace(re, "$1");
4435 args = [values[name]].concat(args);
4437 args = [values[name]];
4439 return fm[format].apply(fm, args);
4442 return values[name] !== undefined ? values[name] : "";
4445 return this.html.replace(this.re, fn);
4449 * Sets the HTML used as the template and optionally compiles it.
4450 * @param {String} html
4451 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4452 * @return {Roo.Template} this
4454 set : function(html, compile){
4456 this.compiled = null;
4464 * True to disable format functions (defaults to false)
4467 disableFormats : false,
4470 * The regular expression used to match template variables
4474 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4477 * Compiles the template into an internal function, eliminating the RegEx overhead.
4478 * @return {Roo.Template} this
4480 compile : function(){
4481 var fm = Roo.util.Format;
4482 var useF = this.disableFormats !== true;
4483 var sep = Roo.isGecko ? "+" : ",";
4484 var fn = function(m, name, format, args){
4486 args = args ? ',' + args : "";
4487 if(format.substr(0, 5) != "this."){
4488 format = "fm." + format + '(';
4490 format = 'this.call("'+ format.substr(5) + '", ';
4494 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4496 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4499 // branched to use + in gecko and [].join() in others
4501 body = "this.compiled = function(values){ return '" +
4502 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4505 body = ["this.compiled = function(values){ return ['"];
4506 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4507 body.push("'].join('');};");
4508 body = body.join('');
4518 // private function used to call members
4519 call : function(fnName, value, allValues){
4520 return this[fnName](value, allValues);
4524 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4525 * @param {String/HTMLElement/Roo.Element} el The context element
4526 * @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'})
4527 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4528 * @return {HTMLElement/Roo.Element} The new node or Element
4530 insertFirst: function(el, values, returnElement){
4531 return this.doInsert('afterBegin', el, values, returnElement);
4535 * Applies the supplied values to the template and inserts the new node(s) before el.
4536 * @param {String/HTMLElement/Roo.Element} el The context element
4537 * @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'})
4538 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4539 * @return {HTMLElement/Roo.Element} The new node or Element
4541 insertBefore: function(el, values, returnElement){
4542 return this.doInsert('beforeBegin', el, values, returnElement);
4546 * Applies the supplied values to the template and inserts the new node(s) after el.
4547 * @param {String/HTMLElement/Roo.Element} el The context element
4548 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4549 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4550 * @return {HTMLElement/Roo.Element} The new node or Element
4552 insertAfter : function(el, values, returnElement){
4553 return this.doInsert('afterEnd', el, values, returnElement);
4557 * Applies the supplied values to the template and appends the new node(s) to el.
4558 * @param {String/HTMLElement/Roo.Element} el The context element
4559 * @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'})
4560 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4561 * @return {HTMLElement/Roo.Element} The new node or Element
4563 append : function(el, values, returnElement){
4564 return this.doInsert('beforeEnd', el, values, returnElement);
4567 doInsert : function(where, el, values, returnEl){
4568 el = Roo.getDom(el);
4569 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4570 return returnEl ? Roo.get(newNode, true) : newNode;
4574 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4575 * @param {String/HTMLElement/Roo.Element} el The context element
4576 * @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'})
4577 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4578 * @return {HTMLElement/Roo.Element} The new node or Element
4580 overwrite : function(el, values, returnElement){
4581 el = Roo.getDom(el);
4582 el.innerHTML = this.applyTemplate(values);
4583 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4587 * Alias for {@link #applyTemplate}
4590 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4593 Roo.DomHelper.Template = Roo.Template;
4596 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4597 * @param {String/HTMLElement} el A DOM element or its id
4598 * @returns {Roo.Template} The created template
4601 Roo.Template.from = function(el){
4602 el = Roo.getDom(el);
4603 return new Roo.Template(el.value || el.innerHTML);
4606 * Ext JS Library 1.1.1
4607 * Copyright(c) 2006-2007, Ext JS, LLC.
4609 * Originally Released Under LGPL - original licence link has changed is not relivant.
4612 * <script type="text/javascript">
4617 * This is code is also distributed under MIT license for use
4618 * with jQuery and prototype JavaScript libraries.
4621 * @class Roo.DomQuery
4622 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).
4624 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>
4627 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.
4629 <h4>Element Selectors:</h4>
4631 <li> <b>*</b> any element</li>
4632 <li> <b>E</b> an element with the tag E</li>
4633 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4634 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4635 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4636 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4638 <h4>Attribute Selectors:</h4>
4639 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4641 <li> <b>E[foo]</b> has an attribute "foo"</li>
4642 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4643 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4644 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4645 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4646 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4647 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4649 <h4>Pseudo Classes:</h4>
4651 <li> <b>E:first-child</b> E is the first child of its parent</li>
4652 <li> <b>E:last-child</b> E is the last child of its parent</li>
4653 <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>
4654 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4655 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4656 <li> <b>E:only-child</b> E is the only child of its parent</li>
4657 <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>
4658 <li> <b>E:first</b> the first E in the resultset</li>
4659 <li> <b>E:last</b> the last E in the resultset</li>
4660 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4661 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4662 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4663 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4664 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4665 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4666 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4667 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4668 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4670 <h4>CSS Value Selectors:</h4>
4672 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4673 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4674 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4675 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4676 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4677 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4681 Roo.DomQuery = function(){
4682 var cache = {}, simpleCache = {}, valueCache = {};
4683 var nonSpace = /\S/;
4684 var trimRe = /^\s+|\s+$/g;
4685 var tplRe = /\{(\d+)\}/g;
4686 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4687 var tagTokenRe = /^(#)?([\w-\*]+)/;
4688 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4690 function child(p, index){
4692 var n = p.firstChild;
4694 if(n.nodeType == 1){
4705 while((n = n.nextSibling) && n.nodeType != 1);
4710 while((n = n.previousSibling) && n.nodeType != 1);
4714 function children(d){
4715 var n = d.firstChild, ni = -1;
4717 var nx = n.nextSibling;
4718 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4728 function byClassName(c, a, v){
4732 var r = [], ri = -1, cn;
4733 for(var i = 0, ci; ci = c[i]; i++){
4734 if((' '+ci.className+' ').indexOf(v) != -1){
4741 function attrValue(n, attr){
4742 if(!n.tagName && typeof n.length != "undefined"){
4751 if(attr == "class" || attr == "className"){
4754 return n.getAttribute(attr) || n[attr];
4758 function getNodes(ns, mode, tagName){
4759 var result = [], ri = -1, cs;
4763 tagName = tagName || "*";
4764 if(typeof ns.getElementsByTagName != "undefined"){
4768 for(var i = 0, ni; ni = ns[i]; i++){
4769 cs = ni.getElementsByTagName(tagName);
4770 for(var j = 0, ci; ci = cs[j]; j++){
4774 }else if(mode == "/" || mode == ">"){
4775 var utag = tagName.toUpperCase();
4776 for(var i = 0, ni, cn; ni = ns[i]; i++){
4777 cn = ni.children || ni.childNodes;
4778 for(var j = 0, cj; cj = cn[j]; j++){
4779 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4784 }else if(mode == "+"){
4785 var utag = tagName.toUpperCase();
4786 for(var i = 0, n; n = ns[i]; i++){
4787 while((n = n.nextSibling) && n.nodeType != 1);
4788 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4792 }else if(mode == "~"){
4793 for(var i = 0, n; n = ns[i]; i++){
4794 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4803 function concat(a, b){
4807 for(var i = 0, l = b.length; i < l; i++){
4813 function byTag(cs, tagName){
4814 if(cs.tagName || cs == document){
4820 var r = [], ri = -1;
4821 tagName = tagName.toLowerCase();
4822 for(var i = 0, ci; ci = cs[i]; i++){
4823 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4830 function byId(cs, attr, id){
4831 if(cs.tagName || cs == document){
4837 var r = [], ri = -1;
4838 for(var i = 0,ci; ci = cs[i]; i++){
4839 if(ci && ci.id == id){
4847 function byAttribute(cs, attr, value, op, custom){
4848 var r = [], ri = -1, st = custom=="{";
4849 var f = Roo.DomQuery.operators[op];
4850 for(var i = 0, ci; ci = cs[i]; i++){
4853 a = Roo.DomQuery.getStyle(ci, attr);
4855 else if(attr == "class" || attr == "className"){
4857 }else if(attr == "for"){
4859 }else if(attr == "href"){
4860 a = ci.getAttribute("href", 2);
4862 a = ci.getAttribute(attr);
4864 if((f && f(a, value)) || (!f && a)){
4871 function byPseudo(cs, name, value){
4872 return Roo.DomQuery.pseudos[name](cs, value);
4875 // This is for IE MSXML which does not support expandos.
4876 // IE runs the same speed using setAttribute, however FF slows way down
4877 // and Safari completely fails so they need to continue to use expandos.
4878 var isIE = window.ActiveXObject ? true : false;
4880 // this eval is stop the compressor from
4881 // renaming the variable to something shorter
4883 /** eval:var:batch */
4888 function nodupIEXml(cs){
4890 cs[0].setAttribute("_nodup", d);
4892 for(var i = 1, len = cs.length; i < len; i++){
4894 if(!c.getAttribute("_nodup") != d){
4895 c.setAttribute("_nodup", d);
4899 for(var i = 0, len = cs.length; i < len; i++){
4900 cs[i].removeAttribute("_nodup");
4909 var len = cs.length, c, i, r = cs, cj, ri = -1;
4910 if(!len || typeof cs.nodeType != "undefined" || len == 1){
4913 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4914 return nodupIEXml(cs);
4918 for(i = 1; c = cs[i]; i++){
4923 for(var j = 0; j < i; j++){
4926 for(j = i+1; cj = cs[j]; j++){
4938 function quickDiffIEXml(c1, c2){
4940 for(var i = 0, len = c1.length; i < len; i++){
4941 c1[i].setAttribute("_qdiff", d);
4944 for(var i = 0, len = c2.length; i < len; i++){
4945 if(c2[i].getAttribute("_qdiff") != d){
4946 r[r.length] = c2[i];
4949 for(var i = 0, len = c1.length; i < len; i++){
4950 c1[i].removeAttribute("_qdiff");
4955 function quickDiff(c1, c2){
4956 var len1 = c1.length;
4960 if(isIE && c1[0].selectSingleNode){
4961 return quickDiffIEXml(c1, c2);
4964 for(var i = 0; i < len1; i++){
4968 for(var i = 0, len = c2.length; i < len; i++){
4969 if(c2[i]._qdiff != d){
4970 r[r.length] = c2[i];
4976 function quickId(ns, mode, root, id){
4978 var d = root.ownerDocument || root;
4979 return d.getElementById(id);
4981 ns = getNodes(ns, mode, "*");
4982 return byId(ns, null, id);
4986 getStyle : function(el, name){
4987 return Roo.fly(el).getStyle(name);
4990 * Compiles a selector/xpath query into a reusable function. The returned function
4991 * takes one parameter "root" (optional), which is the context node from where the query should start.
4992 * @param {String} selector The selector/xpath query
4993 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
4994 * @return {Function}
4996 compile : function(path, type){
4997 type = type || "select";
4999 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5000 var q = path, mode, lq;
5001 var tk = Roo.DomQuery.matchers;
5002 var tklen = tk.length;
5005 // accept leading mode switch
5006 var lmode = q.match(modeRe);
5007 if(lmode && lmode[1]){
5008 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5009 q = q.replace(lmode[1], "");
5011 // strip leading slashes
5012 while(path.substr(0, 1)=="/"){
5013 path = path.substr(1);
5016 while(q && lq != q){
5018 var tm = q.match(tagTokenRe);
5019 if(type == "select"){
5022 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5024 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5026 q = q.replace(tm[0], "");
5027 }else if(q.substr(0, 1) != '@'){
5028 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5033 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5035 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5037 q = q.replace(tm[0], "");
5040 while(!(mm = q.match(modeRe))){
5041 var matched = false;
5042 for(var j = 0; j < tklen; j++){
5044 var m = q.match(t.re);
5046 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5049 q = q.replace(m[0], "");
5054 // prevent infinite loop on bad selector
5056 throw 'Error parsing selector, parsing failed at "' + q + '"';
5060 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5061 q = q.replace(mm[1], "");
5064 fn[fn.length] = "return nodup(n);\n}";
5067 * list of variables that need from compression as they are used by eval.
5077 * eval:var:byClassName
5079 * eval:var:byAttribute
5080 * eval:var:attrValue
5088 * Selects a group of elements.
5089 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5090 * @param {Node} root (optional) The start of the query (defaults to document).
5093 select : function(path, root, type){
5094 if(!root || root == document){
5097 if(typeof root == "string"){
5098 root = document.getElementById(root);
5100 var paths = path.split(",");
5102 for(var i = 0, len = paths.length; i < len; i++){
5103 var p = paths[i].replace(trimRe, "");
5105 cache[p] = Roo.DomQuery.compile(p);
5107 throw p + " is not a valid selector";
5110 var result = cache[p](root);
5111 if(result && result != document){
5112 results = results.concat(result);
5115 if(paths.length > 1){
5116 return nodup(results);
5122 * Selects a single element.
5123 * @param {String} selector The selector/xpath query
5124 * @param {Node} root (optional) The start of the query (defaults to document).
5127 selectNode : function(path, root){
5128 return Roo.DomQuery.select(path, root)[0];
5132 * Selects the value of a node, optionally replacing null with the defaultValue.
5133 * @param {String} selector The selector/xpath query
5134 * @param {Node} root (optional) The start of the query (defaults to document).
5135 * @param {String} defaultValue
5137 selectValue : function(path, root, defaultValue){
5138 path = path.replace(trimRe, "");
5139 if(!valueCache[path]){
5140 valueCache[path] = Roo.DomQuery.compile(path, "select");
5142 var n = valueCache[path](root);
5143 n = n[0] ? n[0] : n;
5144 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5145 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5149 * Selects the value of a node, parsing integers and floats.
5150 * @param {String} selector The selector/xpath query
5151 * @param {Node} root (optional) The start of the query (defaults to document).
5152 * @param {Number} defaultValue
5155 selectNumber : function(path, root, defaultValue){
5156 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5157 return parseFloat(v);
5161 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5162 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5163 * @param {String} selector The simple selector to test
5166 is : function(el, ss){
5167 if(typeof el == "string"){
5168 el = document.getElementById(el);
5170 var isArray = (el instanceof Array);
5171 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5172 return isArray ? (result.length == el.length) : (result.length > 0);
5176 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5177 * @param {Array} el An array of elements to filter
5178 * @param {String} selector The simple selector to test
5179 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5180 * the selector instead of the ones that match
5183 filter : function(els, ss, nonMatches){
5184 ss = ss.replace(trimRe, "");
5185 if(!simpleCache[ss]){
5186 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5188 var result = simpleCache[ss](els);
5189 return nonMatches ? quickDiff(result, els) : result;
5193 * Collection of matching regular expressions and code snippets.
5197 select: 'n = byClassName(n, null, " {1} ");'
5199 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5200 select: 'n = byPseudo(n, "{1}", "{2}");'
5202 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5203 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5206 select: 'n = byId(n, null, "{1}");'
5209 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5214 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5215 * 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, > <.
5218 "=" : function(a, v){
5221 "!=" : function(a, v){
5224 "^=" : function(a, v){
5225 return a && a.substr(0, v.length) == v;
5227 "$=" : function(a, v){
5228 return a && a.substr(a.length-v.length) == v;
5230 "*=" : function(a, v){
5231 return a && a.indexOf(v) !== -1;
5233 "%=" : function(a, v){
5234 return (a % v) == 0;
5236 "|=" : function(a, v){
5237 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5239 "~=" : function(a, v){
5240 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5245 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5246 * and the argument (if any) supplied in the selector.
5249 "first-child" : function(c){
5250 var r = [], ri = -1, n;
5251 for(var i = 0, ci; ci = n = c[i]; i++){
5252 while((n = n.previousSibling) && n.nodeType != 1);
5260 "last-child" : function(c){
5261 var r = [], ri = -1, n;
5262 for(var i = 0, ci; ci = n = c[i]; i++){
5263 while((n = n.nextSibling) && n.nodeType != 1);
5271 "nth-child" : function(c, a) {
5272 var r = [], ri = -1;
5273 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5274 var f = (m[1] || 1) - 0, l = m[2] - 0;
5275 for(var i = 0, n; n = c[i]; i++){
5276 var pn = n.parentNode;
5277 if (batch != pn._batch) {
5279 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5280 if(cn.nodeType == 1){
5287 if (l == 0 || n.nodeIndex == l){
5290 } else if ((n.nodeIndex + l) % f == 0){
5298 "only-child" : function(c){
5299 var r = [], ri = -1;;
5300 for(var i = 0, ci; ci = c[i]; i++){
5301 if(!prev(ci) && !next(ci)){
5308 "empty" : function(c){
5309 var r = [], ri = -1;
5310 for(var i = 0, ci; ci = c[i]; i++){
5311 var cns = ci.childNodes, j = 0, cn, empty = true;
5314 if(cn.nodeType == 1 || cn.nodeType == 3){
5326 "contains" : function(c, v){
5327 var r = [], ri = -1;
5328 for(var i = 0, ci; ci = c[i]; i++){
5329 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5336 "nodeValue" : function(c, v){
5337 var r = [], ri = -1;
5338 for(var i = 0, ci; ci = c[i]; i++){
5339 if(ci.firstChild && ci.firstChild.nodeValue == v){
5346 "checked" : function(c){
5347 var r = [], ri = -1;
5348 for(var i = 0, ci; ci = c[i]; i++){
5349 if(ci.checked == true){
5356 "not" : function(c, ss){
5357 return Roo.DomQuery.filter(c, ss, true);
5360 "odd" : function(c){
5361 return this["nth-child"](c, "odd");
5364 "even" : function(c){
5365 return this["nth-child"](c, "even");
5368 "nth" : function(c, a){
5369 return c[a-1] || [];
5372 "first" : function(c){
5376 "last" : function(c){
5377 return c[c.length-1] || [];
5380 "has" : function(c, ss){
5381 var s = Roo.DomQuery.select;
5382 var r = [], ri = -1;
5383 for(var i = 0, ci; ci = c[i]; i++){
5384 if(s(ss, ci).length > 0){
5391 "next" : function(c, ss){
5392 var is = Roo.DomQuery.is;
5393 var r = [], ri = -1;
5394 for(var i = 0, ci; ci = c[i]; i++){
5403 "prev" : function(c, ss){
5404 var is = Roo.DomQuery.is;
5405 var r = [], ri = -1;
5406 for(var i = 0, ci; ci = c[i]; i++){
5419 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5420 * @param {String} path The selector/xpath query
5421 * @param {Node} root (optional) The start of the query (defaults to document).
5426 Roo.query = Roo.DomQuery.select;
5429 * Ext JS Library 1.1.1
5430 * Copyright(c) 2006-2007, Ext JS, LLC.
5432 * Originally Released Under LGPL - original licence link has changed is not relivant.
5435 * <script type="text/javascript">
5439 * @class Roo.util.Observable
5440 * Base class that provides a common interface for publishing events. Subclasses are expected to
5441 * to have a property "events" with all the events defined.<br>
5444 Employee = function(name){
5451 Roo.extend(Employee, Roo.util.Observable);
5453 * @param {Object} config properties to use (incuding events / listeners)
5456 Roo.util.Observable = function(cfg){
5459 this.addEvents(cfg.events || {});
5461 delete cfg.events; // make sure
5464 Roo.apply(this, cfg);
5467 this.on(this.listeners);
5468 delete this.listeners;
5471 Roo.util.Observable.prototype = {
5473 * @cfg {Object} listeners list of events and functions to call for this object,
5477 'click' : function(e) {
5487 * Fires the specified event with the passed parameters (minus the event name).
5488 * @param {String} eventName
5489 * @param {Object...} args Variable number of parameters are passed to handlers
5490 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5492 fireEvent : function(){
5493 var ce = this.events[arguments[0].toLowerCase()];
5494 if(typeof ce == "object"){
5495 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5502 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5505 * Appends an event handler to this component
5506 * @param {String} eventName The type of event to listen for
5507 * @param {Function} handler The method the event invokes
5508 * @param {Object} scope (optional) The scope in which to execute the handler
5509 * function. The handler function's "this" context.
5510 * @param {Object} options (optional) An object containing handler configuration
5511 * properties. This may contain any of the following properties:<ul>
5512 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5513 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5514 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5515 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5516 * by the specified number of milliseconds. If the event fires again within that time, the original
5517 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5520 * <b>Combining Options</b><br>
5521 * Using the options argument, it is possible to combine different types of listeners:<br>
5523 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5525 el.on('click', this.onClick, this, {
5532 * <b>Attaching multiple handlers in 1 call</b><br>
5533 * The method also allows for a single argument to be passed which is a config object containing properties
5534 * which specify multiple handlers.
5543 fn: this.onMouseOver,
5547 fn: this.onMouseOut,
5553 * Or a shorthand syntax which passes the same scope object to all handlers:
5556 'click': this.onClick,
5557 'mouseover': this.onMouseOver,
5558 'mouseout': this.onMouseOut,
5563 addListener : function(eventName, fn, scope, o){
5564 if(typeof eventName == "object"){
5567 if(this.filterOptRe.test(e)){
5570 if(typeof o[e] == "function"){
5572 this.addListener(e, o[e], o.scope, o);
5574 // individual options
5575 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5580 o = (!o || typeof o == "boolean") ? {} : o;
5581 eventName = eventName.toLowerCase();
5582 var ce = this.events[eventName] || true;
5583 if(typeof ce == "boolean"){
5584 ce = new Roo.util.Event(this, eventName);
5585 this.events[eventName] = ce;
5587 ce.addListener(fn, scope, o);
5591 * Removes a listener
5592 * @param {String} eventName The type of event to listen for
5593 * @param {Function} handler The handler to remove
5594 * @param {Object} scope (optional) The scope (this object) for the handler
5596 removeListener : function(eventName, fn, scope){
5597 var ce = this.events[eventName.toLowerCase()];
5598 if(typeof ce == "object"){
5599 ce.removeListener(fn, scope);
5604 * Removes all listeners for this object
5606 purgeListeners : function(){
5607 for(var evt in this.events){
5608 if(typeof this.events[evt] == "object"){
5609 this.events[evt].clearListeners();
5614 relayEvents : function(o, events){
5615 var createHandler = function(ename){
5617 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5620 for(var i = 0, len = events.length; i < len; i++){
5621 var ename = events[i];
5622 if(!this.events[ename]){ this.events[ename] = true; };
5623 o.on(ename, createHandler(ename), this);
5628 * Used to define events on this Observable
5629 * @param {Object} object The object with the events defined
5631 addEvents : function(o){
5635 Roo.applyIf(this.events, o);
5639 * Checks to see if this object has any listeners for a specified event
5640 * @param {String} eventName The name of the event to check for
5641 * @return {Boolean} True if the event is being listened for, else false
5643 hasListener : function(eventName){
5644 var e = this.events[eventName];
5645 return typeof e == "object" && e.listeners.length > 0;
5649 * Appends an event handler to this element (shorthand for addListener)
5650 * @param {String} eventName The type of event to listen for
5651 * @param {Function} handler The method the event invokes
5652 * @param {Object} scope (optional) The scope in which to execute the handler
5653 * function. The handler function's "this" context.
5654 * @param {Object} options (optional)
5657 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5659 * Removes a listener (shorthand for removeListener)
5660 * @param {String} eventName The type of event to listen for
5661 * @param {Function} handler The handler to remove
5662 * @param {Object} scope (optional) The scope (this object) for the handler
5665 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5668 * Starts capture on the specified Observable. All events will be passed
5669 * to the supplied function with the event name + standard signature of the event
5670 * <b>before</b> the event is fired. If the supplied function returns false,
5671 * the event will not fire.
5672 * @param {Observable} o The Observable to capture
5673 * @param {Function} fn The function to call
5674 * @param {Object} scope (optional) The scope (this object) for the fn
5677 Roo.util.Observable.capture = function(o, fn, scope){
5678 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5682 * Removes <b>all</b> added captures from the Observable.
5683 * @param {Observable} o The Observable to release
5686 Roo.util.Observable.releaseCapture = function(o){
5687 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5692 var createBuffered = function(h, o, scope){
5693 var task = new Roo.util.DelayedTask();
5695 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5699 var createSingle = function(h, e, fn, scope){
5701 e.removeListener(fn, scope);
5702 return h.apply(scope, arguments);
5706 var createDelayed = function(h, o, scope){
5708 var args = Array.prototype.slice.call(arguments, 0);
5709 setTimeout(function(){
5710 h.apply(scope, args);
5715 Roo.util.Event = function(obj, name){
5718 this.listeners = [];
5721 Roo.util.Event.prototype = {
5722 addListener : function(fn, scope, options){
5723 var o = options || {};
5724 scope = scope || this.obj;
5725 if(!this.isListening(fn, scope)){
5726 var l = {fn: fn, scope: scope, options: o};
5729 h = createDelayed(h, o, scope);
5732 h = createSingle(h, this, fn, scope);
5735 h = createBuffered(h, o, scope);
5738 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5739 this.listeners.push(l);
5741 this.listeners = this.listeners.slice(0);
5742 this.listeners.push(l);
5747 findListener : function(fn, scope){
5748 scope = scope || this.obj;
5749 var ls = this.listeners;
5750 for(var i = 0, len = ls.length; i < len; i++){
5752 if(l.fn == fn && l.scope == scope){
5759 isListening : function(fn, scope){
5760 return this.findListener(fn, scope) != -1;
5763 removeListener : function(fn, scope){
5765 if((index = this.findListener(fn, scope)) != -1){
5767 this.listeners.splice(index, 1);
5769 this.listeners = this.listeners.slice(0);
5770 this.listeners.splice(index, 1);
5777 clearListeners : function(){
5778 this.listeners = [];
5782 var ls = this.listeners, scope, len = ls.length;
5785 var args = Array.prototype.slice.call(arguments, 0);
5786 for(var i = 0; i < len; i++){
5788 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5789 this.firing = false;
5793 this.firing = false;
5800 * Ext JS Library 1.1.1
5801 * Copyright(c) 2006-2007, Ext JS, LLC.
5803 * Originally Released Under LGPL - original licence link has changed is not relivant.
5806 * <script type="text/javascript">
5810 * @class Roo.EventManager
5811 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5812 * several useful events directly.
5813 * See {@link Roo.EventObject} for more details on normalized event objects.
5816 Roo.EventManager = function(){
5817 var docReadyEvent, docReadyProcId, docReadyState = false;
5818 var resizeEvent, resizeTask, textEvent, textSize;
5819 var E = Roo.lib.Event;
5820 var D = Roo.lib.Dom;
5823 var fireDocReady = function(){
5825 docReadyState = true;
5828 clearInterval(docReadyProcId);
5830 if(Roo.isGecko || Roo.isOpera) {
5831 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5834 var defer = document.getElementById("ie-deferred-loader");
5836 defer.onreadystatechange = null;
5837 defer.parentNode.removeChild(defer);
5841 docReadyEvent.fire();
5842 docReadyEvent.clearListeners();
5847 var initDocReady = function(){
5848 docReadyEvent = new Roo.util.Event();
5849 if(Roo.isGecko || Roo.isOpera) {
5850 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5852 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5853 var defer = document.getElementById("ie-deferred-loader");
5854 defer.onreadystatechange = function(){
5855 if(this.readyState == "complete"){
5859 }else if(Roo.isSafari){
5860 docReadyProcId = setInterval(function(){
5861 var rs = document.readyState;
5862 if(rs == "complete") {
5867 // no matter what, make sure it fires on load
5868 E.on(window, "load", fireDocReady);
5871 var createBuffered = function(h, o){
5872 var task = new Roo.util.DelayedTask(h);
5874 // create new event object impl so new events don't wipe out properties
5875 e = new Roo.EventObjectImpl(e);
5876 task.delay(o.buffer, h, null, [e]);
5880 var createSingle = function(h, el, ename, fn){
5882 Roo.EventManager.removeListener(el, ename, fn);
5887 var createDelayed = function(h, o){
5889 // create new event object impl so new events don't wipe out properties
5890 e = new Roo.EventObjectImpl(e);
5891 setTimeout(function(){
5897 var listen = function(element, ename, opt, fn, scope){
5898 var o = (!opt || typeof opt == "boolean") ? {} : opt;
5899 fn = fn || o.fn; scope = scope || o.scope;
5900 var el = Roo.getDom(element);
5902 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5904 var h = function(e){
5905 e = Roo.EventObject.setEvent(e);
5908 t = e.getTarget(o.delegate, el);
5915 if(o.stopEvent === true){
5918 if(o.preventDefault === true){
5921 if(o.stopPropagation === true){
5922 e.stopPropagation();
5925 if(o.normalized === false){
5929 fn.call(scope || el, e, t, o);
5932 h = createDelayed(h, o);
5935 h = createSingle(h, el, ename, fn);
5938 h = createBuffered(h, o);
5940 fn._handlers = fn._handlers || [];
5941 fn._handlers.push([Roo.id(el), ename, h]);
5944 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5945 el.addEventListener("DOMMouseScroll", h, false);
5946 E.on(window, 'unload', function(){
5947 el.removeEventListener("DOMMouseScroll", h, false);
5950 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5951 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5956 var stopListening = function(el, ename, fn){
5957 var id = Roo.id(el), hds = fn._handlers, hd = fn;
5959 for(var i = 0, len = hds.length; i < len; i++){
5961 if(h[0] == id && h[1] == ename){
5968 E.un(el, ename, hd);
5969 el = Roo.getDom(el);
5970 if(ename == "mousewheel" && el.addEventListener){
5971 el.removeEventListener("DOMMouseScroll", hd, false);
5973 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5974 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5978 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
5985 * @scope Roo.EventManager
5990 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
5991 * object with a Roo.EventObject
5992 * @param {Function} fn The method the event invokes
5993 * @param {Object} scope An object that becomes the scope of the handler
5994 * @param {boolean} override If true, the obj passed in becomes
5995 * the execution scope of the listener
5996 * @return {Function} The wrapped function
5999 wrap : function(fn, scope, override){
6001 Roo.EventObject.setEvent(e);
6002 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6007 * Appends an event handler to an element (shorthand for addListener)
6008 * @param {String/HTMLElement} element The html element or id to assign the
6009 * @param {String} eventName The type of event to listen for
6010 * @param {Function} handler The method the event invokes
6011 * @param {Object} scope (optional) The scope in which to execute the handler
6012 * function. The handler function's "this" context.
6013 * @param {Object} options (optional) An object containing handler configuration
6014 * properties. This may contain any of the following properties:<ul>
6015 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6016 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6017 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6018 * <li>preventDefault {Boolean} True to prevent the default action</li>
6019 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6020 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6021 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6022 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6023 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6024 * by the specified number of milliseconds. If the event fires again within that time, the original
6025 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6028 * <b>Combining Options</b><br>
6029 * Using the options argument, it is possible to combine different types of listeners:<br>
6031 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6033 el.on('click', this.onClick, this, {
6040 * <b>Attaching multiple handlers in 1 call</b><br>
6041 * The method also allows for a single argument to be passed which is a config object containing properties
6042 * which specify multiple handlers.
6052 fn: this.onMouseOver
6061 * Or a shorthand syntax:<br>
6064 'click' : this.onClick,
6065 'mouseover' : this.onMouseOver,
6066 'mouseout' : this.onMouseOut
6070 addListener : function(element, eventName, fn, scope, options){
6071 if(typeof eventName == "object"){
6077 if(typeof o[e] == "function"){
6079 listen(element, e, o, o[e], o.scope);
6081 // individual options
6082 listen(element, e, o[e]);
6087 return listen(element, eventName, options, fn, scope);
6091 * Removes an event handler
6093 * @param {String/HTMLElement} element The id or html element to remove the
6095 * @param {String} eventName The type of event
6096 * @param {Function} fn
6097 * @return {Boolean} True if a listener was actually removed
6099 removeListener : function(element, eventName, fn){
6100 return stopListening(element, eventName, fn);
6104 * Fires when the document is ready (before onload and before images are loaded). Can be
6105 * accessed shorthanded Roo.onReady().
6106 * @param {Function} fn The method the event invokes
6107 * @param {Object} scope An object that becomes the scope of the handler
6108 * @param {boolean} options
6110 onDocumentReady : function(fn, scope, options){
6111 if(docReadyState){ // if it already fired
6112 docReadyEvent.addListener(fn, scope, options);
6113 docReadyEvent.fire();
6114 docReadyEvent.clearListeners();
6120 docReadyEvent.addListener(fn, scope, options);
6124 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6125 * @param {Function} fn The method the event invokes
6126 * @param {Object} scope An object that becomes the scope of the handler
6127 * @param {boolean} options
6129 onWindowResize : function(fn, scope, options){
6131 resizeEvent = new Roo.util.Event();
6132 resizeTask = new Roo.util.DelayedTask(function(){
6133 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6135 E.on(window, "resize", function(){
6137 resizeTask.delay(50);
6139 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6143 resizeEvent.addListener(fn, scope, options);
6147 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6148 * @param {Function} fn The method the event invokes
6149 * @param {Object} scope An object that becomes the scope of the handler
6150 * @param {boolean} options
6152 onTextResize : function(fn, scope, options){
6154 textEvent = new Roo.util.Event();
6155 var textEl = new Roo.Element(document.createElement('div'));
6156 textEl.dom.className = 'x-text-resize';
6157 textEl.dom.innerHTML = 'X';
6158 textEl.appendTo(document.body);
6159 textSize = textEl.dom.offsetHeight;
6160 setInterval(function(){
6161 if(textEl.dom.offsetHeight != textSize){
6162 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6164 }, this.textResizeInterval);
6166 textEvent.addListener(fn, scope, options);
6170 * Removes the passed window resize listener.
6171 * @param {Function} fn The method the event invokes
6172 * @param {Object} scope The scope of handler
6174 removeResizeListener : function(fn, scope){
6176 resizeEvent.removeListener(fn, scope);
6181 fireResize : function(){
6183 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6187 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6191 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6193 textResizeInterval : 50
6198 * @scopeAlias pub=Roo.EventManager
6202 * Appends an event handler to an element (shorthand for addListener)
6203 * @param {String/HTMLElement} element The html element or id to assign the
6204 * @param {String} eventName The type of event to listen for
6205 * @param {Function} handler The method the event invokes
6206 * @param {Object} scope (optional) The scope in which to execute the handler
6207 * function. The handler function's "this" context.
6208 * @param {Object} options (optional) An object containing handler configuration
6209 * properties. This may contain any of the following properties:<ul>
6210 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6211 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6212 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6213 * <li>preventDefault {Boolean} True to prevent the default action</li>
6214 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6215 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6216 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6217 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6218 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6219 * by the specified number of milliseconds. If the event fires again within that time, the original
6220 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6223 * <b>Combining Options</b><br>
6224 * Using the options argument, it is possible to combine different types of listeners:<br>
6226 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6228 el.on('click', this.onClick, this, {
6235 * <b>Attaching multiple handlers in 1 call</b><br>
6236 * The method also allows for a single argument to be passed which is a config object containing properties
6237 * which specify multiple handlers.
6247 fn: this.onMouseOver
6256 * Or a shorthand syntax:<br>
6259 'click' : this.onClick,
6260 'mouseover' : this.onMouseOver,
6261 'mouseout' : this.onMouseOut
6265 pub.on = pub.addListener;
6266 pub.un = pub.removeListener;
6268 pub.stoppedMouseDownEvent = new Roo.util.Event();
6272 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6273 * @param {Function} fn The method the event invokes
6274 * @param {Object} scope An object that becomes the scope of the handler
6275 * @param {boolean} override If true, the obj passed in becomes
6276 * the execution scope of the listener
6280 Roo.onReady = Roo.EventManager.onDocumentReady;
6282 Roo.onReady(function(){
6283 var bd = Roo.get(document.body);
6288 : Roo.isGecko ? "roo-gecko"
6289 : Roo.isOpera ? "roo-opera"
6290 : Roo.isSafari ? "roo-safari" : ""];
6293 cls.push("roo-mac");
6296 cls.push("roo-linux");
6298 if(Roo.isBorderBox){
6299 cls.push('roo-border-box');
6301 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6302 var p = bd.dom.parentNode;
6304 p.className += ' roo-strict';
6307 bd.addClass(cls.join(' '));
6311 * @class Roo.EventObject
6312 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6313 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6316 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6318 var target = e.getTarget();
6321 var myDiv = Roo.get("myDiv");
6322 myDiv.on("click", handleClick);
6324 Roo.EventManager.on("myDiv", 'click', handleClick);
6325 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6329 Roo.EventObject = function(){
6331 var E = Roo.lib.Event;
6333 // safari keypress events for special keys return bad keycodes
6336 63235 : 39, // right
6339 63276 : 33, // page up
6340 63277 : 34, // page down
6341 63272 : 46, // delete
6346 // normalize button clicks
6347 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6348 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6350 Roo.EventObjectImpl = function(e){
6352 this.setEvent(e.browserEvent || e);
6355 Roo.EventObjectImpl.prototype = {
6357 * Used to fix doc tools.
6358 * @scope Roo.EventObject.prototype
6364 /** The normal browser event */
6365 browserEvent : null,
6366 /** The button pressed in a mouse event */
6368 /** True if the shift key was down during the event */
6370 /** True if the control key was down during the event */
6372 /** True if the alt key was down during the event */
6431 setEvent : function(e){
6432 if(e == this || (e && e.browserEvent)){ // already wrapped
6435 this.browserEvent = e;
6437 // normalize buttons
6438 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6439 if(e.type == 'click' && this.button == -1){
6443 this.shiftKey = e.shiftKey;
6444 // mac metaKey behaves like ctrlKey
6445 this.ctrlKey = e.ctrlKey || e.metaKey;
6446 this.altKey = e.altKey;
6447 // in getKey these will be normalized for the mac
6448 this.keyCode = e.keyCode;
6449 // keyup warnings on firefox.
6450 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6451 // cache the target for the delayed and or buffered events
6452 this.target = E.getTarget(e);
6454 this.xy = E.getXY(e);
6457 this.shiftKey = false;
6458 this.ctrlKey = false;
6459 this.altKey = false;
6469 * Stop the event (preventDefault and stopPropagation)
6471 stopEvent : function(){
6472 if(this.browserEvent){
6473 if(this.browserEvent.type == 'mousedown'){
6474 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6476 E.stopEvent(this.browserEvent);
6481 * Prevents the browsers default handling of the event.
6483 preventDefault : function(){
6484 if(this.browserEvent){
6485 E.preventDefault(this.browserEvent);
6490 isNavKeyPress : function(){
6491 var k = this.keyCode;
6492 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6493 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6496 isSpecialKey : function(){
6497 var k = this.keyCode;
6498 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6499 (k == 16) || (k == 17) ||
6500 (k >= 18 && k <= 20) ||
6501 (k >= 33 && k <= 35) ||
6502 (k >= 36 && k <= 39) ||
6503 (k >= 44 && k <= 45);
6506 * Cancels bubbling of the event.
6508 stopPropagation : function(){
6509 if(this.browserEvent){
6510 if(this.type == 'mousedown'){
6511 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6513 E.stopPropagation(this.browserEvent);
6518 * Gets the key code for the event.
6521 getCharCode : function(){
6522 return this.charCode || this.keyCode;
6526 * Returns a normalized keyCode for the event.
6527 * @return {Number} The key code
6529 getKey : function(){
6530 var k = this.keyCode || this.charCode;
6531 return Roo.isSafari ? (safariKeys[k] || k) : k;
6535 * Gets the x coordinate of the event.
6538 getPageX : function(){
6543 * Gets the y coordinate of the event.
6546 getPageY : function(){
6551 * Gets the time of the event.
6554 getTime : function(){
6555 if(this.browserEvent){
6556 return E.getTime(this.browserEvent);
6562 * Gets the page coordinates of the event.
6563 * @return {Array} The xy values like [x, y]
6570 * Gets the target for the event.
6571 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6572 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6573 search as a number or element (defaults to 10 || document.body)
6574 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6575 * @return {HTMLelement}
6577 getTarget : function(selector, maxDepth, returnEl){
6578 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6581 * Gets the related target.
6582 * @return {HTMLElement}
6584 getRelatedTarget : function(){
6585 if(this.browserEvent){
6586 return E.getRelatedTarget(this.browserEvent);
6592 * Normalizes mouse wheel delta across browsers
6593 * @return {Number} The delta
6595 getWheelDelta : function(){
6596 var e = this.browserEvent;
6598 if(e.wheelDelta){ /* IE/Opera. */
6599 delta = e.wheelDelta/120;
6600 }else if(e.detail){ /* Mozilla case. */
6601 delta = -e.detail/3;
6607 * Returns true if the control, meta, shift or alt key was pressed during this event.
6610 hasModifier : function(){
6611 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6615 * Returns true if the target of this event equals el or is a child of el
6616 * @param {String/HTMLElement/Element} el
6617 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6620 within : function(el, related){
6621 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6622 return t && Roo.fly(el).contains(t);
6625 getPoint : function(){
6626 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6630 return new Roo.EventObjectImpl();
6635 * Ext JS Library 1.1.1
6636 * Copyright(c) 2006-2007, Ext JS, LLC.
6638 * Originally Released Under LGPL - original licence link has changed is not relivant.
6641 * <script type="text/javascript">
6645 // was in Composite Element!??!?!
6648 var D = Roo.lib.Dom;
6649 var E = Roo.lib.Event;
6650 var A = Roo.lib.Anim;
6652 // local style camelizing for speed
6654 var camelRe = /(-[a-z])/gi;
6655 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6656 var view = document.defaultView;
6659 * @class Roo.Element
6660 * Represents an Element in the DOM.<br><br>
6663 var el = Roo.get("my-div");
6666 var el = getEl("my-div");
6668 // or with a DOM element
6669 var el = Roo.get(myDivElement);
6671 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6672 * each call instead of constructing a new one.<br><br>
6673 * <b>Animations</b><br />
6674 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6675 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6677 Option Default Description
6678 --------- -------- ---------------------------------------------
6679 duration .35 The duration of the animation in seconds
6680 easing easeOut The YUI easing method
6681 callback none A function to execute when the anim completes
6682 scope this The scope (this) of the callback function
6684 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6685 * manipulate the animation. Here's an example:
6687 var el = Roo.get("my-div");
6692 // default animation
6693 el.setWidth(100, true);
6695 // animation with some options set
6702 // using the "anim" property to get the Anim object
6708 el.setWidth(100, opt);
6710 if(opt.anim.isAnimated()){
6714 * <b> Composite (Collections of) Elements</b><br />
6715 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6716 * @constructor Create a new Element directly.
6717 * @param {String/HTMLElement} element
6718 * @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).
6720 Roo.Element = function(element, forceNew){
6721 var dom = typeof element == "string" ?
6722 document.getElementById(element) : element;
6723 if(!dom){ // invalid id/element
6727 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6728 return Roo.Element.cache[id];
6738 * The DOM element ID
6741 this.id = id || Roo.id(dom);
6744 var El = Roo.Element;
6748 * The element's default display mode (defaults to "")
6751 originalDisplay : "",
6755 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6760 * Sets the element's visibility mode. When setVisible() is called it
6761 * will use this to determine whether to set the visibility or the display property.
6762 * @param visMode Element.VISIBILITY or Element.DISPLAY
6763 * @return {Roo.Element} this
6765 setVisibilityMode : function(visMode){
6766 this.visibilityMode = visMode;
6770 * Convenience method for setVisibilityMode(Element.DISPLAY)
6771 * @param {String} display (optional) What to set display to when visible
6772 * @return {Roo.Element} this
6774 enableDisplayMode : function(display){
6775 this.setVisibilityMode(El.DISPLAY);
6776 if(typeof display != "undefined") this.originalDisplay = display;
6781 * 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)
6782 * @param {String} selector The simple selector to test
6783 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6784 search as a number or element (defaults to 10 || document.body)
6785 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6786 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6788 findParent : function(simpleSelector, maxDepth, returnEl){
6789 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6790 maxDepth = maxDepth || 50;
6791 if(typeof maxDepth != "number"){
6792 stopEl = Roo.getDom(maxDepth);
6795 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6796 if(dq.is(p, simpleSelector)){
6797 return returnEl ? Roo.get(p) : p;
6807 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6808 * @param {String} selector The simple selector to test
6809 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6810 search as a number or element (defaults to 10 || document.body)
6811 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6812 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6814 findParentNode : function(simpleSelector, maxDepth, returnEl){
6815 var p = Roo.fly(this.dom.parentNode, '_internal');
6816 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6820 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6821 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6822 * @param {String} selector The simple selector to test
6823 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6824 search as a number or element (defaults to 10 || document.body)
6825 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6827 up : function(simpleSelector, maxDepth){
6828 return this.findParentNode(simpleSelector, maxDepth, true);
6834 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6835 * @param {String} selector The simple selector to test
6836 * @return {Boolean} True if this element matches the selector, else false
6838 is : function(simpleSelector){
6839 return Roo.DomQuery.is(this.dom, simpleSelector);
6843 * Perform animation on this element.
6844 * @param {Object} args The YUI animation control args
6845 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6846 * @param {Function} onComplete (optional) Function to call when animation completes
6847 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6848 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6849 * @return {Roo.Element} this
6851 animate : function(args, duration, onComplete, easing, animType){
6852 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6857 * @private Internal animation call
6859 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6860 animType = animType || 'run';
6862 var anim = Roo.lib.Anim[animType](
6864 (opt.duration || defaultDur) || .35,
6865 (opt.easing || defaultEase) || 'easeOut',
6867 Roo.callback(cb, this);
6868 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6876 // private legacy anim prep
6877 preanim : function(a, i){
6878 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6882 * Removes worthless text nodes
6883 * @param {Boolean} forceReclean (optional) By default the element
6884 * keeps track if it has been cleaned already so
6885 * you can call this over and over. However, if you update the element and
6886 * need to force a reclean, you can pass true.
6888 clean : function(forceReclean){
6889 if(this.isCleaned && forceReclean !== true){
6893 var d = this.dom, n = d.firstChild, ni = -1;
6895 var nx = n.nextSibling;
6896 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6903 this.isCleaned = true;
6908 calcOffsetsTo : function(el){
6911 var restorePos = false;
6912 if(el.getStyle('position') == 'static'){
6913 el.position('relative');
6918 while(op && op != d && op.tagName != 'HTML'){
6921 op = op.offsetParent;
6924 el.position('static');
6930 * Scrolls this element into view within the passed container.
6931 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6932 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6933 * @return {Roo.Element} this
6935 scrollIntoView : function(container, hscroll){
6936 var c = Roo.getDom(container) || document.body;
6939 var o = this.calcOffsetsTo(c),
6942 b = t+el.offsetHeight,
6943 r = l+el.offsetWidth;
6945 var ch = c.clientHeight;
6946 var ct = parseInt(c.scrollTop, 10);
6947 var cl = parseInt(c.scrollLeft, 10);
6949 var cr = cl + c.clientWidth;
6957 if(hscroll !== false){
6961 c.scrollLeft = r-c.clientWidth;
6968 scrollChildIntoView : function(child, hscroll){
6969 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6973 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6974 * the new height may not be available immediately.
6975 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6976 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6977 * @param {Function} onComplete (optional) Function to call when animation completes
6978 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
6979 * @return {Roo.Element} this
6981 autoHeight : function(animate, duration, onComplete, easing){
6982 var oldHeight = this.getHeight();
6984 this.setHeight(1); // force clipping
6985 setTimeout(function(){
6986 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
6988 this.setHeight(height);
6990 if(typeof onComplete == "function"){
6994 this.setHeight(oldHeight); // restore original height
6995 this.setHeight(height, animate, duration, function(){
6997 if(typeof onComplete == "function") onComplete();
6998 }.createDelegate(this), easing);
7000 }.createDelegate(this), 0);
7005 * Returns true if this element is an ancestor of the passed element
7006 * @param {HTMLElement/String} el The element to check
7007 * @return {Boolean} True if this element is an ancestor of el, else false
7009 contains : function(el){
7010 if(!el){return false;}
7011 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7015 * Checks whether the element is currently visible using both visibility and display properties.
7016 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7017 * @return {Boolean} True if the element is currently visible, else false
7019 isVisible : function(deep) {
7020 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7021 if(deep !== true || !vis){
7024 var p = this.dom.parentNode;
7025 while(p && p.tagName.toLowerCase() != "body"){
7026 if(!Roo.fly(p, '_isVisible').isVisible()){
7035 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7036 * @param {String} selector The CSS selector
7037 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7038 * @return {CompositeElement/CompositeElementLite} The composite element
7040 select : function(selector, unique){
7041 return El.select(selector, unique, this.dom);
7045 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7046 * @param {String} selector The CSS selector
7047 * @return {Array} An array of the matched nodes
7049 query : function(selector, unique){
7050 return Roo.DomQuery.select(selector, this.dom);
7054 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7055 * @param {String} selector The CSS selector
7056 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7057 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7059 child : function(selector, returnDom){
7060 var n = Roo.DomQuery.selectNode(selector, this.dom);
7061 return returnDom ? n : Roo.get(n);
7065 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7066 * @param {String} selector The CSS selector
7067 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7068 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7070 down : function(selector, returnDom){
7071 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7072 return returnDom ? n : Roo.get(n);
7076 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7077 * @param {String} group The group the DD object is member of
7078 * @param {Object} config The DD config object
7079 * @param {Object} overrides An object containing methods to override/implement on the DD object
7080 * @return {Roo.dd.DD} The DD object
7082 initDD : function(group, config, overrides){
7083 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7084 return Roo.apply(dd, overrides);
7088 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7089 * @param {String} group The group the DDProxy object is member of
7090 * @param {Object} config The DDProxy config object
7091 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7092 * @return {Roo.dd.DDProxy} The DDProxy object
7094 initDDProxy : function(group, config, overrides){
7095 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7096 return Roo.apply(dd, overrides);
7100 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7101 * @param {String} group The group the DDTarget object is member of
7102 * @param {Object} config The DDTarget config object
7103 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7104 * @return {Roo.dd.DDTarget} The DDTarget object
7106 initDDTarget : function(group, config, overrides){
7107 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7108 return Roo.apply(dd, overrides);
7112 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7113 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7114 * @param {Boolean} visible Whether the element is visible
7115 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7116 * @return {Roo.Element} this
7118 setVisible : function(visible, animate){
7120 if(this.visibilityMode == El.DISPLAY){
7121 this.setDisplayed(visible);
7124 this.dom.style.visibility = visible ? "visible" : "hidden";
7127 // closure for composites
7129 var visMode = this.visibilityMode;
7131 this.setOpacity(.01);
7132 this.setVisible(true);
7134 this.anim({opacity: { to: (visible?1:0) }},
7135 this.preanim(arguments, 1),
7136 null, .35, 'easeIn', function(){
7138 if(visMode == El.DISPLAY){
7139 dom.style.display = "none";
7141 dom.style.visibility = "hidden";
7143 Roo.get(dom).setOpacity(1);
7151 * Returns true if display is not "none"
7154 isDisplayed : function() {
7155 return this.getStyle("display") != "none";
7159 * Toggles the element's visibility or display, depending on visibility mode.
7160 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7161 * @return {Roo.Element} this
7163 toggle : function(animate){
7164 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7169 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7170 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7171 * @return {Roo.Element} this
7173 setDisplayed : function(value) {
7174 if(typeof value == "boolean"){
7175 value = value ? this.originalDisplay : "none";
7177 this.setStyle("display", value);
7182 * Tries to focus the element. Any exceptions are caught and ignored.
7183 * @return {Roo.Element} this
7185 focus : function() {
7193 * Tries to blur the element. Any exceptions are caught and ignored.
7194 * @return {Roo.Element} this
7204 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7205 * @param {String/Array} className The CSS class to add, or an array of classes
7206 * @return {Roo.Element} this
7208 addClass : function(className){
7209 if(className instanceof Array){
7210 for(var i = 0, len = className.length; i < len; i++) {
7211 this.addClass(className[i]);
7214 if(className && !this.hasClass(className)){
7215 this.dom.className = this.dom.className + " " + className;
7222 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7223 * @param {String/Array} className The CSS class to add, or an array of classes
7224 * @return {Roo.Element} this
7226 radioClass : function(className){
7227 var siblings = this.dom.parentNode.childNodes;
7228 for(var i = 0; i < siblings.length; i++) {
7229 var s = siblings[i];
7230 if(s.nodeType == 1){
7231 Roo.get(s).removeClass(className);
7234 this.addClass(className);
7239 * Removes one or more CSS classes from the element.
7240 * @param {String/Array} className The CSS class to remove, or an array of classes
7241 * @return {Roo.Element} this
7243 removeClass : function(className){
7244 if(!className || !this.dom.className){
7247 if(className instanceof Array){
7248 for(var i = 0, len = className.length; i < len; i++) {
7249 this.removeClass(className[i]);
7252 if(this.hasClass(className)){
7253 var re = this.classReCache[className];
7255 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7256 this.classReCache[className] = re;
7258 this.dom.className =
7259 this.dom.className.replace(re, " ");
7269 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7270 * @param {String} className The CSS class to toggle
7271 * @return {Roo.Element} this
7273 toggleClass : function(className){
7274 if(this.hasClass(className)){
7275 this.removeClass(className);
7277 this.addClass(className);
7283 * Checks if the specified CSS class exists on this element's DOM node.
7284 * @param {String} className The CSS class to check for
7285 * @return {Boolean} True if the class exists, else false
7287 hasClass : function(className){
7288 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7292 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7293 * @param {String} oldClassName The CSS class to replace
7294 * @param {String} newClassName The replacement CSS class
7295 * @return {Roo.Element} this
7297 replaceClass : function(oldClassName, newClassName){
7298 this.removeClass(oldClassName);
7299 this.addClass(newClassName);
7304 * Returns an object with properties matching the styles requested.
7305 * For example, el.getStyles('color', 'font-size', 'width') might return
7306 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7307 * @param {String} style1 A style name
7308 * @param {String} style2 A style name
7309 * @param {String} etc.
7310 * @return {Object} The style object
7312 getStyles : function(){
7313 var a = arguments, len = a.length, r = {};
7314 for(var i = 0; i < len; i++){
7315 r[a[i]] = this.getStyle(a[i]);
7321 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7322 * @param {String} property The style property whose value is returned.
7323 * @return {String} The current value of the style property for this element.
7325 getStyle : function(){
7326 return view && view.getComputedStyle ?
7328 var el = this.dom, v, cs, camel;
7329 if(prop == 'float'){
7332 if(el.style && (v = el.style[prop])){
7335 if(cs = view.getComputedStyle(el, "")){
7336 if(!(camel = propCache[prop])){
7337 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7344 var el = this.dom, v, cs, camel;
7345 if(prop == 'opacity'){
7346 if(typeof el.style.filter == 'string'){
7347 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7349 var fv = parseFloat(m[1]);
7351 return fv ? fv / 100 : 0;
7356 }else if(prop == 'float'){
7357 prop = "styleFloat";
7359 if(!(camel = propCache[prop])){
7360 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7362 if(v = el.style[camel]){
7365 if(cs = el.currentStyle){
7373 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7374 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7375 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7376 * @return {Roo.Element} this
7378 setStyle : function(prop, value){
7379 if(typeof prop == "string"){
7381 if(!(camel = propCache[prop])){
7382 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7384 if(camel == 'opacity') {
7385 this.setOpacity(value);
7387 this.dom.style[camel] = value;
7390 for(var style in prop){
7391 if(typeof prop[style] != "function"){
7392 this.setStyle(style, prop[style]);
7400 * More flexible version of {@link #setStyle} for setting style properties.
7401 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7402 * a function which returns such a specification.
7403 * @return {Roo.Element} this
7405 applyStyles : function(style){
7406 Roo.DomHelper.applyStyles(this.dom, style);
7411 * 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).
7412 * @return {Number} The X position of the element
7415 return D.getX(this.dom);
7419 * 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).
7420 * @return {Number} The Y position of the element
7423 return D.getY(this.dom);
7427 * 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).
7428 * @return {Array} The XY position of the element
7431 return D.getXY(this.dom);
7435 * 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).
7436 * @param {Number} The X position of the element
7437 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7438 * @return {Roo.Element} this
7440 setX : function(x, animate){
7442 D.setX(this.dom, x);
7444 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7450 * 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).
7451 * @param {Number} The Y position of the element
7452 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7453 * @return {Roo.Element} this
7455 setY : function(y, animate){
7457 D.setY(this.dom, y);
7459 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7465 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7466 * @param {String} left The left CSS property value
7467 * @return {Roo.Element} this
7469 setLeft : function(left){
7470 this.setStyle("left", this.addUnits(left));
7475 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7476 * @param {String} top The top CSS property value
7477 * @return {Roo.Element} this
7479 setTop : function(top){
7480 this.setStyle("top", this.addUnits(top));
7485 * Sets the element's CSS right style.
7486 * @param {String} right The right CSS property value
7487 * @return {Roo.Element} this
7489 setRight : function(right){
7490 this.setStyle("right", this.addUnits(right));
7495 * Sets the element's CSS bottom style.
7496 * @param {String} bottom The bottom CSS property value
7497 * @return {Roo.Element} this
7499 setBottom : function(bottom){
7500 this.setStyle("bottom", this.addUnits(bottom));
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 {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7508 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7509 * @return {Roo.Element} this
7511 setXY : function(pos, animate){
7513 D.setXY(this.dom, pos);
7515 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7521 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7522 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7523 * @param {Number} x X value for new position (coordinates are page-based)
7524 * @param {Number} y Y value for new position (coordinates are page-based)
7525 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7526 * @return {Roo.Element} this
7528 setLocation : function(x, y, animate){
7529 this.setXY([x, y], this.preanim(arguments, 2));
7534 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7535 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7536 * @param {Number} x X value for new position (coordinates are page-based)
7537 * @param {Number} y Y value for new position (coordinates are page-based)
7538 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7539 * @return {Roo.Element} this
7541 moveTo : function(x, y, animate){
7542 this.setXY([x, y], this.preanim(arguments, 2));
7547 * Returns the region of the given element.
7548 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7549 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7551 getRegion : function(){
7552 return D.getRegion(this.dom);
7556 * Returns the offset height of the element
7557 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7558 * @return {Number} The element's height
7560 getHeight : function(contentHeight){
7561 var h = this.dom.offsetHeight || 0;
7562 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7566 * Returns the offset width of the element
7567 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7568 * @return {Number} The element's width
7570 getWidth : function(contentWidth){
7571 var w = this.dom.offsetWidth || 0;
7572 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7576 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7577 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7578 * if a height has not been set using CSS.
7581 getComputedHeight : function(){
7582 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7584 h = parseInt(this.getStyle('height'), 10) || 0;
7585 if(!this.isBorderBox()){
7586 h += this.getFrameWidth('tb');
7593 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7594 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7595 * if a width has not been set using CSS.
7598 getComputedWidth : function(){
7599 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7601 w = parseInt(this.getStyle('width'), 10) || 0;
7602 if(!this.isBorderBox()){
7603 w += this.getFrameWidth('lr');
7610 * Returns the size of the element.
7611 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7612 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7614 getSize : function(contentSize){
7615 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7619 * Returns the width and height of the viewport.
7620 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7622 getViewSize : function(){
7623 var d = this.dom, doc = document, aw = 0, ah = 0;
7624 if(d == doc || d == doc.body){
7625 return {width : D.getViewWidth(), height: D.getViewHeight()};
7628 width : d.clientWidth,
7629 height: d.clientHeight
7635 * Returns the value of the "value" attribute
7636 * @param {Boolean} asNumber true to parse the value as a number
7637 * @return {String/Number}
7639 getValue : function(asNumber){
7640 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7644 adjustWidth : function(width){
7645 if(typeof width == "number"){
7646 if(this.autoBoxAdjust && !this.isBorderBox()){
7647 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7657 adjustHeight : function(height){
7658 if(typeof height == "number"){
7659 if(this.autoBoxAdjust && !this.isBorderBox()){
7660 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7670 * Set the width of the element
7671 * @param {Number} width The new width
7672 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7673 * @return {Roo.Element} this
7675 setWidth : function(width, animate){
7676 width = this.adjustWidth(width);
7678 this.dom.style.width = this.addUnits(width);
7680 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7686 * Set the height of the element
7687 * @param {Number} height The new height
7688 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7689 * @return {Roo.Element} this
7691 setHeight : function(height, animate){
7692 height = this.adjustHeight(height);
7694 this.dom.style.height = this.addUnits(height);
7696 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7702 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7703 * @param {Number} width The new width
7704 * @param {Number} height The new height
7705 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7706 * @return {Roo.Element} this
7708 setSize : function(width, height, animate){
7709 if(typeof width == "object"){ // in case of object from getSize()
7710 height = width.height; width = width.width;
7712 width = this.adjustWidth(width); height = this.adjustHeight(height);
7714 this.dom.style.width = this.addUnits(width);
7715 this.dom.style.height = this.addUnits(height);
7717 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7723 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7724 * @param {Number} x X value for new position (coordinates are page-based)
7725 * @param {Number} y Y value for new position (coordinates are page-based)
7726 * @param {Number} width The new width
7727 * @param {Number} height The new height
7728 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7729 * @return {Roo.Element} this
7731 setBounds : function(x, y, width, height, animate){
7733 this.setSize(width, height);
7734 this.setLocation(x, y);
7736 width = this.adjustWidth(width); height = this.adjustHeight(height);
7737 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7738 this.preanim(arguments, 4), 'motion');
7744 * 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.
7745 * @param {Roo.lib.Region} region The region to fill
7746 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7747 * @return {Roo.Element} this
7749 setRegion : function(region, animate){
7750 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7755 * Appends an event handler
7757 * @param {String} eventName The type of event to append
7758 * @param {Function} fn The method the event invokes
7759 * @param {Object} scope (optional) The scope (this object) of the fn
7760 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7762 addListener : function(eventName, fn, scope, options){
7763 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7767 * Removes an event handler from this element
7768 * @param {String} eventName the type of event to remove
7769 * @param {Function} fn the method the event invokes
7770 * @return {Roo.Element} this
7772 removeListener : function(eventName, fn){
7773 Roo.EventManager.removeListener(this.dom, eventName, fn);
7778 * Removes all previous added listeners from this element
7779 * @return {Roo.Element} this
7781 removeAllListeners : function(){
7782 E.purgeElement(this.dom);
7786 relayEvent : function(eventName, observable){
7787 this.on(eventName, function(e){
7788 observable.fireEvent(eventName, e);
7793 * Set the opacity of the element
7794 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7795 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7796 * @return {Roo.Element} this
7798 setOpacity : function(opacity, animate){
7800 var s = this.dom.style;
7803 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7804 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7806 s.opacity = opacity;
7809 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7815 * Gets the left X coordinate
7816 * @param {Boolean} local True to get the local css position instead of page coordinate
7819 getLeft : function(local){
7823 return parseInt(this.getStyle("left"), 10) || 0;
7828 * Gets the right X coordinate of the element (element X position + element width)
7829 * @param {Boolean} local True to get the local css position instead of page coordinate
7832 getRight : function(local){
7834 return this.getX() + this.getWidth();
7836 return (this.getLeft(true) + this.getWidth()) || 0;
7841 * Gets the top Y coordinate
7842 * @param {Boolean} local True to get the local css position instead of page coordinate
7845 getTop : function(local) {
7849 return parseInt(this.getStyle("top"), 10) || 0;
7854 * Gets the bottom Y coordinate of the element (element Y position + element height)
7855 * @param {Boolean} local True to get the local css position instead of page coordinate
7858 getBottom : function(local){
7860 return this.getY() + this.getHeight();
7862 return (this.getTop(true) + this.getHeight()) || 0;
7867 * Initializes positioning on this element. If a desired position is not passed, it will make the
7868 * the element positioned relative IF it is not already positioned.
7869 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7870 * @param {Number} zIndex (optional) The zIndex to apply
7871 * @param {Number} x (optional) Set the page X position
7872 * @param {Number} y (optional) Set the page Y position
7874 position : function(pos, zIndex, x, y){
7876 if(this.getStyle('position') == 'static'){
7877 this.setStyle('position', 'relative');
7880 this.setStyle("position", pos);
7883 this.setStyle("z-index", zIndex);
7885 if(x !== undefined && y !== undefined){
7887 }else if(x !== undefined){
7889 }else if(y !== undefined){
7895 * Clear positioning back to the default when the document was loaded
7896 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7897 * @return {Roo.Element} this
7899 clearPositioning : function(value){
7907 "position" : "static"
7913 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7914 * snapshot before performing an update and then restoring the element.
7917 getPositioning : function(){
7918 var l = this.getStyle("left");
7919 var t = this.getStyle("top");
7921 "position" : this.getStyle("position"),
7923 "right" : l ? "" : this.getStyle("right"),
7925 "bottom" : t ? "" : this.getStyle("bottom"),
7926 "z-index" : this.getStyle("z-index")
7931 * Gets the width of the border(s) for the specified side(s)
7932 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7933 * passing lr would get the border (l)eft width + the border (r)ight width.
7934 * @return {Number} The width of the sides passed added together
7936 getBorderWidth : function(side){
7937 return this.addStyles(side, El.borders);
7941 * Gets the width of the padding(s) for the specified side(s)
7942 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7943 * passing lr would get the padding (l)eft + the padding (r)ight.
7944 * @return {Number} The padding of the sides passed added together
7946 getPadding : function(side){
7947 return this.addStyles(side, El.paddings);
7951 * Set positioning with an object returned by getPositioning().
7952 * @param {Object} posCfg
7953 * @return {Roo.Element} this
7955 setPositioning : function(pc){
7956 this.applyStyles(pc);
7957 if(pc.right == "auto"){
7958 this.dom.style.right = "";
7960 if(pc.bottom == "auto"){
7961 this.dom.style.bottom = "";
7967 fixDisplay : function(){
7968 if(this.getStyle("display") == "none"){
7969 this.setStyle("visibility", "hidden");
7970 this.setStyle("display", this.originalDisplay); // first try reverting to default
7971 if(this.getStyle("display") == "none"){ // if that fails, default to block
7972 this.setStyle("display", "block");
7978 * Quick set left and top adding default units
7979 * @param {String} left The left CSS property value
7980 * @param {String} top The top CSS property value
7981 * @return {Roo.Element} this
7983 setLeftTop : function(left, top){
7984 this.dom.style.left = this.addUnits(left);
7985 this.dom.style.top = this.addUnits(top);
7990 * Move this element relative to its current position.
7991 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
7992 * @param {Number} distance How far to move the element in pixels
7993 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7994 * @return {Roo.Element} this
7996 move : function(direction, distance, animate){
7997 var xy = this.getXY();
7998 direction = direction.toLowerCase();
8002 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8006 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8011 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8016 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8023 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8024 * @return {Roo.Element} this
8027 if(!this.isClipped){
8028 this.isClipped = true;
8029 this.originalClip = {
8030 "o": this.getStyle("overflow"),
8031 "x": this.getStyle("overflow-x"),
8032 "y": this.getStyle("overflow-y")
8034 this.setStyle("overflow", "hidden");
8035 this.setStyle("overflow-x", "hidden");
8036 this.setStyle("overflow-y", "hidden");
8042 * Return clipping (overflow) to original clipping before clip() was called
8043 * @return {Roo.Element} this
8045 unclip : function(){
8047 this.isClipped = false;
8048 var o = this.originalClip;
8049 if(o.o){this.setStyle("overflow", o.o);}
8050 if(o.x){this.setStyle("overflow-x", o.x);}
8051 if(o.y){this.setStyle("overflow-y", o.y);}
8058 * Gets the x,y coordinates specified by the anchor position on the element.
8059 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8060 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8061 * {width: (target width), height: (target height)} (defaults to the element's current size)
8062 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8063 * @return {Array} [x, y] An array containing the element's x and y coordinates
8065 getAnchorXY : function(anchor, local, s){
8066 //Passing a different size is useful for pre-calculating anchors,
8067 //especially for anchored animations that change the el size.
8069 var w, h, vp = false;
8072 if(d == document.body || d == document){
8074 w = D.getViewWidth(); h = D.getViewHeight();
8076 w = this.getWidth(); h = this.getHeight();
8079 w = s.width; h = s.height;
8081 var x = 0, y = 0, r = Math.round;
8082 switch((anchor || "tl").toLowerCase()){
8124 var sc = this.getScroll();
8125 return [x + sc.left, y + sc.top];
8127 //Add the element's offset xy
8128 var o = this.getXY();
8129 return [x+o[0], y+o[1]];
8133 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8134 * supported position values.
8135 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8136 * @param {String} position The position to align to.
8137 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8138 * @return {Array} [x, y]
8140 getAlignToXY : function(el, p, o){
8144 throw "Element.alignTo with an element that doesn't exist";
8146 var c = false; //constrain to viewport
8147 var p1 = "", p2 = "";
8154 }else if(p.indexOf("-") == -1){
8157 p = p.toLowerCase();
8158 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8160 throw "Element.alignTo with an invalid alignment " + p;
8162 p1 = m[1]; p2 = m[2]; c = !!m[3];
8164 //Subtract the aligned el's internal xy from the target's offset xy
8165 //plus custom offset to get the aligned el's new offset xy
8166 var a1 = this.getAnchorXY(p1, true);
8167 var a2 = el.getAnchorXY(p2, false);
8168 var x = a2[0] - a1[0] + o[0];
8169 var y = a2[1] - a1[1] + o[1];
8171 //constrain the aligned el to viewport if necessary
8172 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8173 // 5px of margin for ie
8174 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8176 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8177 //perpendicular to the vp border, allow the aligned el to slide on that border,
8178 //otherwise swap the aligned el to the opposite border of the target.
8179 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8180 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8181 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8182 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8185 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8186 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8188 if((x+w) > dw + scrollX){
8189 x = swapX ? r.left-w : dw+scrollX-w;
8192 x = swapX ? r.right : scrollX;
8194 if((y+h) > dh + scrollY){
8195 y = swapY ? r.top-h : dh+scrollY-h;
8198 y = swapY ? r.bottom : scrollY;
8205 getConstrainToXY : function(){
8206 var os = {top:0, left:0, bottom:0, right: 0};
8208 return function(el, local, offsets, proposedXY){
8210 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8212 var vw, vh, vx = 0, vy = 0;
8213 if(el.dom == document.body || el.dom == document){
8214 vw = Roo.lib.Dom.getViewWidth();
8215 vh = Roo.lib.Dom.getViewHeight();
8217 vw = el.dom.clientWidth;
8218 vh = el.dom.clientHeight;
8220 var vxy = el.getXY();
8226 var s = el.getScroll();
8228 vx += offsets.left + s.left;
8229 vy += offsets.top + s.top;
8231 vw -= offsets.right;
8232 vh -= offsets.bottom;
8237 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8238 var x = xy[0], y = xy[1];
8239 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8241 // only move it if it needs it
8244 // first validate right/bottom
8253 // then make sure top/left isn't negative
8262 return moved ? [x, y] : false;
8267 adjustForConstraints : function(xy, parent, offsets){
8268 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8272 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8273 * document it aligns it to the viewport.
8274 * The position parameter is optional, and can be specified in any one of the following formats:
8276 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8277 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8278 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8279 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8280 * <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
8281 * element's anchor point, and the second value is used as the target's anchor point.</li>
8283 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8284 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8285 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8286 * that specified in order to enforce the viewport constraints.
8287 * Following are all of the supported anchor positions:
8290 ----- -----------------------------
8291 tl The top left corner (default)
8292 t The center of the top edge
8293 tr The top right corner
8294 l The center of the left edge
8295 c In the center of the element
8296 r The center of the right edge
8297 bl The bottom left corner
8298 b The center of the bottom edge
8299 br The bottom right corner
8303 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8304 el.alignTo("other-el");
8306 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8307 el.alignTo("other-el", "tr?");
8309 // align the bottom right corner of el with the center left edge of other-el
8310 el.alignTo("other-el", "br-l?");
8312 // align the center of el with the bottom left corner of other-el and
8313 // adjust the x position by -6 pixels (and the y position by 0)
8314 el.alignTo("other-el", "c-bl", [-6, 0]);
8316 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8317 * @param {String} position The position to align to.
8318 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8319 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8320 * @return {Roo.Element} this
8322 alignTo : function(element, position, offsets, animate){
8323 var xy = this.getAlignToXY(element, position, offsets);
8324 this.setXY(xy, this.preanim(arguments, 3));
8329 * Anchors an element to another element and realigns it when the window is resized.
8330 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8331 * @param {String} position The position to align to.
8332 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8333 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8334 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8335 * is a number, it is used as the buffer delay (defaults to 50ms).
8336 * @param {Function} callback The function to call after the animation finishes
8337 * @return {Roo.Element} this
8339 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8340 var action = function(){
8341 this.alignTo(el, alignment, offsets, animate);
8342 Roo.callback(callback, this);
8344 Roo.EventManager.onWindowResize(action, this);
8345 var tm = typeof monitorScroll;
8346 if(tm != 'undefined'){
8347 Roo.EventManager.on(window, 'scroll', action, this,
8348 {buffer: tm == 'number' ? monitorScroll : 50});
8350 action.call(this); // align immediately
8354 * Clears any opacity settings from this element. Required in some cases for IE.
8355 * @return {Roo.Element} this
8357 clearOpacity : function(){
8358 if (window.ActiveXObject) {
8359 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8360 this.dom.style.filter = "";
8363 this.dom.style.opacity = "";
8364 this.dom.style["-moz-opacity"] = "";
8365 this.dom.style["-khtml-opacity"] = "";
8371 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8372 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8373 * @return {Roo.Element} this
8375 hide : function(animate){
8376 this.setVisible(false, this.preanim(arguments, 0));
8381 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8382 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8383 * @return {Roo.Element} this
8385 show : function(animate){
8386 this.setVisible(true, this.preanim(arguments, 0));
8391 * @private Test if size has a unit, otherwise appends the default
8393 addUnits : function(size){
8394 return Roo.Element.addUnits(size, this.defaultUnit);
8398 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8399 * @return {Roo.Element} this
8401 beginMeasure : function(){
8403 if(el.offsetWidth || el.offsetHeight){
8404 return this; // offsets work already
8407 var p = this.dom, b = document.body; // start with this element
8408 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8409 var pe = Roo.get(p);
8410 if(pe.getStyle('display') == 'none'){
8411 changed.push({el: p, visibility: pe.getStyle("visibility")});
8412 p.style.visibility = "hidden";
8413 p.style.display = "block";
8417 this._measureChanged = changed;
8423 * Restores displays to before beginMeasure was called
8424 * @return {Roo.Element} this
8426 endMeasure : function(){
8427 var changed = this._measureChanged;
8429 for(var i = 0, len = changed.length; i < len; i++) {
8431 r.el.style.visibility = r.visibility;
8432 r.el.style.display = "none";
8434 this._measureChanged = null;
8440 * Update the innerHTML of this element, optionally searching for and processing scripts
8441 * @param {String} html The new HTML
8442 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8443 * @param {Function} callback For async script loading you can be noticed when the update completes
8444 * @return {Roo.Element} this
8446 update : function(html, loadScripts, callback){
8447 if(typeof html == "undefined"){
8450 if(loadScripts !== true){
8451 this.dom.innerHTML = html;
8452 if(typeof callback == "function"){
8460 html += '<span id="' + id + '"></span>';
8462 E.onAvailable(id, function(){
8463 var hd = document.getElementsByTagName("head")[0];
8464 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8465 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8466 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8469 while(match = re.exec(html)){
8470 var attrs = match[1];
8471 var srcMatch = attrs ? attrs.match(srcRe) : false;
8472 if(srcMatch && srcMatch[2]){
8473 var s = document.createElement("script");
8474 s.src = srcMatch[2];
8475 var typeMatch = attrs.match(typeRe);
8476 if(typeMatch && typeMatch[2]){
8477 s.type = typeMatch[2];
8480 }else if(match[2] && match[2].length > 0){
8481 if(window.execScript) {
8482 window.execScript(match[2]);
8490 window.eval(match[2]);
8494 var el = document.getElementById(id);
8495 if(el){el.parentNode.removeChild(el);}
8496 if(typeof callback == "function"){
8500 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8505 * Direct access to the UpdateManager update() method (takes the same parameters).
8506 * @param {String/Function} url The url for this request or a function to call to get the url
8507 * @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}
8508 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8509 * @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.
8510 * @return {Roo.Element} this
8513 var um = this.getUpdateManager();
8514 um.update.apply(um, arguments);
8519 * Gets this element's UpdateManager
8520 * @return {Roo.UpdateManager} The UpdateManager
8522 getUpdateManager : function(){
8523 if(!this.updateManager){
8524 this.updateManager = new Roo.UpdateManager(this);
8526 return this.updateManager;
8530 * Disables text selection for this element (normalized across browsers)
8531 * @return {Roo.Element} this
8533 unselectable : function(){
8534 this.dom.unselectable = "on";
8535 this.swallowEvent("selectstart", true);
8536 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8537 this.addClass("x-unselectable");
8542 * Calculates the x, y to center this element on the screen
8543 * @return {Array} The x, y values [x, y]
8545 getCenterXY : function(){
8546 return this.getAlignToXY(document, 'c-c');
8550 * Centers the Element in either the viewport, or another Element.
8551 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8553 center : function(centerIn){
8554 this.alignTo(centerIn || document, 'c-c');
8559 * Tests various css rules/browsers to determine if this element uses a border box
8562 isBorderBox : function(){
8563 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8567 * Return a box {x, y, width, height} that can be used to set another elements
8568 * size/location to match this element.
8569 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8570 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8571 * @return {Object} box An object in the format {x, y, width, height}
8573 getBox : function(contentBox, local){
8578 var left = parseInt(this.getStyle("left"), 10) || 0;
8579 var top = parseInt(this.getStyle("top"), 10) || 0;
8582 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8584 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8586 var l = this.getBorderWidth("l")+this.getPadding("l");
8587 var r = this.getBorderWidth("r")+this.getPadding("r");
8588 var t = this.getBorderWidth("t")+this.getPadding("t");
8589 var b = this.getBorderWidth("b")+this.getPadding("b");
8590 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)};
8592 bx.right = bx.x + bx.width;
8593 bx.bottom = bx.y + bx.height;
8598 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8599 for more information about the sides.
8600 * @param {String} sides
8603 getFrameWidth : function(sides, onlyContentBox){
8604 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8608 * 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.
8609 * @param {Object} box The box to fill {x, y, width, height}
8610 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8611 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8612 * @return {Roo.Element} this
8614 setBox : function(box, adjust, animate){
8615 var w = box.width, h = box.height;
8616 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8617 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8618 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8620 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8625 * Forces the browser to repaint this element
8626 * @return {Roo.Element} this
8628 repaint : function(){
8630 this.addClass("x-repaint");
8631 setTimeout(function(){
8632 Roo.get(dom).removeClass("x-repaint");
8638 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8639 * then it returns the calculated width of the sides (see getPadding)
8640 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8641 * @return {Object/Number}
8643 getMargins : function(side){
8646 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8647 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8648 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8649 right: parseInt(this.getStyle("margin-right"), 10) || 0
8652 return this.addStyles(side, El.margins);
8657 addStyles : function(sides, styles){
8659 for(var i = 0, len = sides.length; i < len; i++){
8660 v = this.getStyle(styles[sides.charAt(i)]);
8662 w = parseInt(v, 10);
8670 * Creates a proxy element of this element
8671 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8672 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8673 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8674 * @return {Roo.Element} The new proxy element
8676 createProxy : function(config, renderTo, matchBox){
8678 renderTo = Roo.getDom(renderTo);
8680 renderTo = document.body;
8682 config = typeof config == "object" ?
8683 config : {tag : "div", cls: config};
8684 var proxy = Roo.DomHelper.append(renderTo, config, true);
8686 proxy.setBox(this.getBox());
8692 * Puts a mask over this element to disable user interaction. Requires core.css.
8693 * This method can only be applied to elements which accept child nodes.
8694 * @param {String} msg (optional) A message to display in the mask
8695 * @param {String} msgCls (optional) A css class to apply to the msg element
8696 * @return {Element} The mask element
8698 mask : function(msg, msgCls){
8699 if(this.getStyle("position") == "static"){
8700 this.setStyle("position", "relative");
8703 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8705 this.addClass("x-masked");
8706 this._mask.setDisplayed(true);
8707 if(typeof msg == 'string'){
8709 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8711 var mm = this._maskMsg;
8712 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8713 mm.dom.firstChild.innerHTML = msg;
8714 mm.setDisplayed(true);
8717 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8718 this._mask.setHeight(this.getHeight());
8724 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8725 * it is cached for reuse.
8727 unmask : function(removeEl){
8729 if(removeEl === true){
8730 this._mask.remove();
8733 this._maskMsg.remove();
8734 delete this._maskMsg;
8737 this._mask.setDisplayed(false);
8739 this._maskMsg.setDisplayed(false);
8743 this.removeClass("x-masked");
8747 * Returns true if this element is masked
8750 isMasked : function(){
8751 return this._mask && this._mask.isVisible();
8755 * Creates an iframe shim for this element to keep selects and other windowed objects from
8757 * @return {Roo.Element} The new shim element
8759 createShim : function(){
8760 var el = document.createElement('iframe');
8761 el.frameBorder = 'no';
8762 el.className = 'roo-shim';
8763 if(Roo.isIE && Roo.isSecure){
8764 el.src = Roo.SSL_SECURE_URL;
8766 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8767 shim.autoBoxAdjust = false;
8772 * Removes this element from the DOM and deletes it from the cache
8774 remove : function(){
8775 if(this.dom.parentNode){
8776 this.dom.parentNode.removeChild(this.dom);
8778 delete El.cache[this.dom.id];
8782 * Sets up event handlers to add and remove a css class when the mouse is over this element
8783 * @param {String} className
8784 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8785 * mouseout events for children elements
8786 * @return {Roo.Element} this
8788 addClassOnOver : function(className, preventFlicker){
8789 this.on("mouseover", function(){
8790 Roo.fly(this, '_internal').addClass(className);
8792 var removeFn = function(e){
8793 if(preventFlicker !== true || !e.within(this, true)){
8794 Roo.fly(this, '_internal').removeClass(className);
8797 this.on("mouseout", removeFn, this.dom);
8802 * Sets up event handlers to add and remove a css class when this element has the focus
8803 * @param {String} className
8804 * @return {Roo.Element} this
8806 addClassOnFocus : function(className){
8807 this.on("focus", function(){
8808 Roo.fly(this, '_internal').addClass(className);
8810 this.on("blur", function(){
8811 Roo.fly(this, '_internal').removeClass(className);
8816 * 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)
8817 * @param {String} className
8818 * @return {Roo.Element} this
8820 addClassOnClick : function(className){
8822 this.on("mousedown", function(){
8823 Roo.fly(dom, '_internal').addClass(className);
8824 var d = Roo.get(document);
8825 var fn = function(){
8826 Roo.fly(dom, '_internal').removeClass(className);
8827 d.removeListener("mouseup", fn);
8829 d.on("mouseup", fn);
8835 * Stops the specified event from bubbling and optionally prevents the default action
8836 * @param {String} eventName
8837 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8838 * @return {Roo.Element} this
8840 swallowEvent : function(eventName, preventDefault){
8841 var fn = function(e){
8842 e.stopPropagation();
8847 if(eventName instanceof Array){
8848 for(var i = 0, len = eventName.length; i < len; i++){
8849 this.on(eventName[i], fn);
8853 this.on(eventName, fn);
8860 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8863 * Sizes this element to its parent element's dimensions performing
8864 * neccessary box adjustments.
8865 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8866 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8867 * @return {Roo.Element} this
8869 fitToParent : function(monitorResize, targetParent) {
8870 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8871 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8872 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8875 var p = Roo.get(targetParent || this.dom.parentNode);
8876 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8877 if (monitorResize === true) {
8878 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8879 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8885 * Gets the next sibling, skipping text nodes
8886 * @return {HTMLElement} The next sibling or null
8888 getNextSibling : function(){
8889 var n = this.dom.nextSibling;
8890 while(n && n.nodeType != 1){
8897 * Gets the previous sibling, skipping text nodes
8898 * @return {HTMLElement} The previous sibling or null
8900 getPrevSibling : function(){
8901 var n = this.dom.previousSibling;
8902 while(n && n.nodeType != 1){
8903 n = n.previousSibling;
8910 * Appends the passed element(s) to this element
8911 * @param {String/HTMLElement/Array/Element/CompositeElement} el
8912 * @return {Roo.Element} this
8914 appendChild: function(el){
8921 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8922 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
8923 * automatically generated with the specified attributes.
8924 * @param {HTMLElement} insertBefore (optional) a child element of this element
8925 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8926 * @return {Roo.Element} The new child element
8928 createChild: function(config, insertBefore, returnDom){
8929 config = config || {tag:'div'};
8931 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8933 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
8937 * Appends this element to the passed element
8938 * @param {String/HTMLElement/Element} el The new parent element
8939 * @return {Roo.Element} this
8941 appendTo: function(el){
8942 el = Roo.getDom(el);
8943 el.appendChild(this.dom);
8948 * Inserts this element before the passed element in the DOM
8949 * @param {String/HTMLElement/Element} el The element to insert before
8950 * @return {Roo.Element} this
8952 insertBefore: function(el){
8953 el = Roo.getDom(el);
8954 el.parentNode.insertBefore(this.dom, el);
8959 * Inserts this element after the passed element in the DOM
8960 * @param {String/HTMLElement/Element} el The element to insert after
8961 * @return {Roo.Element} this
8963 insertAfter: function(el){
8964 el = Roo.getDom(el);
8965 el.parentNode.insertBefore(this.dom, el.nextSibling);
8970 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8971 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8972 * @return {Roo.Element} The new child
8974 insertFirst: function(el, returnDom){
8976 if(typeof el == 'object' && !el.nodeType){ // dh config
8977 return this.createChild(el, this.dom.firstChild, returnDom);
8979 el = Roo.getDom(el);
8980 this.dom.insertBefore(el, this.dom.firstChild);
8981 return !returnDom ? Roo.get(el) : el;
8986 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
8987 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8988 * @param {String} where (optional) 'before' or 'after' defaults to before
8989 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8990 * @return {Roo.Element} the inserted Element
8992 insertSibling: function(el, where, returnDom){
8993 where = where ? where.toLowerCase() : 'before';
8995 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
8997 if(typeof el == 'object' && !el.nodeType){ // dh config
8998 if(where == 'after' && !this.dom.nextSibling){
8999 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9001 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9005 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9006 where == 'before' ? this.dom : this.dom.nextSibling);
9015 * Creates and wraps this element with another element
9016 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9017 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9018 * @return {HTMLElement/Element} The newly created wrapper element
9020 wrap: function(config, returnDom){
9022 config = {tag: "div"};
9024 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9025 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9030 * Replaces the passed element with this element
9031 * @param {String/HTMLElement/Element} el The element to replace
9032 * @return {Roo.Element} this
9034 replace: function(el){
9036 this.insertBefore(el);
9042 * Inserts an html fragment into this element
9043 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9044 * @param {String} html The HTML fragment
9045 * @param {Boolean} returnEl True to return an Roo.Element
9046 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9048 insertHtml : function(where, html, returnEl){
9049 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9050 return returnEl ? Roo.get(el) : el;
9054 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9055 * @param {Object} o The object with the attributes
9056 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9057 * @return {Roo.Element} this
9059 set : function(o, useSet){
9061 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9063 if(attr == "style" || typeof o[attr] == "function") continue;
9065 el.className = o["cls"];
9067 if(useSet) el.setAttribute(attr, o[attr]);
9068 else el[attr] = o[attr];
9072 Roo.DomHelper.applyStyles(el, o.style);
9078 * Convenience method for constructing a KeyMap
9079 * @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:
9080 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9081 * @param {Function} fn The function to call
9082 * @param {Object} scope (optional) The scope of the function
9083 * @return {Roo.KeyMap} The KeyMap created
9085 addKeyListener : function(key, fn, scope){
9087 if(typeof key != "object" || key instanceof Array){
9103 return new Roo.KeyMap(this, config);
9107 * Creates a KeyMap for this element
9108 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9109 * @return {Roo.KeyMap} The KeyMap created
9111 addKeyMap : function(config){
9112 return new Roo.KeyMap(this, config);
9116 * Returns true if this element is scrollable.
9119 isScrollable : function(){
9121 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9125 * 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().
9126 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9127 * @param {Number} value The new scroll value
9128 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9129 * @return {Element} this
9132 scrollTo : function(side, value, animate){
9133 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9135 this.dom[prop] = value;
9137 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9138 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9144 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9145 * within this element's scrollable range.
9146 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9147 * @param {Number} distance How far to scroll the element in pixels
9148 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9149 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9150 * was scrolled as far as it could go.
9152 scroll : function(direction, distance, animate){
9153 if(!this.isScrollable()){
9157 var l = el.scrollLeft, t = el.scrollTop;
9158 var w = el.scrollWidth, h = el.scrollHeight;
9159 var cw = el.clientWidth, ch = el.clientHeight;
9160 direction = direction.toLowerCase();
9161 var scrolled = false;
9162 var a = this.preanim(arguments, 2);
9167 var v = Math.min(l + distance, w-cw);
9168 this.scrollTo("left", v, a);
9175 var v = Math.max(l - distance, 0);
9176 this.scrollTo("left", v, a);
9184 var v = Math.max(t - distance, 0);
9185 this.scrollTo("top", v, a);
9193 var v = Math.min(t + distance, h-ch);
9194 this.scrollTo("top", v, a);
9203 * Translates the passed page coordinates into left/top css values for this element
9204 * @param {Number/Array} x The page x or an array containing [x, y]
9205 * @param {Number} y The page y
9206 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9208 translatePoints : function(x, y){
9209 if(typeof x == 'object' || x instanceof Array){
9212 var p = this.getStyle('position');
9213 var o = this.getXY();
9215 var l = parseInt(this.getStyle('left'), 10);
9216 var t = parseInt(this.getStyle('top'), 10);
9219 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9222 t = (p == "relative") ? 0 : this.dom.offsetTop;
9225 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9229 * Returns the current scroll position of the element.
9230 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9232 getScroll : function(){
9233 var d = this.dom, doc = document;
9234 if(d == doc || d == doc.body){
9235 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9236 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9237 return {left: l, top: t};
9239 return {left: d.scrollLeft, top: d.scrollTop};
9244 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9245 * are convert to standard 6 digit hex color.
9246 * @param {String} attr The css attribute
9247 * @param {String} defaultValue The default value to use when a valid color isn't found
9248 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9251 getColor : function(attr, defaultValue, prefix){
9252 var v = this.getStyle(attr);
9253 if(!v || v == "transparent" || v == "inherit") {
9254 return defaultValue;
9256 var color = typeof prefix == "undefined" ? "#" : prefix;
9257 if(v.substr(0, 4) == "rgb("){
9258 var rvs = v.slice(4, v.length -1).split(",");
9259 for(var i = 0; i < 3; i++){
9260 var h = parseInt(rvs[i]).toString(16);
9267 if(v.substr(0, 1) == "#"){
9269 for(var i = 1; i < 4; i++){
9270 var c = v.charAt(i);
9273 }else if(v.length == 7){
9274 color += v.substr(1);
9278 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9282 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9283 * gradient background, rounded corners and a 4-way shadow.
9284 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9285 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9286 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9287 * @return {Roo.Element} this
9289 boxWrap : function(cls){
9290 cls = cls || 'x-box';
9291 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9292 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9297 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9298 * @param {String} namespace The namespace in which to look for the attribute
9299 * @param {String} name The attribute name
9300 * @return {String} The attribute value
9302 getAttributeNS : Roo.isIE ? function(ns, name){
9304 var type = typeof d[ns+":"+name];
9305 if(type != 'undefined' && type != 'unknown'){
9306 return d[ns+":"+name];
9309 } : function(ns, name){
9311 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9315 var ep = El.prototype;
9318 * Appends an event handler (Shorthand for addListener)
9319 * @param {String} eventName The type of event to append
9320 * @param {Function} fn The method the event invokes
9321 * @param {Object} scope (optional) The scope (this object) of the fn
9322 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9325 ep.on = ep.addListener;
9327 ep.mon = ep.addListener;
9330 * Removes an event handler from this element (shorthand for removeListener)
9331 * @param {String} eventName the type of event to remove
9332 * @param {Function} fn the method the event invokes
9333 * @return {Roo.Element} this
9336 ep.un = ep.removeListener;
9339 * true to automatically adjust width and height settings for box-model issues (default to true)
9341 ep.autoBoxAdjust = true;
9344 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9347 El.addUnits = function(v, defaultUnit){
9348 if(v === "" || v == "auto"){
9351 if(v === undefined){
9354 if(typeof v == "number" || !El.unitPattern.test(v)){
9355 return v + (defaultUnit || 'px');
9360 // special markup used throughout Roo when box wrapping elements
9361 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>';
9363 * Visibility mode constant - Use visibility to hide element
9369 * Visibility mode constant - Use display to hide element
9375 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9376 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9377 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9389 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9390 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9391 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9392 * @return {Element} The Element object
9395 El.get = function(el){
9397 if(!el){ return null; }
9398 if(typeof el == "string"){ // element id
9399 if(!(elm = document.getElementById(el))){
9402 if(ex = El.cache[el]){
9405 ex = El.cache[el] = new El(elm);
9408 }else if(el.tagName){ // dom element
9412 if(ex = El.cache[id]){
9415 ex = El.cache[id] = new El(el);
9418 }else if(el instanceof El){
9420 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9421 // catch case where it hasn't been appended
9422 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9425 }else if(el.isComposite){
9427 }else if(el instanceof Array){
9428 return El.select(el);
9429 }else if(el == document){
9430 // create a bogus element object representing the document object
9432 var f = function(){};
9433 f.prototype = El.prototype;
9435 docEl.dom = document;
9443 El.uncache = function(el){
9444 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9446 delete El.cache[a[i].id || a[i]];
9452 // Garbage collection - uncache elements/purge listeners on orphaned elements
9453 // so we don't hold a reference and cause the browser to retain them
9454 El.garbageCollect = function(){
9455 if(!Roo.enableGarbageCollector){
9456 clearInterval(El.collectorThread);
9459 for(var eid in El.cache){
9460 var el = El.cache[eid], d = el.dom;
9461 // -------------------------------------------------------
9462 // Determining what is garbage:
9463 // -------------------------------------------------------
9465 // dom node is null, definitely garbage
9466 // -------------------------------------------------------
9468 // no parentNode == direct orphan, definitely garbage
9469 // -------------------------------------------------------
9470 // !d.offsetParent && !document.getElementById(eid)
9471 // display none elements have no offsetParent so we will
9472 // also try to look it up by it's id. However, check
9473 // offsetParent first so we don't do unneeded lookups.
9474 // This enables collection of elements that are not orphans
9475 // directly, but somewhere up the line they have an orphan
9477 // -------------------------------------------------------
9478 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9479 delete El.cache[eid];
9480 if(d && Roo.enableListenerCollection){
9486 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9490 El.Flyweight = function(dom){
9493 El.Flyweight.prototype = El.prototype;
9495 El._flyweights = {};
9497 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9498 * the dom node can be overwritten by other code.
9499 * @param {String/HTMLElement} el The dom node or id
9500 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9501 * prevent conflicts (e.g. internally Roo uses "_internal")
9503 * @return {Element} The shared Element object
9505 El.fly = function(el, named){
9506 named = named || '_global';
9507 el = Roo.getDom(el);
9511 if(!El._flyweights[named]){
9512 El._flyweights[named] = new El.Flyweight();
9514 El._flyweights[named].dom = el;
9515 return El._flyweights[named];
9519 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9520 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9521 * Shorthand of {@link Roo.Element#get}
9522 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9523 * @return {Element} The Element object
9529 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9530 * the dom node can be overwritten by other code.
9531 * Shorthand of {@link Roo.Element#fly}
9532 * @param {String/HTMLElement} el The dom node or id
9533 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9534 * prevent conflicts (e.g. internally Roo uses "_internal")
9536 * @return {Element} The shared Element object
9542 // speedy lookup for elements never to box adjust
9543 var noBoxAdjust = Roo.isStrict ? {
9546 input:1, select:1, textarea:1
9548 if(Roo.isIE || Roo.isGecko){
9549 noBoxAdjust['button'] = 1;
9553 Roo.EventManager.on(window, 'unload', function(){
9555 delete El._flyweights;
9563 Roo.Element.selectorFunction = Roo.DomQuery.select;
9566 Roo.Element.select = function(selector, unique, root){
9568 if(typeof selector == "string"){
9569 els = Roo.Element.selectorFunction(selector, root);
9570 }else if(selector.length !== undefined){
9573 throw "Invalid selector";
9575 if(unique === true){
9576 return new Roo.CompositeElement(els);
9578 return new Roo.CompositeElementLite(els);
9582 * Selects elements based on the passed CSS selector to enable working on them as 1.
9583 * @param {String/Array} selector The CSS selector or an array of elements
9584 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9585 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9586 * @return {CompositeElementLite/CompositeElement}
9590 Roo.select = Roo.Element.select;
9607 * Ext JS Library 1.1.1
9608 * Copyright(c) 2006-2007, Ext JS, LLC.
9610 * Originally Released Under LGPL - original licence link has changed is not relivant.
9613 * <script type="text/javascript">
9618 //Notifies Element that fx methods are available
9619 Roo.enableFx = true;
9623 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9624 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9625 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9626 * Element effects to work.</p><br/>
9628 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9629 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9630 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9631 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9632 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9633 * expected results and should be done with care.</p><br/>
9635 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9636 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9639 ----- -----------------------------
9640 tl The top left corner
9641 t The center of the top edge
9642 tr The top right corner
9643 l The center of the left edge
9644 r The center of the right edge
9645 bl The bottom left corner
9646 b The center of the bottom edge
9647 br The bottom right corner
9649 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9650 * below are common options that can be passed to any Fx method.</b>
9651 * @cfg {Function} callback A function called when the effect is finished
9652 * @cfg {Object} scope The scope of the effect function
9653 * @cfg {String} easing A valid Easing value for the effect
9654 * @cfg {String} afterCls A css class to apply after the effect
9655 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9656 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9657 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9658 * effects that end with the element being visually hidden, ignored otherwise)
9659 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9660 * a function which returns such a specification that will be applied to the Element after the effect finishes
9661 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9662 * @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
9663 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9667 * Slides the element into view. An anchor point can be optionally passed to set the point of
9668 * origin for the slide effect. This function automatically handles wrapping the element with
9669 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9672 // default: slide the element in from the top
9675 // custom: slide the element in from the right with a 2-second duration
9676 el.slideIn('r', { duration: 2 });
9678 // common config options shown with default values
9684 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9685 * @param {Object} options (optional) Object literal with any of the Fx config options
9686 * @return {Roo.Element} The Element
9688 slideIn : function(anchor, o){
9689 var el = this.getFxEl();
9692 el.queueFx(o, function(){
9694 anchor = anchor || "t";
9696 // fix display to visibility
9699 // restore values after effect
9700 var r = this.getFxRestore();
9701 var b = this.getBox();
9702 // fixed size for slide
9706 var wrap = this.fxWrap(r.pos, o, "hidden");
9708 var st = this.dom.style;
9709 st.visibility = "visible";
9710 st.position = "absolute";
9712 // clear out temp styles after slide and unwrap
9713 var after = function(){
9714 el.fxUnwrap(wrap, r.pos, o);
9716 st.height = r.height;
9719 // time to calc the positions
9720 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9722 switch(anchor.toLowerCase()){
9724 wrap.setSize(b.width, 0);
9725 st.left = st.bottom = "0";
9729 wrap.setSize(0, b.height);
9730 st.right = st.top = "0";
9734 wrap.setSize(0, b.height);
9736 st.left = st.top = "0";
9737 a = {width: bw, points: pt};
9740 wrap.setSize(b.width, 0);
9741 wrap.setY(b.bottom);
9742 st.left = st.top = "0";
9743 a = {height: bh, points: pt};
9747 st.right = st.bottom = "0";
9748 a = {width: bw, height: bh};
9752 wrap.setY(b.y+b.height);
9753 st.right = st.top = "0";
9754 a = {width: bw, height: bh, points: pt};
9758 wrap.setXY([b.right, b.bottom]);
9759 st.left = st.top = "0";
9760 a = {width: bw, height: bh, points: pt};
9764 wrap.setX(b.x+b.width);
9765 st.left = st.bottom = "0";
9766 a = {width: bw, height: bh, points: pt};
9769 this.dom.style.visibility = "visible";
9772 arguments.callee.anim = wrap.fxanim(a,
9782 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9783 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9784 * 'hidden') but block elements will still take up space in the document. The element must be removed
9785 * from the DOM using the 'remove' config option if desired. This function automatically handles
9786 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9789 // default: slide the element out to the top
9792 // custom: slide the element out to the right with a 2-second duration
9793 el.slideOut('r', { duration: 2 });
9795 // common config options shown with default values
9803 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9804 * @param {Object} options (optional) Object literal with any of the Fx config options
9805 * @return {Roo.Element} The Element
9807 slideOut : function(anchor, o){
9808 var el = this.getFxEl();
9811 el.queueFx(o, function(){
9813 anchor = anchor || "t";
9815 // restore values after effect
9816 var r = this.getFxRestore();
9818 var b = this.getBox();
9819 // fixed size for slide
9823 var wrap = this.fxWrap(r.pos, o, "visible");
9825 var st = this.dom.style;
9826 st.visibility = "visible";
9827 st.position = "absolute";
9831 var after = function(){
9833 el.setDisplayed(false);
9838 el.fxUnwrap(wrap, r.pos, o);
9841 st.height = r.height;
9846 var a, zero = {to: 0};
9847 switch(anchor.toLowerCase()){
9849 st.left = st.bottom = "0";
9853 st.right = st.top = "0";
9857 st.left = st.top = "0";
9858 a = {width: zero, points: {to:[b.right, b.y]}};
9861 st.left = st.top = "0";
9862 a = {height: zero, points: {to:[b.x, b.bottom]}};
9865 st.right = st.bottom = "0";
9866 a = {width: zero, height: zero};
9869 st.right = st.top = "0";
9870 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9873 st.left = st.top = "0";
9874 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9877 st.left = st.bottom = "0";
9878 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9882 arguments.callee.anim = wrap.fxanim(a,
9892 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
9893 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
9894 * The element must be removed from the DOM using the 'remove' config option if desired.
9900 // common config options shown with default values
9908 * @param {Object} options (optional) Object literal with any of the Fx config options
9909 * @return {Roo.Element} The Element
9912 var el = this.getFxEl();
9915 el.queueFx(o, function(){
9916 this.clearOpacity();
9919 // restore values after effect
9920 var r = this.getFxRestore();
9921 var st = this.dom.style;
9923 var after = function(){
9925 el.setDisplayed(false);
9932 el.setPositioning(r.pos);
9934 st.height = r.height;
9939 var width = this.getWidth();
9940 var height = this.getHeight();
9942 arguments.callee.anim = this.fxanim({
9943 width : {to: this.adjustWidth(width * 2)},
9944 height : {to: this.adjustHeight(height * 2)},
9945 points : {by: [-(width * .5), -(height * .5)]},
9947 fontSize: {to:200, unit: "%"}
9958 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9959 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
9960 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9966 // all config options shown with default values
9974 * @param {Object} options (optional) Object literal with any of the Fx config options
9975 * @return {Roo.Element} The Element
9977 switchOff : function(o){
9978 var el = this.getFxEl();
9981 el.queueFx(o, function(){
9982 this.clearOpacity();
9985 // restore values after effect
9986 var r = this.getFxRestore();
9987 var st = this.dom.style;
9989 var after = function(){
9991 el.setDisplayed(false);
9997 el.setPositioning(r.pos);
9999 st.height = r.height;
10004 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10005 this.clearOpacity();
10009 points:{by:[0, this.getHeight() * .5]}
10010 }, o, 'motion', 0.3, 'easeIn', after);
10011 }).defer(100, this);
10018 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10019 * changed using the "attr" config option) and then fading back to the original color. If no original
10020 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10023 // default: highlight background to yellow
10026 // custom: highlight foreground text to blue for 2 seconds
10027 el.highlight("0000ff", { attr: 'color', duration: 2 });
10029 // common config options shown with default values
10030 el.highlight("ffff9c", {
10031 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10032 endColor: (current color) or "ffffff",
10037 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10038 * @param {Object} options (optional) Object literal with any of the Fx config options
10039 * @return {Roo.Element} The Element
10041 highlight : function(color, o){
10042 var el = this.getFxEl();
10045 el.queueFx(o, function(){
10046 color = color || "ffff9c";
10047 attr = o.attr || "backgroundColor";
10049 this.clearOpacity();
10052 var origColor = this.getColor(attr);
10053 var restoreColor = this.dom.style[attr];
10054 endColor = (o.endColor || origColor) || "ffffff";
10056 var after = function(){
10057 el.dom.style[attr] = restoreColor;
10062 a[attr] = {from: color, to: endColor};
10063 arguments.callee.anim = this.fxanim(a,
10073 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10076 // default: a single light blue ripple
10079 // custom: 3 red ripples lasting 3 seconds total
10080 el.frame("ff0000", 3, { duration: 3 });
10082 // common config options shown with default values
10083 el.frame("C3DAF9", 1, {
10084 duration: 1 //duration of entire animation (not each individual ripple)
10085 // Note: Easing is not configurable and will be ignored if included
10088 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10089 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10090 * @param {Object} options (optional) Object literal with any of the Fx config options
10091 * @return {Roo.Element} The Element
10093 frame : function(color, count, o){
10094 var el = this.getFxEl();
10097 el.queueFx(o, function(){
10098 color = color || "#C3DAF9";
10099 if(color.length == 6){
10100 color = "#" + color;
10102 count = count || 1;
10103 duration = o.duration || 1;
10106 var b = this.getBox();
10107 var animFn = function(){
10108 var proxy = this.createProxy({
10111 visbility:"hidden",
10112 position:"absolute",
10113 "z-index":"35000", // yee haw
10114 border:"0px solid " + color
10117 var scale = Roo.isBorderBox ? 2 : 1;
10119 top:{from:b.y, to:b.y - 20},
10120 left:{from:b.x, to:b.x - 20},
10121 borderWidth:{from:0, to:10},
10122 opacity:{from:1, to:0},
10123 height:{from:b.height, to:(b.height + (20*scale))},
10124 width:{from:b.width, to:(b.width + (20*scale))}
10125 }, duration, function(){
10129 animFn.defer((duration/2)*1000, this);
10140 * Creates a pause before any subsequent queued effects begin. If there are
10141 * no effects queued after the pause it will have no effect.
10146 * @param {Number} seconds The length of time to pause (in seconds)
10147 * @return {Roo.Element} The Element
10149 pause : function(seconds){
10150 var el = this.getFxEl();
10153 el.queueFx(o, function(){
10154 setTimeout(function(){
10156 }, seconds * 1000);
10162 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10163 * using the "endOpacity" config option.
10166 // default: fade in from opacity 0 to 100%
10169 // custom: fade in from opacity 0 to 75% over 2 seconds
10170 el.fadeIn({ endOpacity: .75, duration: 2});
10172 // common config options shown with default values
10174 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10179 * @param {Object} options (optional) Object literal with any of the Fx config options
10180 * @return {Roo.Element} The Element
10182 fadeIn : function(o){
10183 var el = this.getFxEl();
10185 el.queueFx(o, function(){
10186 this.setOpacity(0);
10188 this.dom.style.visibility = 'visible';
10189 var to = o.endOpacity || 1;
10190 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10191 o, null, .5, "easeOut", function(){
10193 this.clearOpacity();
10202 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10203 * using the "endOpacity" config option.
10206 // default: fade out from the element's current opacity to 0
10209 // custom: fade out from the element's current opacity to 25% over 2 seconds
10210 el.fadeOut({ endOpacity: .25, duration: 2});
10212 // common config options shown with default values
10214 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10221 * @param {Object} options (optional) Object literal with any of the Fx config options
10222 * @return {Roo.Element} The Element
10224 fadeOut : function(o){
10225 var el = this.getFxEl();
10227 el.queueFx(o, function(){
10228 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10229 o, null, .5, "easeOut", function(){
10230 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10231 this.dom.style.display = "none";
10233 this.dom.style.visibility = "hidden";
10235 this.clearOpacity();
10243 * Animates the transition of an element's dimensions from a starting height/width
10244 * to an ending height/width.
10247 // change height and width to 100x100 pixels
10248 el.scale(100, 100);
10250 // common config options shown with default values. The height and width will default to
10251 // the element's existing values if passed as null.
10254 [element's height], {
10259 * @param {Number} width The new width (pass undefined to keep the original width)
10260 * @param {Number} height The new height (pass undefined to keep the original height)
10261 * @param {Object} options (optional) Object literal with any of the Fx config options
10262 * @return {Roo.Element} The Element
10264 scale : function(w, h, o){
10265 this.shift(Roo.apply({}, o, {
10273 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10274 * Any of these properties not specified in the config object will not be changed. This effect
10275 * requires that at least one new dimension, position or opacity setting must be passed in on
10276 * the config object in order for the function to have any effect.
10279 // slide the element horizontally to x position 200 while changing the height and opacity
10280 el.shift({ x: 200, height: 50, opacity: .8 });
10282 // common config options shown with default values.
10284 width: [element's width],
10285 height: [element's height],
10286 x: [element's x position],
10287 y: [element's y position],
10288 opacity: [element's opacity],
10293 * @param {Object} options Object literal with any of the Fx config options
10294 * @return {Roo.Element} The Element
10296 shift : function(o){
10297 var el = this.getFxEl();
10299 el.queueFx(o, function(){
10300 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10301 if(w !== undefined){
10302 a.width = {to: this.adjustWidth(w)};
10304 if(h !== undefined){
10305 a.height = {to: this.adjustHeight(h)};
10307 if(x !== undefined || y !== undefined){
10309 x !== undefined ? x : this.getX(),
10310 y !== undefined ? y : this.getY()
10313 if(op !== undefined){
10314 a.opacity = {to: op};
10316 if(o.xy !== undefined){
10317 a.points = {to: o.xy};
10319 arguments.callee.anim = this.fxanim(a,
10320 o, 'motion', .35, "easeOut", function(){
10328 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10329 * ending point of the effect.
10332 // default: slide the element downward while fading out
10335 // custom: slide the element out to the right with a 2-second duration
10336 el.ghost('r', { duration: 2 });
10338 // common config options shown with default values
10346 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10347 * @param {Object} options (optional) Object literal with any of the Fx config options
10348 * @return {Roo.Element} The Element
10350 ghost : function(anchor, o){
10351 var el = this.getFxEl();
10354 el.queueFx(o, function(){
10355 anchor = anchor || "b";
10357 // restore values after effect
10358 var r = this.getFxRestore();
10359 var w = this.getWidth(),
10360 h = this.getHeight();
10362 var st = this.dom.style;
10364 var after = function(){
10366 el.setDisplayed(false);
10372 el.setPositioning(r.pos);
10373 st.width = r.width;
10374 st.height = r.height;
10379 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10380 switch(anchor.toLowerCase()){
10407 arguments.callee.anim = this.fxanim(a,
10417 * Ensures that all effects queued after syncFx is called on the element are
10418 * run concurrently. This is the opposite of {@link #sequenceFx}.
10419 * @return {Roo.Element} The Element
10421 syncFx : function(){
10422 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10431 * Ensures that all effects queued after sequenceFx is called on the element are
10432 * run in sequence. This is the opposite of {@link #syncFx}.
10433 * @return {Roo.Element} The Element
10435 sequenceFx : function(){
10436 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10438 concurrent : false,
10445 nextFx : function(){
10446 var ef = this.fxQueue[0];
10453 * Returns true if the element has any effects actively running or queued, else returns false.
10454 * @return {Boolean} True if element has active effects, else false
10456 hasActiveFx : function(){
10457 return this.fxQueue && this.fxQueue[0];
10461 * Stops any running effects and clears the element's internal effects queue if it contains
10462 * any additional effects that haven't started yet.
10463 * @return {Roo.Element} The Element
10465 stopFx : function(){
10466 if(this.hasActiveFx()){
10467 var cur = this.fxQueue[0];
10468 if(cur && cur.anim && cur.anim.isAnimated()){
10469 this.fxQueue = [cur]; // clear out others
10470 cur.anim.stop(true);
10477 beforeFx : function(o){
10478 if(this.hasActiveFx() && !o.concurrent){
10489 * Returns true if the element is currently blocking so that no other effect can be queued
10490 * until this effect is finished, else returns false if blocking is not set. This is commonly
10491 * used to ensure that an effect initiated by a user action runs to completion prior to the
10492 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10493 * @return {Boolean} True if blocking, else false
10495 hasFxBlock : function(){
10496 var q = this.fxQueue;
10497 return q && q[0] && q[0].block;
10501 queueFx : function(o, fn){
10505 if(!this.hasFxBlock()){
10506 Roo.applyIf(o, this.fxDefaults);
10508 var run = this.beforeFx(o);
10509 fn.block = o.block;
10510 this.fxQueue.push(fn);
10522 fxWrap : function(pos, o, vis){
10524 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10527 wrapXY = this.getXY();
10529 var div = document.createElement("div");
10530 div.style.visibility = vis;
10531 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10532 wrap.setPositioning(pos);
10533 if(wrap.getStyle("position") == "static"){
10534 wrap.position("relative");
10536 this.clearPositioning('auto');
10538 wrap.dom.appendChild(this.dom);
10540 wrap.setXY(wrapXY);
10547 fxUnwrap : function(wrap, pos, o){
10548 this.clearPositioning();
10549 this.setPositioning(pos);
10551 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10557 getFxRestore : function(){
10558 var st = this.dom.style;
10559 return {pos: this.getPositioning(), width: st.width, height : st.height};
10563 afterFx : function(o){
10565 this.applyStyles(o.afterStyle);
10568 this.addClass(o.afterCls);
10570 if(o.remove === true){
10573 Roo.callback(o.callback, o.scope, [this]);
10575 this.fxQueue.shift();
10581 getFxEl : function(){ // support for composite element fx
10582 return Roo.get(this.dom);
10586 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10587 animType = animType || 'run';
10589 var anim = Roo.lib.Anim[animType](
10591 (opt.duration || defaultDur) || .35,
10592 (opt.easing || defaultEase) || 'easeOut',
10594 Roo.callback(cb, this);
10603 // backwords compat
10604 Roo.Fx.resize = Roo.Fx.scale;
10606 //When included, Roo.Fx is automatically applied to Element so that all basic
10607 //effects are available directly via the Element API
10608 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10610 * Ext JS Library 1.1.1
10611 * Copyright(c) 2006-2007, Ext JS, LLC.
10613 * Originally Released Under LGPL - original licence link has changed is not relivant.
10616 * <script type="text/javascript">
10621 * @class Roo.CompositeElement
10622 * Standard composite class. Creates a Roo.Element for every element in the collection.
10624 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10625 * actions will be performed on all the elements in this collection.</b>
10627 * All methods return <i>this</i> and can be chained.
10629 var els = Roo.select("#some-el div.some-class", true);
10630 // or select directly from an existing element
10631 var el = Roo.get('some-el');
10632 el.select('div.some-class', true);
10634 els.setWidth(100); // all elements become 100 width
10635 els.hide(true); // all elements fade out and hide
10637 els.setWidth(100).hide(true);
10640 Roo.CompositeElement = function(els){
10641 this.elements = [];
10642 this.addElements(els);
10644 Roo.CompositeElement.prototype = {
10646 addElements : function(els){
10647 if(!els) return this;
10648 if(typeof els == "string"){
10649 els = Roo.Element.selectorFunction(els);
10651 var yels = this.elements;
10652 var index = yels.length-1;
10653 for(var i = 0, len = els.length; i < len; i++) {
10654 yels[++index] = Roo.get(els[i]);
10660 * Clears this composite and adds the elements returned by the passed selector.
10661 * @param {String/Array} els A string CSS selector, an array of elements or an element
10662 * @return {CompositeElement} this
10664 fill : function(els){
10665 this.elements = [];
10671 * Filters this composite to only elements that match the passed selector.
10672 * @param {String} selector A string CSS selector
10673 * @return {CompositeElement} this
10675 filter : function(selector){
10677 this.each(function(el){
10678 if(el.is(selector)){
10679 els[els.length] = el.dom;
10686 invoke : function(fn, args){
10687 var els = this.elements;
10688 for(var i = 0, len = els.length; i < len; i++) {
10689 Roo.Element.prototype[fn].apply(els[i], args);
10694 * Adds elements to this composite.
10695 * @param {String/Array} els A string CSS selector, an array of elements or an element
10696 * @return {CompositeElement} this
10698 add : function(els){
10699 if(typeof els == "string"){
10700 this.addElements(Roo.Element.selectorFunction(els));
10701 }else if(els.length !== undefined){
10702 this.addElements(els);
10704 this.addElements([els]);
10709 * Calls the passed function passing (el, this, index) for each element in this composite.
10710 * @param {Function} fn The function to call
10711 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10712 * @return {CompositeElement} this
10714 each : function(fn, scope){
10715 var els = this.elements;
10716 for(var i = 0, len = els.length; i < len; i++){
10717 if(fn.call(scope || els[i], els[i], this, i) === false) {
10725 * Returns the Element object at the specified index
10726 * @param {Number} index
10727 * @return {Roo.Element}
10729 item : function(index){
10730 return this.elements[index] || null;
10734 * Returns the first Element
10735 * @return {Roo.Element}
10737 first : function(){
10738 return this.item(0);
10742 * Returns the last Element
10743 * @return {Roo.Element}
10746 return this.item(this.elements.length-1);
10750 * Returns the number of elements in this composite
10753 getCount : function(){
10754 return this.elements.length;
10758 * Returns true if this composite contains the passed element
10761 contains : function(el){
10762 return this.indexOf(el) !== -1;
10766 * Returns true if this composite contains the passed element
10769 indexOf : function(el){
10770 return this.elements.indexOf(Roo.get(el));
10775 * Removes the specified element(s).
10776 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10777 * or an array of any of those.
10778 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10779 * @return {CompositeElement} this
10781 removeElement : function(el, removeDom){
10782 if(el instanceof Array){
10783 for(var i = 0, len = el.length; i < len; i++){
10784 this.removeElement(el[i]);
10788 var index = typeof el == 'number' ? el : this.indexOf(el);
10791 var d = this.elements[index];
10795 d.parentNode.removeChild(d);
10798 this.elements.splice(index, 1);
10804 * Replaces the specified element with the passed element.
10805 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10807 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10808 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10809 * @return {CompositeElement} this
10811 replaceElement : function(el, replacement, domReplace){
10812 var index = typeof el == 'number' ? el : this.indexOf(el);
10815 this.elements[index].replaceWith(replacement);
10817 this.elements.splice(index, 1, Roo.get(replacement))
10824 * Removes all elements.
10826 clear : function(){
10827 this.elements = [];
10831 Roo.CompositeElement.createCall = function(proto, fnName){
10832 if(!proto[fnName]){
10833 proto[fnName] = function(){
10834 return this.invoke(fnName, arguments);
10838 for(var fnName in Roo.Element.prototype){
10839 if(typeof Roo.Element.prototype[fnName] == "function"){
10840 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10846 * Ext JS Library 1.1.1
10847 * Copyright(c) 2006-2007, Ext JS, LLC.
10849 * Originally Released Under LGPL - original licence link has changed is not relivant.
10852 * <script type="text/javascript">
10856 * @class Roo.CompositeElementLite
10857 * @extends Roo.CompositeElement
10858 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10860 var els = Roo.select("#some-el div.some-class");
10861 // or select directly from an existing element
10862 var el = Roo.get('some-el');
10863 el.select('div.some-class');
10865 els.setWidth(100); // all elements become 100 width
10866 els.hide(true); // all elements fade out and hide
10868 els.setWidth(100).hide(true);
10869 </code></pre><br><br>
10870 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10871 * actions will be performed on all the elements in this collection.</b>
10873 Roo.CompositeElementLite = function(els){
10874 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10875 this.el = new Roo.Element.Flyweight();
10877 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10878 addElements : function(els){
10880 if(els instanceof Array){
10881 this.elements = this.elements.concat(els);
10883 var yels = this.elements;
10884 var index = yels.length-1;
10885 for(var i = 0, len = els.length; i < len; i++) {
10886 yels[++index] = els[i];
10892 invoke : function(fn, args){
10893 var els = this.elements;
10895 for(var i = 0, len = els.length; i < len; i++) {
10897 Roo.Element.prototype[fn].apply(el, args);
10902 * Returns a flyweight Element of the dom element object at the specified index
10903 * @param {Number} index
10904 * @return {Roo.Element}
10906 item : function(index){
10907 if(!this.elements[index]){
10910 this.el.dom = this.elements[index];
10914 // fixes scope with flyweight
10915 addListener : function(eventName, handler, scope, opt){
10916 var els = this.elements;
10917 for(var i = 0, len = els.length; i < len; i++) {
10918 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10924 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10925 * passed is the flyweight (shared) Roo.Element instance, so if you require a
10926 * a reference to the dom node, use el.dom.</b>
10927 * @param {Function} fn The function to call
10928 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10929 * @return {CompositeElement} this
10931 each : function(fn, scope){
10932 var els = this.elements;
10934 for(var i = 0, len = els.length; i < len; i++){
10936 if(fn.call(scope || el, el, this, i) === false){
10943 indexOf : function(el){
10944 return this.elements.indexOf(Roo.getDom(el));
10947 replaceElement : function(el, replacement, domReplace){
10948 var index = typeof el == 'number' ? el : this.indexOf(el);
10950 replacement = Roo.getDom(replacement);
10952 var d = this.elements[index];
10953 d.parentNode.insertBefore(replacement, d);
10954 d.parentNode.removeChild(d);
10956 this.elements.splice(index, 1, replacement);
10961 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10965 * Ext JS Library 1.1.1
10966 * Copyright(c) 2006-2007, Ext JS, LLC.
10968 * Originally Released Under LGPL - original licence link has changed is not relivant.
10971 * <script type="text/javascript">
10977 * @class Roo.data.Connection
10978 * @extends Roo.util.Observable
10979 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
10980 * either to a configured URL, or to a URL specified at request time.<br><br>
10982 * Requests made by this class are asynchronous, and will return immediately. No data from
10983 * the server will be available to the statement immediately following the {@link #request} call.
10984 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
10986 * Note: If you are doing a file upload, you will not get a normal response object sent back to
10987 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
10988 * The response object is created using the innerHTML of the IFRAME's document as the responseText
10989 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
10990 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
10991 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
10992 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
10993 * standard DOM methods.
10995 * @param {Object} config a configuration object.
10997 Roo.data.Connection = function(config){
10998 Roo.apply(this, config);
11001 * @event beforerequest
11002 * Fires before a network request is made to retrieve a data object.
11003 * @param {Connection} conn This Connection object.
11004 * @param {Object} options The options config object passed to the {@link #request} method.
11006 "beforerequest" : true,
11008 * @event requestcomplete
11009 * Fires if the request was successfully completed.
11010 * @param {Connection} conn This Connection object.
11011 * @param {Object} response The XHR object containing the response data.
11012 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11013 * @param {Object} options The options config object passed to the {@link #request} method.
11015 "requestcomplete" : true,
11017 * @event requestexception
11018 * Fires if an error HTTP status was returned from the server.
11019 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11020 * @param {Connection} conn This Connection object.
11021 * @param {Object} response The XHR object containing the response data.
11022 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11023 * @param {Object} options The options config object passed to the {@link #request} method.
11025 "requestexception" : true
11027 Roo.data.Connection.superclass.constructor.call(this);
11030 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11032 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11035 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11036 * extra parameters to each request made by this object. (defaults to undefined)
11039 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11040 * to each request made by this object. (defaults to undefined)
11043 * @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)
11046 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11050 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11056 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11059 disableCaching: true,
11062 * Sends an HTTP request to a remote server.
11063 * @param {Object} options An object which may contain the following properties:<ul>
11064 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11065 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11066 * request, a url encoded string or a function to call to get either.</li>
11067 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11068 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11069 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11070 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11071 * <li>options {Object} The parameter to the request call.</li>
11072 * <li>success {Boolean} True if the request succeeded.</li>
11073 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11075 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11076 * The callback is passed the following parameters:<ul>
11077 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11078 * <li>options {Object} The parameter to the request call.</li>
11080 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11081 * The callback is passed the following parameters:<ul>
11082 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11083 * <li>options {Object} The parameter to the request call.</li>
11085 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11086 * for the callback function. Defaults to the browser window.</li>
11087 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11088 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11089 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11090 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11091 * params for the post data. Any params will be appended to the URL.</li>
11092 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11094 * @return {Number} transactionId
11096 request : function(o){
11097 if(this.fireEvent("beforerequest", this, o) !== false){
11100 if(typeof p == "function"){
11101 p = p.call(o.scope||window, o);
11103 if(typeof p == "object"){
11104 p = Roo.urlEncode(o.params);
11106 if(this.extraParams){
11107 var extras = Roo.urlEncode(this.extraParams);
11108 p = p ? (p + '&' + extras) : extras;
11111 var url = o.url || this.url;
11112 if(typeof url == 'function'){
11113 url = url.call(o.scope||window, o);
11117 var form = Roo.getDom(o.form);
11118 url = url || form.action;
11120 var enctype = form.getAttribute("enctype");
11121 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11122 return this.doFormUpload(o, p, url);
11124 var f = Roo.lib.Ajax.serializeForm(form);
11125 p = p ? (p + '&' + f) : f;
11128 var hs = o.headers;
11129 if(this.defaultHeaders){
11130 hs = Roo.apply(hs || {}, this.defaultHeaders);
11137 success: this.handleResponse,
11138 failure: this.handleFailure,
11140 argument: {options: o},
11141 timeout : this.timeout
11144 var method = o.method||this.method||(p ? "POST" : "GET");
11146 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11147 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11150 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11154 }else if(this.autoAbort !== false){
11158 if((method == 'GET' && p) || o.xmlData){
11159 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11162 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11163 return this.transId;
11165 Roo.callback(o.callback, o.scope, [o, null, null]);
11171 * Determine whether this object has a request outstanding.
11172 * @param {Number} transactionId (Optional) defaults to the last transaction
11173 * @return {Boolean} True if there is an outstanding request.
11175 isLoading : function(transId){
11177 return Roo.lib.Ajax.isCallInProgress(transId);
11179 return this.transId ? true : false;
11184 * Aborts any outstanding request.
11185 * @param {Number} transactionId (Optional) defaults to the last transaction
11187 abort : function(transId){
11188 if(transId || this.isLoading()){
11189 Roo.lib.Ajax.abort(transId || this.transId);
11194 handleResponse : function(response){
11195 this.transId = false;
11196 var options = response.argument.options;
11197 response.argument = options ? options.argument : null;
11198 this.fireEvent("requestcomplete", this, response, options);
11199 Roo.callback(options.success, options.scope, [response, options]);
11200 Roo.callback(options.callback, options.scope, [options, true, response]);
11204 handleFailure : function(response, e){
11205 this.transId = false;
11206 var options = response.argument.options;
11207 response.argument = options ? options.argument : null;
11208 this.fireEvent("requestexception", this, response, options, e);
11209 Roo.callback(options.failure, options.scope, [response, options]);
11210 Roo.callback(options.callback, options.scope, [options, false, response]);
11214 doFormUpload : function(o, ps, url){
11216 var frame = document.createElement('iframe');
11219 frame.className = 'x-hidden';
11221 frame.src = Roo.SSL_SECURE_URL;
11223 document.body.appendChild(frame);
11226 document.frames[id].name = id;
11229 var form = Roo.getDom(o.form);
11231 form.method = 'POST';
11232 form.enctype = form.encoding = 'multipart/form-data';
11238 if(ps){ // add dynamic params
11240 ps = Roo.urlDecode(ps, false);
11242 if(ps.hasOwnProperty(k)){
11243 hd = document.createElement('input');
11244 hd.type = 'hidden';
11247 form.appendChild(hd);
11254 var r = { // bogus response object
11259 r.argument = o ? o.argument : null;
11264 doc = frame.contentWindow.document;
11266 doc = (frame.contentDocument || window.frames[id].document);
11268 if(doc && doc.body){
11269 r.responseText = doc.body.innerHTML;
11271 if(doc && doc.XMLDocument){
11272 r.responseXML = doc.XMLDocument;
11274 r.responseXML = doc;
11281 Roo.EventManager.removeListener(frame, 'load', cb, this);
11283 this.fireEvent("requestcomplete", this, r, o);
11284 Roo.callback(o.success, o.scope, [r, o]);
11285 Roo.callback(o.callback, o.scope, [o, true, r]);
11287 setTimeout(function(){document.body.removeChild(frame);}, 100);
11290 Roo.EventManager.on(frame, 'load', cb, this);
11293 if(hiddens){ // remove dynamic params
11294 for(var i = 0, len = hiddens.length; i < len; i++){
11295 form.removeChild(hiddens[i]);
11303 * @extends Roo.data.Connection
11304 * Global Ajax request class.
11308 Roo.Ajax = new Roo.data.Connection({
11311 * @cfg {String} url @hide
11314 * @cfg {Object} extraParams @hide
11317 * @cfg {Object} defaultHeaders @hide
11320 * @cfg {String} method (Optional) @hide
11323 * @cfg {Number} timeout (Optional) @hide
11326 * @cfg {Boolean} autoAbort (Optional) @hide
11330 * @cfg {Boolean} disableCaching (Optional) @hide
11334 * @property disableCaching
11335 * True to add a unique cache-buster param to GET requests. (defaults to true)
11340 * The default URL to be used for requests to the server. (defaults to undefined)
11344 * @property extraParams
11345 * An object containing properties which are used as
11346 * extra parameters to each request made by this object. (defaults to undefined)
11350 * @property defaultHeaders
11351 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11356 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11360 * @property timeout
11361 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11366 * @property autoAbort
11367 * Whether a new request should abort any pending requests. (defaults to false)
11373 * Serialize the passed form into a url encoded string
11374 * @param {String/HTMLElement} form
11377 serializeForm : function(form){
11378 return Roo.lib.Ajax.serializeForm(form);
11382 * Ext JS Library 1.1.1
11383 * Copyright(c) 2006-2007, Ext JS, LLC.
11385 * Originally Released Under LGPL - original licence link has changed is not relivant.
11388 * <script type="text/javascript">
11393 * @extends Roo.data.Connection
11394 * Global Ajax request class.
11396 * @instanceOf Roo.data.Connection
11398 Roo.Ajax = new Roo.data.Connection({
11407 * @cfg {String} url @hide
11410 * @cfg {Object} extraParams @hide
11413 * @cfg {Object} defaultHeaders @hide
11416 * @cfg {String} method (Optional) @hide
11419 * @cfg {Number} timeout (Optional) @hide
11422 * @cfg {Boolean} autoAbort (Optional) @hide
11426 * @cfg {Boolean} disableCaching (Optional) @hide
11430 * @property disableCaching
11431 * True to add a unique cache-buster param to GET requests. (defaults to true)
11436 * The default URL to be used for requests to the server. (defaults to undefined)
11440 * @property extraParams
11441 * An object containing properties which are used as
11442 * extra parameters to each request made by this object. (defaults to undefined)
11446 * @property defaultHeaders
11447 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11452 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11456 * @property timeout
11457 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11462 * @property autoAbort
11463 * Whether a new request should abort any pending requests. (defaults to false)
11469 * Serialize the passed form into a url encoded string
11470 * @param {String/HTMLElement} form
11473 serializeForm : function(form){
11474 return Roo.lib.Ajax.serializeForm(form);
11478 * Ext JS Library 1.1.1
11479 * Copyright(c) 2006-2007, Ext JS, LLC.
11481 * Originally Released Under LGPL - original licence link has changed is not relivant.
11484 * <script type="text/javascript">
11489 * @class Roo.UpdateManager
11490 * @extends Roo.util.Observable
11491 * Provides AJAX-style update for Element object.<br><br>
11494 * // Get it from a Roo.Element object
11495 * var el = Roo.get("foo");
11496 * var mgr = el.getUpdateManager();
11497 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11499 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11501 * // or directly (returns the same UpdateManager instance)
11502 * var mgr = new Roo.UpdateManager("myElementId");
11503 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11504 * mgr.on("update", myFcnNeedsToKnow);
11506 // short handed call directly from the element object
11507 Roo.get("foo").load({
11511 text: "Loading Foo..."
11515 * Create new UpdateManager directly.
11516 * @param {String/HTMLElement/Roo.Element} el The element to update
11517 * @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).
11519 Roo.UpdateManager = function(el, forceNew){
11521 if(!forceNew && el.updateManager){
11522 return el.updateManager;
11525 * The Element object
11526 * @type Roo.Element
11530 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11533 this.defaultUrl = null;
11537 * @event beforeupdate
11538 * Fired before an update is made, return false from your handler and the update is cancelled.
11539 * @param {Roo.Element} el
11540 * @param {String/Object/Function} url
11541 * @param {String/Object} params
11543 "beforeupdate": true,
11546 * Fired after successful update is made.
11547 * @param {Roo.Element} el
11548 * @param {Object} oResponseObject The response Object
11553 * Fired on update failure.
11554 * @param {Roo.Element} el
11555 * @param {Object} oResponseObject The response Object
11559 var d = Roo.UpdateManager.defaults;
11561 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11564 this.sslBlankUrl = d.sslBlankUrl;
11566 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11569 this.disableCaching = d.disableCaching;
11571 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11574 this.indicatorText = d.indicatorText;
11576 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11579 this.showLoadIndicator = d.showLoadIndicator;
11581 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11584 this.timeout = d.timeout;
11587 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11590 this.loadScripts = d.loadScripts;
11593 * Transaction object of current executing transaction
11595 this.transaction = null;
11600 this.autoRefreshProcId = null;
11602 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11605 this.refreshDelegate = this.refresh.createDelegate(this);
11607 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11610 this.updateDelegate = this.update.createDelegate(this);
11612 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11615 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11619 this.successDelegate = this.processSuccess.createDelegate(this);
11623 this.failureDelegate = this.processFailure.createDelegate(this);
11625 if(!this.renderer){
11627 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11629 this.renderer = new Roo.UpdateManager.BasicRenderer();
11632 Roo.UpdateManager.superclass.constructor.call(this);
11635 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11637 * Get the Element this UpdateManager is bound to
11638 * @return {Roo.Element} The element
11640 getEl : function(){
11644 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11645 * @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:
11648 url: "your-url.php",<br/>
11649 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11650 callback: yourFunction,<br/>
11651 scope: yourObject, //(optional scope) <br/>
11652 discardUrl: false, <br/>
11653 nocache: false,<br/>
11654 text: "Loading...",<br/>
11656 scripts: false<br/>
11659 * The only required property is url. The optional properties nocache, text and scripts
11660 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11661 * @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}
11662 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11663 * @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.
11665 update : function(url, params, callback, discardUrl){
11666 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11667 var method = this.method, cfg;
11668 if(typeof url == "object"){ // must be config object
11671 params = params || cfg.params;
11672 callback = callback || cfg.callback;
11673 discardUrl = discardUrl || cfg.discardUrl;
11674 if(callback && cfg.scope){
11675 callback = callback.createDelegate(cfg.scope);
11677 if(typeof cfg.method != "undefined"){method = cfg.method;};
11678 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11679 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11680 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11681 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11683 this.showLoading();
11685 this.defaultUrl = url;
11687 if(typeof url == "function"){
11688 url = url.call(this);
11691 method = method || (params ? "POST" : "GET");
11692 if(method == "GET"){
11693 url = this.prepareUrl(url);
11696 var o = Roo.apply(cfg ||{}, {
11699 success: this.successDelegate,
11700 failure: this.failureDelegate,
11701 callback: undefined,
11702 timeout: (this.timeout*1000),
11703 argument: {"url": url, "form": null, "callback": callback, "params": params}
11706 this.transaction = Roo.Ajax.request(o);
11711 * 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.
11712 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11713 * @param {String/HTMLElement} form The form Id or form element
11714 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11715 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11716 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11718 formUpdate : function(form, url, reset, callback){
11719 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11720 if(typeof url == "function"){
11721 url = url.call(this);
11723 form = Roo.getDom(form);
11724 this.transaction = Roo.Ajax.request({
11727 success: this.successDelegate,
11728 failure: this.failureDelegate,
11729 timeout: (this.timeout*1000),
11730 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11732 this.showLoading.defer(1, this);
11737 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11738 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11740 refresh : function(callback){
11741 if(this.defaultUrl == null){
11744 this.update(this.defaultUrl, null, callback, true);
11748 * Set this element to auto refresh.
11749 * @param {Number} interval How often to update (in seconds).
11750 * @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)
11751 * @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}
11752 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11753 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11755 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11757 this.update(url || this.defaultUrl, params, callback, true);
11759 if(this.autoRefreshProcId){
11760 clearInterval(this.autoRefreshProcId);
11762 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11766 * Stop auto refresh on this element.
11768 stopAutoRefresh : function(){
11769 if(this.autoRefreshProcId){
11770 clearInterval(this.autoRefreshProcId);
11771 delete this.autoRefreshProcId;
11775 isAutoRefreshing : function(){
11776 return this.autoRefreshProcId ? true : false;
11779 * Called to update the element to "Loading" state. Override to perform custom action.
11781 showLoading : function(){
11782 if(this.showLoadIndicator){
11783 this.el.update(this.indicatorText);
11788 * Adds unique parameter to query string if disableCaching = true
11791 prepareUrl : function(url){
11792 if(this.disableCaching){
11793 var append = "_dc=" + (new Date().getTime());
11794 if(url.indexOf("?") !== -1){
11795 url += "&" + append;
11797 url += "?" + append;
11806 processSuccess : function(response){
11807 this.transaction = null;
11808 if(response.argument.form && response.argument.reset){
11809 try{ // put in try/catch since some older FF releases had problems with this
11810 response.argument.form.reset();
11813 if(this.loadScripts){
11814 this.renderer.render(this.el, response, this,
11815 this.updateComplete.createDelegate(this, [response]));
11817 this.renderer.render(this.el, response, this);
11818 this.updateComplete(response);
11822 updateComplete : function(response){
11823 this.fireEvent("update", this.el, response);
11824 if(typeof response.argument.callback == "function"){
11825 response.argument.callback(this.el, true, response);
11832 processFailure : function(response){
11833 this.transaction = null;
11834 this.fireEvent("failure", this.el, response);
11835 if(typeof response.argument.callback == "function"){
11836 response.argument.callback(this.el, false, response);
11841 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11842 * @param {Object} renderer The object implementing the render() method
11844 setRenderer : function(renderer){
11845 this.renderer = renderer;
11848 getRenderer : function(){
11849 return this.renderer;
11853 * Set the defaultUrl used for updates
11854 * @param {String/Function} defaultUrl The url or a function to call to get the url
11856 setDefaultUrl : function(defaultUrl){
11857 this.defaultUrl = defaultUrl;
11861 * Aborts the executing transaction
11863 abort : function(){
11864 if(this.transaction){
11865 Roo.Ajax.abort(this.transaction);
11870 * Returns true if an update is in progress
11871 * @return {Boolean}
11873 isUpdating : function(){
11874 if(this.transaction){
11875 return Roo.Ajax.isLoading(this.transaction);
11882 * @class Roo.UpdateManager.defaults
11883 * @static (not really - but it helps the doc tool)
11884 * The defaults collection enables customizing the default properties of UpdateManager
11886 Roo.UpdateManager.defaults = {
11888 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11894 * True to process scripts by default (Defaults to false).
11897 loadScripts : false,
11900 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11903 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11905 * Whether to append unique parameter on get request to disable caching (Defaults to false).
11908 disableCaching : false,
11910 * Whether to show indicatorText when loading (Defaults to true).
11913 showLoadIndicator : true,
11915 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
11918 indicatorText : '<div class="loading-indicator">Loading...</div>'
11922 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11924 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11925 * @param {String/HTMLElement/Roo.Element} el The element to update
11926 * @param {String} url The url
11927 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11928 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11931 * @member Roo.UpdateManager
11933 Roo.UpdateManager.updateElement = function(el, url, params, options){
11934 var um = Roo.get(el, true).getUpdateManager();
11935 Roo.apply(um, options);
11936 um.update(url, params, options ? options.callback : null);
11938 // alias for backwards compat
11939 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11941 * @class Roo.UpdateManager.BasicRenderer
11942 * Default Content renderer. Updates the elements innerHTML with the responseText.
11944 Roo.UpdateManager.BasicRenderer = function(){};
11946 Roo.UpdateManager.BasicRenderer.prototype = {
11948 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11949 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11950 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11951 * @param {Roo.Element} el The element being rendered
11952 * @param {Object} response The YUI Connect response object
11953 * @param {UpdateManager} updateManager The calling update manager
11954 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11956 render : function(el, response, updateManager, callback){
11957 el.update(response.responseText, updateManager.loadScripts, callback);
11962 * Ext JS Library 1.1.1
11963 * Copyright(c) 2006-2007, Ext JS, LLC.
11965 * Originally Released Under LGPL - original licence link has changed is not relivant.
11968 * <script type="text/javascript">
11972 * @class Roo.util.DelayedTask
11973 * Provides a convenient method of performing setTimeout where a new
11974 * timeout cancels the old timeout. An example would be performing validation on a keypress.
11975 * You can use this class to buffer
11976 * the keypress events for a certain number of milliseconds, and perform only if they stop
11977 * for that amount of time.
11978 * @constructor The parameters to this constructor serve as defaults and are not required.
11979 * @param {Function} fn (optional) The default function to timeout
11980 * @param {Object} scope (optional) The default scope of that timeout
11981 * @param {Array} args (optional) The default Array of arguments
11983 Roo.util.DelayedTask = function(fn, scope, args){
11984 var id = null, d, t;
11986 var call = function(){
11987 var now = new Date().getTime();
11991 fn.apply(scope, args || []);
11995 * Cancels any pending timeout and queues a new one
11996 * @param {Number} delay The milliseconds to delay
11997 * @param {Function} newFn (optional) Overrides function passed to constructor
11998 * @param {Object} newScope (optional) Overrides scope passed to constructor
11999 * @param {Array} newArgs (optional) Overrides args passed to constructor
12001 this.delay = function(delay, newFn, newScope, newArgs){
12002 if(id && delay != d){
12006 t = new Date().getTime();
12008 scope = newScope || scope;
12009 args = newArgs || args;
12011 id = setInterval(call, d);
12016 * Cancel the last queued timeout
12018 this.cancel = function(){
12026 * Ext JS Library 1.1.1
12027 * Copyright(c) 2006-2007, Ext JS, LLC.
12029 * Originally Released Under LGPL - original licence link has changed is not relivant.
12032 * <script type="text/javascript">
12036 Roo.util.TaskRunner = function(interval){
12037 interval = interval || 10;
12038 var tasks = [], removeQueue = [];
12040 var running = false;
12042 var stopThread = function(){
12048 var startThread = function(){
12051 id = setInterval(runTasks, interval);
12055 var removeTask = function(task){
12056 removeQueue.push(task);
12062 var runTasks = function(){
12063 if(removeQueue.length > 0){
12064 for(var i = 0, len = removeQueue.length; i < len; i++){
12065 tasks.remove(removeQueue[i]);
12068 if(tasks.length < 1){
12073 var now = new Date().getTime();
12074 for(var i = 0, len = tasks.length; i < len; ++i){
12076 var itime = now - t.taskRunTime;
12077 if(t.interval <= itime){
12078 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12079 t.taskRunTime = now;
12080 if(rt === false || t.taskRunCount === t.repeat){
12085 if(t.duration && t.duration <= (now - t.taskStartTime)){
12092 * Queues a new task.
12093 * @param {Object} task
12095 this.start = function(task){
12097 task.taskStartTime = new Date().getTime();
12098 task.taskRunTime = 0;
12099 task.taskRunCount = 0;
12104 this.stop = function(task){
12109 this.stopAll = function(){
12111 for(var i = 0, len = tasks.length; i < len; i++){
12112 if(tasks[i].onStop){
12121 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12123 * Ext JS Library 1.1.1
12124 * Copyright(c) 2006-2007, Ext JS, LLC.
12126 * Originally Released Under LGPL - original licence link has changed is not relivant.
12129 * <script type="text/javascript">
12134 * @class Roo.util.MixedCollection
12135 * @extends Roo.util.Observable
12136 * A Collection class that maintains both numeric indexes and keys and exposes events.
12138 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12139 * collection (defaults to false)
12140 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12141 * and return the key value for that item. This is used when available to look up the key on items that
12142 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12143 * equivalent to providing an implementation for the {@link #getKey} method.
12145 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12153 * Fires when the collection is cleared.
12158 * Fires when an item is added to the collection.
12159 * @param {Number} index The index at which the item was added.
12160 * @param {Object} o The item added.
12161 * @param {String} key The key associated with the added item.
12166 * Fires when an item is replaced in the collection.
12167 * @param {String} key he key associated with the new added.
12168 * @param {Object} old The item being replaced.
12169 * @param {Object} new The new item.
12174 * Fires when an item is removed from the collection.
12175 * @param {Object} o The item being removed.
12176 * @param {String} key (optional) The key associated with the removed item.
12181 this.allowFunctions = allowFunctions === true;
12183 this.getKey = keyFn;
12185 Roo.util.MixedCollection.superclass.constructor.call(this);
12188 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12189 allowFunctions : false,
12192 * Adds an item to the collection.
12193 * @param {String} key The key to associate with the item
12194 * @param {Object} o The item to add.
12195 * @return {Object} The item added.
12197 add : function(key, o){
12198 if(arguments.length == 1){
12200 key = this.getKey(o);
12202 if(typeof key == "undefined" || key === null){
12204 this.items.push(o);
12205 this.keys.push(null);
12207 var old = this.map[key];
12209 return this.replace(key, o);
12212 this.items.push(o);
12214 this.keys.push(key);
12216 this.fireEvent("add", this.length-1, o, key);
12221 * MixedCollection has a generic way to fetch keys if you implement getKey.
12224 var mc = new Roo.util.MixedCollection();
12225 mc.add(someEl.dom.id, someEl);
12226 mc.add(otherEl.dom.id, otherEl);
12230 var mc = new Roo.util.MixedCollection();
12231 mc.getKey = function(el){
12237 // or via the constructor
12238 var mc = new Roo.util.MixedCollection(false, function(el){
12244 * @param o {Object} The item for which to find the key.
12245 * @return {Object} The key for the passed item.
12247 getKey : function(o){
12252 * Replaces an item in the collection.
12253 * @param {String} key The key associated with the item to replace, or the item to replace.
12254 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12255 * @return {Object} The new item.
12257 replace : function(key, o){
12258 if(arguments.length == 1){
12260 key = this.getKey(o);
12262 var old = this.item(key);
12263 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12264 return this.add(key, o);
12266 var index = this.indexOfKey(key);
12267 this.items[index] = o;
12269 this.fireEvent("replace", key, old, o);
12274 * Adds all elements of an Array or an Object to the collection.
12275 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12276 * an Array of values, each of which are added to the collection.
12278 addAll : function(objs){
12279 if(arguments.length > 1 || objs instanceof Array){
12280 var args = arguments.length > 1 ? arguments : objs;
12281 for(var i = 0, len = args.length; i < len; i++){
12285 for(var key in objs){
12286 if(this.allowFunctions || typeof objs[key] != "function"){
12287 this.add(key, objs[key]);
12294 * Executes the specified function once for every item in the collection, passing each
12295 * item as the first and only parameter. returning false from the function will stop the iteration.
12296 * @param {Function} fn The function to execute for each item.
12297 * @param {Object} scope (optional) The scope in which to execute the function.
12299 each : function(fn, scope){
12300 var items = [].concat(this.items); // each safe for removal
12301 for(var i = 0, len = items.length; i < len; i++){
12302 if(fn.call(scope || items[i], items[i], i, len) === false){
12309 * Executes the specified function once for every key in the collection, passing each
12310 * key, and its associated item as the first two parameters.
12311 * @param {Function} fn The function to execute for each item.
12312 * @param {Object} scope (optional) The scope in which to execute the function.
12314 eachKey : function(fn, scope){
12315 for(var i = 0, len = this.keys.length; i < len; i++){
12316 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12321 * Returns the first item in the collection which elicits a true return value from the
12322 * passed selection function.
12323 * @param {Function} fn The selection function to execute for each item.
12324 * @param {Object} scope (optional) The scope in which to execute the function.
12325 * @return {Object} The first item in the collection which returned true from the selection function.
12327 find : function(fn, scope){
12328 for(var i = 0, len = this.items.length; i < len; i++){
12329 if(fn.call(scope || window, this.items[i], this.keys[i])){
12330 return this.items[i];
12337 * Inserts an item at the specified index in the collection.
12338 * @param {Number} index The index to insert the item at.
12339 * @param {String} key The key to associate with the new item, or the item itself.
12340 * @param {Object} o (optional) If the second parameter was a key, the new item.
12341 * @return {Object} The item inserted.
12343 insert : function(index, key, o){
12344 if(arguments.length == 2){
12346 key = this.getKey(o);
12348 if(index >= this.length){
12349 return this.add(key, o);
12352 this.items.splice(index, 0, o);
12353 if(typeof key != "undefined" && key != null){
12356 this.keys.splice(index, 0, key);
12357 this.fireEvent("add", index, o, key);
12362 * Removed an item from the collection.
12363 * @param {Object} o The item to remove.
12364 * @return {Object} The item removed.
12366 remove : function(o){
12367 return this.removeAt(this.indexOf(o));
12371 * Remove an item from a specified index in the collection.
12372 * @param {Number} index The index within the collection of the item to remove.
12374 removeAt : function(index){
12375 if(index < this.length && index >= 0){
12377 var o = this.items[index];
12378 this.items.splice(index, 1);
12379 var key = this.keys[index];
12380 if(typeof key != "undefined"){
12381 delete this.map[key];
12383 this.keys.splice(index, 1);
12384 this.fireEvent("remove", o, key);
12389 * Removed an item associated with the passed key fom the collection.
12390 * @param {String} key The key of the item to remove.
12392 removeKey : function(key){
12393 return this.removeAt(this.indexOfKey(key));
12397 * Returns the number of items in the collection.
12398 * @return {Number} the number of items in the collection.
12400 getCount : function(){
12401 return this.length;
12405 * Returns index within the collection of the passed Object.
12406 * @param {Object} o The item to find the index of.
12407 * @return {Number} index of the item.
12409 indexOf : function(o){
12410 if(!this.items.indexOf){
12411 for(var i = 0, len = this.items.length; i < len; i++){
12412 if(this.items[i] == o) return i;
12416 return this.items.indexOf(o);
12421 * Returns index within the collection of the passed key.
12422 * @param {String} key The key to find the index of.
12423 * @return {Number} index of the key.
12425 indexOfKey : function(key){
12426 if(!this.keys.indexOf){
12427 for(var i = 0, len = this.keys.length; i < len; i++){
12428 if(this.keys[i] == key) return i;
12432 return this.keys.indexOf(key);
12437 * Returns the item associated with the passed key OR index. Key has priority over index.
12438 * @param {String/Number} key The key or index of the item.
12439 * @return {Object} The item associated with the passed key.
12441 item : function(key){
12442 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12443 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12447 * Returns the item at the specified index.
12448 * @param {Number} index The index of the item.
12451 itemAt : function(index){
12452 return this.items[index];
12456 * Returns the item associated with the passed key.
12457 * @param {String/Number} key The key of the item.
12458 * @return {Object} The item associated with the passed key.
12460 key : function(key){
12461 return this.map[key];
12465 * Returns true if the collection contains the passed Object as an item.
12466 * @param {Object} o The Object to look for in the collection.
12467 * @return {Boolean} True if the collection contains the Object as an item.
12469 contains : function(o){
12470 return this.indexOf(o) != -1;
12474 * Returns true if the collection contains the passed Object as a key.
12475 * @param {String} key The key to look for in the collection.
12476 * @return {Boolean} True if the collection contains the Object as a key.
12478 containsKey : function(key){
12479 return typeof this.map[key] != "undefined";
12483 * Removes all items from the collection.
12485 clear : function(){
12490 this.fireEvent("clear");
12494 * Returns the first item in the collection.
12495 * @return {Object} the first item in the collection..
12497 first : function(){
12498 return this.items[0];
12502 * Returns the last item in the collection.
12503 * @return {Object} the last item in the collection..
12506 return this.items[this.length-1];
12509 _sort : function(property, dir, fn){
12510 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12511 fn = fn || function(a, b){
12514 var c = [], k = this.keys, items = this.items;
12515 for(var i = 0, len = items.length; i < len; i++){
12516 c[c.length] = {key: k[i], value: items[i], index: i};
12518 c.sort(function(a, b){
12519 var v = fn(a[property], b[property]) * dsc;
12521 v = (a.index < b.index ? -1 : 1);
12525 for(var i = 0, len = c.length; i < len; i++){
12526 items[i] = c[i].value;
12529 this.fireEvent("sort", this);
12533 * Sorts this collection with the passed comparison function
12534 * @param {String} direction (optional) "ASC" or "DESC"
12535 * @param {Function} fn (optional) comparison function
12537 sort : function(dir, fn){
12538 this._sort("value", dir, fn);
12542 * Sorts this collection by keys
12543 * @param {String} direction (optional) "ASC" or "DESC"
12544 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12546 keySort : function(dir, fn){
12547 this._sort("key", dir, fn || function(a, b){
12548 return String(a).toUpperCase()-String(b).toUpperCase();
12553 * Returns a range of items in this collection
12554 * @param {Number} startIndex (optional) defaults to 0
12555 * @param {Number} endIndex (optional) default to the last item
12556 * @return {Array} An array of items
12558 getRange : function(start, end){
12559 var items = this.items;
12560 if(items.length < 1){
12563 start = start || 0;
12564 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12567 for(var i = start; i <= end; i++) {
12568 r[r.length] = items[i];
12571 for(var i = start; i >= end; i--) {
12572 r[r.length] = items[i];
12579 * Filter the <i>objects</i> in this collection by a specific property.
12580 * Returns a new collection that has been filtered.
12581 * @param {String} property A property on your objects
12582 * @param {String/RegExp} value Either string that the property values
12583 * should start with or a RegExp to test against the property
12584 * @return {MixedCollection} The new filtered collection
12586 filter : function(property, value){
12587 if(!value.exec){ // not a regex
12588 value = String(value);
12589 if(value.length == 0){
12590 return this.clone();
12592 value = new RegExp("^" + Roo.escapeRe(value), "i");
12594 return this.filterBy(function(o){
12595 return o && value.test(o[property]);
12600 * Filter by a function. * Returns a new collection that has been filtered.
12601 * The passed function will be called with each
12602 * object in the collection. If the function returns true, the value is included
12603 * otherwise it is filtered.
12604 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12605 * @param {Object} scope (optional) The scope of the function (defaults to this)
12606 * @return {MixedCollection} The new filtered collection
12608 filterBy : function(fn, scope){
12609 var r = new Roo.util.MixedCollection();
12610 r.getKey = this.getKey;
12611 var k = this.keys, it = this.items;
12612 for(var i = 0, len = it.length; i < len; i++){
12613 if(fn.call(scope||this, it[i], k[i])){
12614 r.add(k[i], it[i]);
12621 * Creates a duplicate of this collection
12622 * @return {MixedCollection}
12624 clone : function(){
12625 var r = new Roo.util.MixedCollection();
12626 var k = this.keys, it = this.items;
12627 for(var i = 0, len = it.length; i < len; i++){
12628 r.add(k[i], it[i]);
12630 r.getKey = this.getKey;
12635 * Returns the item associated with the passed key or index.
12637 * @param {String/Number} key The key or index of the item.
12638 * @return {Object} The item associated with the passed key.
12640 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12642 * Ext JS Library 1.1.1
12643 * Copyright(c) 2006-2007, Ext JS, LLC.
12645 * Originally Released Under LGPL - original licence link has changed is not relivant.
12648 * <script type="text/javascript">
12651 * @class Roo.util.JSON
12652 * Modified version of Douglas Crockford"s json.js that doesn"t
12653 * mess with the Object prototype
12654 * http://www.json.org/js.html
12657 Roo.util.JSON = new (function(){
12658 var useHasOwn = {}.hasOwnProperty ? true : false;
12660 // crashes Safari in some instances
12661 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12663 var pad = function(n) {
12664 return n < 10 ? "0" + n : n;
12677 var encodeString = function(s){
12678 if (/["\\\x00-\x1f]/.test(s)) {
12679 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12684 c = b.charCodeAt();
12686 Math.floor(c / 16).toString(16) +
12687 (c % 16).toString(16);
12690 return '"' + s + '"';
12693 var encodeArray = function(o){
12694 var a = ["["], b, i, l = o.length, v;
12695 for (i = 0; i < l; i += 1) {
12697 switch (typeof v) {
12706 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12714 var encodeDate = function(o){
12715 return '"' + o.getFullYear() + "-" +
12716 pad(o.getMonth() + 1) + "-" +
12717 pad(o.getDate()) + "T" +
12718 pad(o.getHours()) + ":" +
12719 pad(o.getMinutes()) + ":" +
12720 pad(o.getSeconds()) + '"';
12724 * Encodes an Object, Array or other value
12725 * @param {Mixed} o The variable to encode
12726 * @return {String} The JSON string
12728 this.encode = function(o){
12729 if(typeof o == "undefined" || o === null){
12731 }else if(o instanceof Array){
12732 return encodeArray(o);
12733 }else if(o instanceof Date){
12734 return encodeDate(o);
12735 }else if(typeof o == "string"){
12736 return encodeString(o);
12737 }else if(typeof o == "number"){
12738 return isFinite(o) ? String(o) : "null";
12739 }else if(typeof o == "boolean"){
12742 var a = ["{"], b, i, v;
12744 if(!useHasOwn || o.hasOwnProperty(i)) {
12746 switch (typeof v) {
12755 a.push(this.encode(i), ":",
12756 v === null ? "null" : this.encode(v));
12767 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12768 * @param {String} json The JSON string
12769 * @return {Object} The resulting object
12771 this.decode = function(json){
12775 return eval("(" + json + ')');
12779 * Shorthand for {@link Roo.util.JSON#encode}
12780 * @member Roo encode
12782 Roo.encode = Roo.util.JSON.encode;
12784 * Shorthand for {@link Roo.util.JSON#decode}
12785 * @member Roo decode
12787 Roo.decode = Roo.util.JSON.decode;
12790 * Ext JS Library 1.1.1
12791 * Copyright(c) 2006-2007, Ext JS, LLC.
12793 * Originally Released Under LGPL - original licence link has changed is not relivant.
12796 * <script type="text/javascript">
12800 * @class Roo.util.Format
12801 * Reusable data formatting functions
12804 Roo.util.Format = function(){
12805 var trimRe = /^\s+|\s+$/g;
12808 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12809 * @param {String} value The string to truncate
12810 * @param {Number} length The maximum length to allow before truncating
12811 * @return {String} The converted text
12813 ellipsis : function(value, len){
12814 if(value && value.length > len){
12815 return value.substr(0, len-3)+"...";
12821 * Checks a reference and converts it to empty string if it is undefined
12822 * @param {Mixed} value Reference to check
12823 * @return {Mixed} Empty string if converted, otherwise the original value
12825 undef : function(value){
12826 return typeof value != "undefined" ? value : "";
12830 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12831 * @param {String} value The string to encode
12832 * @return {String} The encoded text
12834 htmlEncode : function(value){
12835 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12839 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12840 * @param {String} value The string to decode
12841 * @return {String} The decoded text
12843 htmlDecode : function(value){
12844 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12848 * Trims any whitespace from either side of a string
12849 * @param {String} value The text to trim
12850 * @return {String} The trimmed text
12852 trim : function(value){
12853 return String(value).replace(trimRe, "");
12857 * Returns a substring from within an original string
12858 * @param {String} value The original text
12859 * @param {Number} start The start index of the substring
12860 * @param {Number} length The length of the substring
12861 * @return {String} The substring
12863 substr : function(value, start, length){
12864 return String(value).substr(start, length);
12868 * Converts a string to all lower case letters
12869 * @param {String} value The text to convert
12870 * @return {String} The converted text
12872 lowercase : function(value){
12873 return String(value).toLowerCase();
12877 * Converts a string to all upper case letters
12878 * @param {String} value The text to convert
12879 * @return {String} The converted text
12881 uppercase : function(value){
12882 return String(value).toUpperCase();
12886 * Converts the first character only of a string to upper case
12887 * @param {String} value The text to convert
12888 * @return {String} The converted text
12890 capitalize : function(value){
12891 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12895 call : function(value, fn){
12896 if(arguments.length > 2){
12897 var args = Array.prototype.slice.call(arguments, 2);
12898 args.unshift(value);
12900 return /** eval:var:value */ eval(fn).apply(window, args);
12902 /** eval:var:value */
12903 return /** eval:var:value */ eval(fn).call(window, value);
12908 * Format a number as US currency
12909 * @param {Number/String} value The numeric value to format
12910 * @return {String} The formatted currency string
12912 usMoney : function(v){
12913 v = (Math.round((v-0)*100))/100;
12914 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12916 var ps = v.split('.');
12918 var sub = ps[1] ? '.'+ ps[1] : '.00';
12919 var r = /(\d+)(\d{3})/;
12920 while (r.test(whole)) {
12921 whole = whole.replace(r, '$1' + ',' + '$2');
12923 return "$" + whole + sub ;
12927 * Parse a value into a formatted date using the specified format pattern.
12928 * @param {Mixed} value The value to format
12929 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12930 * @return {String} The formatted date string
12932 date : function(v, format){
12936 if(!(v instanceof Date)){
12937 v = new Date(Date.parse(v));
12939 return v.dateFormat(format || "m/d/Y");
12943 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12944 * @param {String} format Any valid date format string
12945 * @return {Function} The date formatting function
12947 dateRenderer : function(format){
12948 return function(v){
12949 return Roo.util.Format.date(v, format);
12954 stripTagsRE : /<\/?[^>]+>/gi,
12957 * Strips all HTML tags
12958 * @param {Mixed} value The text from which to strip tags
12959 * @return {String} The stripped text
12961 stripTags : function(v){
12962 return !v ? v : String(v).replace(this.stripTagsRE, "");
12967 * Ext JS Library 1.1.1
12968 * Copyright(c) 2006-2007, Ext JS, LLC.
12970 * Originally Released Under LGPL - original licence link has changed is not relivant.
12973 * <script type="text/javascript">
12980 * @class Roo.MasterTemplate
12981 * @extends Roo.Template
12982 * Provides a template that can have child templates. The syntax is:
12984 var t = new Roo.MasterTemplate(
12985 '<select name="{name}">',
12986 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
12989 t.add('options', {value: 'foo', text: 'bar'});
12990 // or you can add multiple child elements in one shot
12991 t.addAll('options', [
12992 {value: 'foo', text: 'bar'},
12993 {value: 'foo2', text: 'bar2'},
12994 {value: 'foo3', text: 'bar3'}
12996 // then append, applying the master template values
12997 t.append('my-form', {name: 'my-select'});
12999 * A name attribute for the child template is not required if you have only one child
13000 * template or you want to refer to them by index.
13002 Roo.MasterTemplate = function(){
13003 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13004 this.originalHtml = this.html;
13006 var m, re = this.subTemplateRe;
13009 while(m = re.exec(this.html)){
13010 var name = m[1], content = m[2];
13015 tpl : new Roo.Template(content)
13018 st[name] = st[subIndex];
13020 st[subIndex].tpl.compile();
13021 st[subIndex].tpl.call = this.call.createDelegate(this);
13024 this.subCount = subIndex;
13027 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13029 * The regular expression used to match sub templates
13033 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13036 * Applies the passed values to a child template.
13037 * @param {String/Number} name (optional) The name or index of the child template
13038 * @param {Array/Object} values The values to be applied to the template
13039 * @return {MasterTemplate} this
13041 add : function(name, values){
13042 if(arguments.length == 1){
13043 values = arguments[0];
13046 var s = this.subs[name];
13047 s.buffer[s.buffer.length] = s.tpl.apply(values);
13052 * Applies all the passed values to a child template.
13053 * @param {String/Number} name (optional) The name or index of the child template
13054 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13055 * @param {Boolean} reset (optional) True to reset the template first
13056 * @return {MasterTemplate} this
13058 fill : function(name, values, reset){
13060 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13068 for(var i = 0, len = values.length; i < len; i++){
13069 this.add(name, values[i]);
13075 * Resets the template for reuse
13076 * @return {MasterTemplate} this
13078 reset : function(){
13080 for(var i = 0; i < this.subCount; i++){
13086 applyTemplate : function(values){
13088 var replaceIndex = -1;
13089 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13090 return s[++replaceIndex].buffer.join("");
13092 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13095 apply : function(){
13096 return this.applyTemplate.apply(this, arguments);
13099 compile : function(){return this;}
13103 * Alias for fill().
13106 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13108 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13109 * var tpl = Roo.MasterTemplate.from('element-id');
13110 * @param {String/HTMLElement} el
13111 * @param {Object} config
13114 Roo.MasterTemplate.from = function(el, config){
13115 el = Roo.getDom(el);
13116 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13119 * Ext JS Library 1.1.1
13120 * Copyright(c) 2006-2007, Ext JS, LLC.
13122 * Originally Released Under LGPL - original licence link has changed is not relivant.
13125 * <script type="text/javascript">
13130 * @class Roo.util.CSS
13131 * Utility class for manipulating CSS rules
13134 Roo.util.CSS = function(){
13136 var doc = document;
13138 var camelRe = /(-[a-z])/gi;
13139 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13143 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13144 * tag and appended to the HEAD of the document.
13145 * @param {String} cssText The text containing the css rules
13146 * @param {String} id An id to add to the stylesheet for later removal
13147 * @return {StyleSheet}
13149 createStyleSheet : function(cssText, id){
13151 var head = doc.getElementsByTagName("head")[0];
13152 var rules = doc.createElement("style");
13153 rules.setAttribute("type", "text/css");
13155 rules.setAttribute("id", id);
13158 head.appendChild(rules);
13159 ss = rules.styleSheet;
13160 ss.cssText = cssText;
13163 rules.appendChild(doc.createTextNode(cssText));
13165 rules.cssText = cssText;
13167 head.appendChild(rules);
13168 ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13170 this.cacheStyleSheet(ss);
13175 * Removes a style or link tag by id
13176 * @param {String} id The id of the tag
13178 removeStyleSheet : function(id){
13179 var existing = doc.getElementById(id);
13181 existing.parentNode.removeChild(existing);
13186 * Dynamically swaps an existing stylesheet reference for a new one
13187 * @param {String} id The id of an existing link tag to remove
13188 * @param {String} url The href of the new stylesheet to include
13190 swapStyleSheet : function(id, url){
13191 this.removeStyleSheet(id);
13192 var ss = doc.createElement("link");
13193 ss.setAttribute("rel", "stylesheet");
13194 ss.setAttribute("type", "text/css");
13195 ss.setAttribute("id", id);
13196 ss.setAttribute("href", url);
13197 doc.getElementsByTagName("head")[0].appendChild(ss);
13201 * Refresh the rule cache if you have dynamically added stylesheets
13202 * @return {Object} An object (hash) of rules indexed by selector
13204 refreshCache : function(){
13205 return this.getRules(true);
13209 cacheStyleSheet : function(ss){
13213 try{// try catch for cross domain access issue
13214 var ssRules = ss.cssRules || ss.rules;
13215 for(var j = ssRules.length-1; j >= 0; --j){
13216 rules[ssRules[j].selectorText] = ssRules[j];
13222 * Gets all css rules for the document
13223 * @param {Boolean} refreshCache true to refresh the internal cache
13224 * @return {Object} An object (hash) of rules indexed by selector
13226 getRules : function(refreshCache){
13227 if(rules == null || refreshCache){
13229 var ds = doc.styleSheets;
13230 for(var i =0, len = ds.length; i < len; i++){
13232 this.cacheStyleSheet(ds[i]);
13240 * Gets an an individual CSS rule by selector(s)
13241 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13242 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13243 * @return {CSSRule} The CSS rule or null if one is not found
13245 getRule : function(selector, refreshCache){
13246 var rs = this.getRules(refreshCache);
13247 if(!(selector instanceof Array)){
13248 return rs[selector];
13250 for(var i = 0; i < selector.length; i++){
13251 if(rs[selector[i]]){
13252 return rs[selector[i]];
13260 * Updates a rule property
13261 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13262 * @param {String} property The css property
13263 * @param {String} value The new value for the property
13264 * @return {Boolean} true If a rule was found and updated
13266 updateRule : function(selector, property, value){
13267 if(!(selector instanceof Array)){
13268 var rule = this.getRule(selector);
13270 rule.style[property.replace(camelRe, camelFn)] = value;
13274 for(var i = 0; i < selector.length; i++){
13275 if(this.updateRule(selector[i], property, value)){
13285 * Ext JS Library 1.1.1
13286 * Copyright(c) 2006-2007, Ext JS, LLC.
13288 * Originally Released Under LGPL - original licence link has changed is not relivant.
13291 * <script type="text/javascript">
13297 * @class Roo.util.ClickRepeater
13298 * @extends Roo.util.Observable
13300 * A wrapper class which can be applied to any element. Fires a "click" event while the
13301 * mouse is pressed. The interval between firings may be specified in the config but
13302 * defaults to 10 milliseconds.
13304 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13306 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13307 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13308 * Similar to an autorepeat key delay.
13309 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13310 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13311 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13312 * "interval" and "delay" are ignored. "immediate" is honored.
13313 * @cfg {Boolean} preventDefault True to prevent the default click event
13314 * @cfg {Boolean} stopDefault True to stop the default click event
13317 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13318 * 2007-02-02 jvs Renamed to ClickRepeater
13319 * 2007-02-03 jvs Modifications for FF Mac and Safari
13322 * @param {String/HTMLElement/Element} el The element to listen on
13323 * @param {Object} config
13325 Roo.util.ClickRepeater = function(el, config)
13327 this.el = Roo.get(el);
13328 this.el.unselectable();
13330 Roo.apply(this, config);
13335 * Fires when the mouse button is depressed.
13336 * @param {Roo.util.ClickRepeater} this
13338 "mousedown" : true,
13341 * Fires on a specified interval during the time the element is pressed.
13342 * @param {Roo.util.ClickRepeater} this
13347 * Fires when the mouse key is released.
13348 * @param {Roo.util.ClickRepeater} this
13353 this.el.on("mousedown", this.handleMouseDown, this);
13354 if(this.preventDefault || this.stopDefault){
13355 this.el.on("click", function(e){
13356 if(this.preventDefault){
13357 e.preventDefault();
13359 if(this.stopDefault){
13365 // allow inline handler
13367 this.on("click", this.handler, this.scope || this);
13370 Roo.util.ClickRepeater.superclass.constructor.call(this);
13373 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13376 preventDefault : true,
13377 stopDefault : false,
13381 handleMouseDown : function(){
13382 clearTimeout(this.timer);
13384 if(this.pressClass){
13385 this.el.addClass(this.pressClass);
13387 this.mousedownTime = new Date();
13389 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13390 this.el.on("mouseout", this.handleMouseOut, this);
13392 this.fireEvent("mousedown", this);
13393 this.fireEvent("click", this);
13395 this.timer = this.click.defer(this.delay || this.interval, this);
13399 click : function(){
13400 this.fireEvent("click", this);
13401 this.timer = this.click.defer(this.getInterval(), this);
13405 getInterval: function(){
13406 if(!this.accelerate){
13407 return this.interval;
13409 var pressTime = this.mousedownTime.getElapsed();
13410 if(pressTime < 500){
13412 }else if(pressTime < 1700){
13414 }else if(pressTime < 2600){
13416 }else if(pressTime < 3500){
13418 }else if(pressTime < 4400){
13420 }else if(pressTime < 5300){
13422 }else if(pressTime < 6200){
13430 handleMouseOut : function(){
13431 clearTimeout(this.timer);
13432 if(this.pressClass){
13433 this.el.removeClass(this.pressClass);
13435 this.el.on("mouseover", this.handleMouseReturn, this);
13439 handleMouseReturn : function(){
13440 this.el.un("mouseover", this.handleMouseReturn);
13441 if(this.pressClass){
13442 this.el.addClass(this.pressClass);
13448 handleMouseUp : function(){
13449 clearTimeout(this.timer);
13450 this.el.un("mouseover", this.handleMouseReturn);
13451 this.el.un("mouseout", this.handleMouseOut);
13452 Roo.get(document).un("mouseup", this.handleMouseUp);
13453 this.el.removeClass(this.pressClass);
13454 this.fireEvent("mouseup", this);
13458 * Ext JS Library 1.1.1
13459 * Copyright(c) 2006-2007, Ext JS, LLC.
13461 * Originally Released Under LGPL - original licence link has changed is not relivant.
13464 * <script type="text/javascript">
13469 * @class Roo.KeyNav
13470 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13471 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13472 * way to implement custom navigation schemes for any UI component.</p>
13473 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13474 * pageUp, pageDown, del, home, end. Usage:</p>
13476 var nav = new Roo.KeyNav("my-element", {
13477 "left" : function(e){
13478 this.moveLeft(e.ctrlKey);
13480 "right" : function(e){
13481 this.moveRight(e.ctrlKey);
13483 "enter" : function(e){
13490 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13491 * @param {Object} config The config
13493 Roo.KeyNav = function(el, config){
13494 this.el = Roo.get(el);
13495 Roo.apply(this, config);
13496 if(!this.disabled){
13497 this.disabled = true;
13502 Roo.KeyNav.prototype = {
13504 * @cfg {Boolean} disabled
13505 * True to disable this KeyNav instance (defaults to false)
13509 * @cfg {String} defaultEventAction
13510 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13511 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13512 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13514 defaultEventAction: "stopEvent",
13516 * @cfg {Boolean} forceKeyDown
13517 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13518 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13519 * handle keydown instead of keypress.
13521 forceKeyDown : false,
13524 prepareEvent : function(e){
13525 var k = e.getKey();
13526 var h = this.keyToHandler[k];
13527 //if(h && this[h]){
13528 // e.stopPropagation();
13530 if(Roo.isSafari && h && k >= 37 && k <= 40){
13536 relay : function(e){
13537 var k = e.getKey();
13538 var h = this.keyToHandler[k];
13540 if(this.doRelay(e, this[h], h) !== true){
13541 e[this.defaultEventAction]();
13547 doRelay : function(e, h, hname){
13548 return h.call(this.scope || this, e);
13551 // possible handlers
13565 // quick lookup hash
13582 * Enable this KeyNav
13584 enable: function(){
13586 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13587 // the EventObject will normalize Safari automatically
13588 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13589 this.el.on("keydown", this.relay, this);
13591 this.el.on("keydown", this.prepareEvent, this);
13592 this.el.on("keypress", this.relay, this);
13594 this.disabled = false;
13599 * Disable this KeyNav
13601 disable: function(){
13602 if(!this.disabled){
13603 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13604 this.el.un("keydown", this.relay);
13606 this.el.un("keydown", this.prepareEvent);
13607 this.el.un("keypress", this.relay);
13609 this.disabled = true;
13614 * Ext JS Library 1.1.1
13615 * Copyright(c) 2006-2007, Ext JS, LLC.
13617 * Originally Released Under LGPL - original licence link has changed is not relivant.
13620 * <script type="text/javascript">
13625 * @class Roo.KeyMap
13626 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13627 * The constructor accepts the same config object as defined by {@link #addBinding}.
13628 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13629 * combination it will call the function with this signature (if the match is a multi-key
13630 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13631 * A KeyMap can also handle a string representation of keys.<br />
13634 // map one key by key code
13635 var map = new Roo.KeyMap("my-element", {
13636 key: 13, // or Roo.EventObject.ENTER
13641 // map multiple keys to one action by string
13642 var map = new Roo.KeyMap("my-element", {
13648 // map multiple keys to multiple actions by strings and array of codes
13649 var map = new Roo.KeyMap("my-element", [
13652 fn: function(){ alert("Return was pressed"); }
13655 fn: function(){ alert('a, b or c was pressed'); }
13660 fn: function(){ alert('Control + shift + tab was pressed.'); }
13664 * <b>Note: A KeyMap starts enabled</b>
13666 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13667 * @param {Object} config The config (see {@link #addBinding})
13668 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13670 Roo.KeyMap = function(el, config, eventName){
13671 this.el = Roo.get(el);
13672 this.eventName = eventName || "keydown";
13673 this.bindings = [];
13675 this.addBinding(config);
13680 Roo.KeyMap.prototype = {
13682 * True to stop the event from bubbling and prevent the default browser action if the
13683 * key was handled by the KeyMap (defaults to false)
13689 * Add a new binding to this KeyMap. The following config object properties are supported:
13691 Property Type Description
13692 ---------- --------------- ----------------------------------------------------------------------
13693 key String/Array A single keycode or an array of keycodes to handle
13694 shift Boolean True to handle key only when shift is pressed (defaults to false)
13695 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13696 alt Boolean True to handle key only when alt is pressed (defaults to false)
13697 fn Function The function to call when KeyMap finds the expected key combination
13698 scope Object The scope of the callback function
13704 var map = new Roo.KeyMap(document, {
13705 key: Roo.EventObject.ENTER,
13710 //Add a new binding to the existing KeyMap later
13718 * @param {Object/Array} config A single KeyMap config or an array of configs
13720 addBinding : function(config){
13721 if(config instanceof Array){
13722 for(var i = 0, len = config.length; i < len; i++){
13723 this.addBinding(config[i]);
13727 var keyCode = config.key,
13728 shift = config.shift,
13729 ctrl = config.ctrl,
13732 scope = config.scope;
13733 if(typeof keyCode == "string"){
13735 var keyString = keyCode.toUpperCase();
13736 for(var j = 0, len = keyString.length; j < len; j++){
13737 ks.push(keyString.charCodeAt(j));
13741 var keyArray = keyCode instanceof Array;
13742 var handler = function(e){
13743 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13744 var k = e.getKey();
13746 for(var i = 0, len = keyCode.length; i < len; i++){
13747 if(keyCode[i] == k){
13748 if(this.stopEvent){
13751 fn.call(scope || window, k, e);
13757 if(this.stopEvent){
13760 fn.call(scope || window, k, e);
13765 this.bindings.push(handler);
13769 * Shorthand for adding a single key listener
13770 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13771 * following options:
13772 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13773 * @param {Function} fn The function to call
13774 * @param {Object} scope (optional) The scope of the function
13776 on : function(key, fn, scope){
13777 var keyCode, shift, ctrl, alt;
13778 if(typeof key == "object" && !(key instanceof Array)){
13797 handleKeyDown : function(e){
13798 if(this.enabled){ //just in case
13799 var b = this.bindings;
13800 for(var i = 0, len = b.length; i < len; i++){
13801 b[i].call(this, e);
13807 * Returns true if this KeyMap is enabled
13808 * @return {Boolean}
13810 isEnabled : function(){
13811 return this.enabled;
13815 * Enables this KeyMap
13817 enable: function(){
13819 this.el.on(this.eventName, this.handleKeyDown, this);
13820 this.enabled = true;
13825 * Disable this KeyMap
13827 disable: function(){
13829 this.el.removeListener(this.eventName, this.handleKeyDown, this);
13830 this.enabled = false;
13835 * Ext JS Library 1.1.1
13836 * Copyright(c) 2006-2007, Ext JS, LLC.
13838 * Originally Released Under LGPL - original licence link has changed is not relivant.
13841 * <script type="text/javascript">
13846 * @class Roo.util.TextMetrics
13847 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13848 * wide, in pixels, a given block of text will be.
13851 Roo.util.TextMetrics = function(){
13855 * Measures the size of the specified text
13856 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13857 * that can affect the size of the rendered text
13858 * @param {String} text The text to measure
13859 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13860 * in order to accurately measure the text height
13861 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13863 measure : function(el, text, fixedWidth){
13865 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13868 shared.setFixedWidth(fixedWidth || 'auto');
13869 return shared.getSize(text);
13873 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13874 * the overhead of multiple calls to initialize the style properties on each measurement.
13875 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13876 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13877 * in order to accurately measure the text height
13878 * @return {Roo.util.TextMetrics.Instance} instance The new instance
13880 createInstance : function(el, fixedWidth){
13881 return Roo.util.TextMetrics.Instance(el, fixedWidth);
13888 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13889 var ml = new Roo.Element(document.createElement('div'));
13890 document.body.appendChild(ml.dom);
13891 ml.position('absolute');
13892 ml.setLeftTop(-1000, -1000);
13896 ml.setWidth(fixedWidth);
13901 * Returns the size of the specified text based on the internal element's style and width properties
13902 * @memberOf Roo.util.TextMetrics.Instance#
13903 * @param {String} text The text to measure
13904 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13906 getSize : function(text){
13908 var s = ml.getSize();
13914 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13915 * that can affect the size of the rendered text
13916 * @memberOf Roo.util.TextMetrics.Instance#
13917 * @param {String/HTMLElement} el The element, dom node or id
13919 bind : function(el){
13921 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13926 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
13927 * to set a fixed width in order to accurately measure the text height.
13928 * @memberOf Roo.util.TextMetrics.Instance#
13929 * @param {Number} width The width to set on the element
13931 setFixedWidth : function(width){
13932 ml.setWidth(width);
13936 * Returns the measured width of the specified text
13937 * @memberOf Roo.util.TextMetrics.Instance#
13938 * @param {String} text The text to measure
13939 * @return {Number} width The width in pixels
13941 getWidth : function(text){
13942 ml.dom.style.width = 'auto';
13943 return this.getSize(text).width;
13947 * Returns the measured height of the specified text. For multiline text, be sure to call
13948 * {@link #setFixedWidth} if necessary.
13949 * @memberOf Roo.util.TextMetrics.Instance#
13950 * @param {String} text The text to measure
13951 * @return {Number} height The height in pixels
13953 getHeight : function(text){
13954 return this.getSize(text).height;
13958 instance.bind(bindTo);
13963 // backwards compat
13964 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13966 * Ext JS Library 1.1.1
13967 * Copyright(c) 2006-2007, Ext JS, LLC.
13969 * Originally Released Under LGPL - original licence link has changed is not relivant.
13972 * <script type="text/javascript">
13976 * @class Roo.state.Provider
13977 * Abstract base class for state provider implementations. This class provides methods
13978 * for encoding and decoding <b>typed</b> variables including dates and defines the
13979 * Provider interface.
13981 Roo.state.Provider = function(){
13983 * @event statechange
13984 * Fires when a state change occurs.
13985 * @param {Provider} this This state provider
13986 * @param {String} key The state key which was changed
13987 * @param {String} value The encoded value for the state
13990 "statechange": true
13993 Roo.state.Provider.superclass.constructor.call(this);
13995 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
13997 * Returns the current value for a key
13998 * @param {String} name The key name
13999 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14000 * @return {Mixed} The state data
14002 get : function(name, defaultValue){
14003 return typeof this.state[name] == "undefined" ?
14004 defaultValue : this.state[name];
14008 * Clears a value from the state
14009 * @param {String} name The key name
14011 clear : function(name){
14012 delete this.state[name];
14013 this.fireEvent("statechange", this, name, null);
14017 * Sets the value for a key
14018 * @param {String} name The key name
14019 * @param {Mixed} value The value to set
14021 set : function(name, value){
14022 this.state[name] = value;
14023 this.fireEvent("statechange", this, name, value);
14027 * Decodes a string previously encoded with {@link #encodeValue}.
14028 * @param {String} value The value to decode
14029 * @return {Mixed} The decoded value
14031 decodeValue : function(cookie){
14032 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14033 var matches = re.exec(unescape(cookie));
14034 if(!matches || !matches[1]) return; // non state cookie
14035 var type = matches[1];
14036 var v = matches[2];
14039 return parseFloat(v);
14041 return new Date(Date.parse(v));
14046 var values = v.split("^");
14047 for(var i = 0, len = values.length; i < len; i++){
14048 all.push(this.decodeValue(values[i]));
14053 var values = v.split("^");
14054 for(var i = 0, len = values.length; i < len; i++){
14055 var kv = values[i].split("=");
14056 all[kv[0]] = this.decodeValue(kv[1]);
14065 * Encodes a value including type information. Decode with {@link #decodeValue}.
14066 * @param {Mixed} value The value to encode
14067 * @return {String} The encoded value
14069 encodeValue : function(v){
14071 if(typeof v == "number"){
14073 }else if(typeof v == "boolean"){
14074 enc = "b:" + (v ? "1" : "0");
14075 }else if(v instanceof Date){
14076 enc = "d:" + v.toGMTString();
14077 }else if(v instanceof Array){
14079 for(var i = 0, len = v.length; i < len; i++){
14080 flat += this.encodeValue(v[i]);
14081 if(i != len-1) flat += "^";
14084 }else if(typeof v == "object"){
14087 if(typeof v[key] != "function"){
14088 flat += key + "=" + this.encodeValue(v[key]) + "^";
14091 enc = "o:" + flat.substring(0, flat.length-1);
14095 return escape(enc);
14101 * Ext JS Library 1.1.1
14102 * Copyright(c) 2006-2007, Ext JS, LLC.
14104 * Originally Released Under LGPL - original licence link has changed is not relivant.
14107 * <script type="text/javascript">
14110 * @class Roo.state.Manager
14111 * This is the global state manager. By default all components that are "state aware" check this class
14112 * for state information if you don't pass them a custom state provider. In order for this class
14113 * to be useful, it must be initialized with a provider when your application initializes.
14115 // in your initialization function
14117 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14119 // supposed you have a {@link Roo.BorderLayout}
14120 var layout = new Roo.BorderLayout(...);
14121 layout.restoreState();
14122 // or a {Roo.BasicDialog}
14123 var dialog = new Roo.BasicDialog(...);
14124 dialog.restoreState();
14128 Roo.state.Manager = function(){
14129 var provider = new Roo.state.Provider();
14133 * Configures the default state provider for your application
14134 * @param {Provider} stateProvider The state provider to set
14136 setProvider : function(stateProvider){
14137 provider = stateProvider;
14141 * Returns the current value for a key
14142 * @param {String} name The key name
14143 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14144 * @return {Mixed} The state data
14146 get : function(key, defaultValue){
14147 return provider.get(key, defaultValue);
14151 * Sets the value for a key
14152 * @param {String} name The key name
14153 * @param {Mixed} value The state data
14155 set : function(key, value){
14156 provider.set(key, value);
14160 * Clears a value from the state
14161 * @param {String} name The key name
14163 clear : function(key){
14164 provider.clear(key);
14168 * Gets the currently configured state provider
14169 * @return {Provider} The state provider
14171 getProvider : function(){
14178 * Ext JS Library 1.1.1
14179 * Copyright(c) 2006-2007, Ext JS, LLC.
14181 * Originally Released Under LGPL - original licence link has changed is not relivant.
14184 * <script type="text/javascript">
14187 * @class Roo.state.CookieProvider
14188 * @extends Roo.state.Provider
14189 * The default Provider implementation which saves state via cookies.
14192 var cp = new Roo.state.CookieProvider({
14194 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14195 domain: "roojs.com"
14197 Roo.state.Manager.setProvider(cp);
14199 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14200 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14201 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14202 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14203 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14204 * domain the page is running on including the 'www' like 'www.roojs.com')
14205 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14207 * Create a new CookieProvider
14208 * @param {Object} config The configuration object
14210 Roo.state.CookieProvider = function(config){
14211 Roo.state.CookieProvider.superclass.constructor.call(this);
14213 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14214 this.domain = null;
14215 this.secure = false;
14216 Roo.apply(this, config);
14217 this.state = this.readCookies();
14220 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14222 set : function(name, value){
14223 if(typeof value == "undefined" || value === null){
14227 this.setCookie(name, value);
14228 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14232 clear : function(name){
14233 this.clearCookie(name);
14234 Roo.state.CookieProvider.superclass.clear.call(this, name);
14238 readCookies : function(){
14240 var c = document.cookie + ";";
14241 var re = /\s?(.*?)=(.*?);/g;
14243 while((matches = re.exec(c)) != null){
14244 var name = matches[1];
14245 var value = matches[2];
14246 if(name && name.substring(0,3) == "ys-"){
14247 cookies[name.substr(3)] = this.decodeValue(value);
14254 setCookie : function(name, value){
14255 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14256 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14257 ((this.path == null) ? "" : ("; path=" + this.path)) +
14258 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14259 ((this.secure == true) ? "; secure" : "");
14263 clearCookie : function(name){
14264 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14265 ((this.path == null) ? "" : ("; path=" + this.path)) +
14266 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14267 ((this.secure == true) ? "; secure" : "");
14271 * Ext JS Library 1.1.1
14272 * Copyright(c) 2006-2007, Ext JS, LLC.
14274 * Originally Released Under LGPL - original licence link has changed is not relivant.
14277 * <script type="text/javascript">
14283 * These classes are derivatives of the similarly named classes in the YUI Library.
14284 * The original license:
14285 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14286 * Code licensed under the BSD License:
14287 * http://developer.yahoo.net/yui/license.txt
14292 var Event=Roo.EventManager;
14293 var Dom=Roo.lib.Dom;
14296 * @class Roo.dd.DragDrop
14297 * Defines the interface and base operation of items that that can be
14298 * dragged or can be drop targets. It was designed to be extended, overriding
14299 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14300 * Up to three html elements can be associated with a DragDrop instance:
14302 * <li>linked element: the element that is passed into the constructor.
14303 * This is the element which defines the boundaries for interaction with
14304 * other DragDrop objects.</li>
14305 * <li>handle element(s): The drag operation only occurs if the element that
14306 * was clicked matches a handle element. By default this is the linked
14307 * element, but there are times that you will want only a portion of the
14308 * linked element to initiate the drag operation, and the setHandleElId()
14309 * method provides a way to define this.</li>
14310 * <li>drag element: this represents the element that would be moved along
14311 * with the cursor during a drag operation. By default, this is the linked
14312 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14313 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14316 * This class should not be instantiated until the onload event to ensure that
14317 * the associated elements are available.
14318 * The following would define a DragDrop obj that would interact with any
14319 * other DragDrop obj in the "group1" group:
14321 * dd = new Roo.dd.DragDrop("div1", "group1");
14323 * Since none of the event handlers have been implemented, nothing would
14324 * actually happen if you were to run the code above. Normally you would
14325 * override this class or one of the default implementations, but you can
14326 * also override the methods you want on an instance of the class...
14328 * dd.onDragDrop = function(e, id) {
14329 * alert("dd was dropped on " + id);
14333 * @param {String} id of the element that is linked to this instance
14334 * @param {String} sGroup the group of related DragDrop objects
14335 * @param {object} config an object containing configurable attributes
14336 * Valid properties for DragDrop:
14337 * padding, isTarget, maintainOffset, primaryButtonOnly
14339 Roo.dd.DragDrop = function(id, sGroup, config) {
14341 this.init(id, sGroup, config);
14345 Roo.dd.DragDrop.prototype = {
14348 * The id of the element associated with this object. This is what we
14349 * refer to as the "linked element" because the size and position of
14350 * this element is used to determine when the drag and drop objects have
14358 * Configuration attributes passed into the constructor
14365 * The id of the element that will be dragged. By default this is same
14366 * as the linked element , but could be changed to another element. Ex:
14368 * @property dragElId
14375 * the id of the element that initiates the drag operation. By default
14376 * this is the linked element, but could be changed to be a child of this
14377 * element. This lets us do things like only starting the drag when the
14378 * header element within the linked html element is clicked.
14379 * @property handleElId
14386 * An associative array of HTML tags that will be ignored if clicked.
14387 * @property invalidHandleTypes
14388 * @type {string: string}
14390 invalidHandleTypes: null,
14393 * An associative array of ids for elements that will be ignored if clicked
14394 * @property invalidHandleIds
14395 * @type {string: string}
14397 invalidHandleIds: null,
14400 * An indexted array of css class names for elements that will be ignored
14402 * @property invalidHandleClasses
14405 invalidHandleClasses: null,
14408 * The linked element's absolute X position at the time the drag was
14410 * @property startPageX
14417 * The linked element's absolute X position at the time the drag was
14419 * @property startPageY
14426 * The group defines a logical collection of DragDrop objects that are
14427 * related. Instances only get events when interacting with other
14428 * DragDrop object in the same group. This lets us define multiple
14429 * groups using a single DragDrop subclass if we want.
14431 * @type {string: string}
14436 * Individual drag/drop instances can be locked. This will prevent
14437 * onmousedown start drag.
14445 * Lock this instance
14448 lock: function() { this.locked = true; },
14451 * Unlock this instace
14454 unlock: function() { this.locked = false; },
14457 * By default, all insances can be a drop target. This can be disabled by
14458 * setting isTarget to false.
14465 * The padding configured for this drag and drop object for calculating
14466 * the drop zone intersection with this object.
14473 * Cached reference to the linked element
14474 * @property _domRef
14480 * Internal typeof flag
14481 * @property __ygDragDrop
14484 __ygDragDrop: true,
14487 * Set to true when horizontal contraints are applied
14488 * @property constrainX
14495 * Set to true when vertical contraints are applied
14496 * @property constrainY
14503 * The left constraint
14511 * The right constraint
14519 * The up constraint
14528 * The down constraint
14536 * Maintain offsets when we resetconstraints. Set to true when you want
14537 * the position of the element relative to its parent to stay the same
14538 * when the page changes
14540 * @property maintainOffset
14543 maintainOffset: false,
14546 * Array of pixel locations the element will snap to if we specified a
14547 * horizontal graduation/interval. This array is generated automatically
14548 * when you define a tick interval.
14555 * Array of pixel locations the element will snap to if we specified a
14556 * vertical graduation/interval. This array is generated automatically
14557 * when you define a tick interval.
14564 * By default the drag and drop instance will only respond to the primary
14565 * button click (left button for a right-handed mouse). Set to true to
14566 * allow drag and drop to start with any mouse click that is propogated
14568 * @property primaryButtonOnly
14571 primaryButtonOnly: true,
14574 * The availabe property is false until the linked dom element is accessible.
14575 * @property available
14581 * By default, drags can only be initiated if the mousedown occurs in the
14582 * region the linked element is. This is done in part to work around a
14583 * bug in some browsers that mis-report the mousedown if the previous
14584 * mouseup happened outside of the window. This property is set to true
14585 * if outer handles are defined.
14587 * @property hasOuterHandles
14591 hasOuterHandles: false,
14594 * Code that executes immediately before the startDrag event
14595 * @method b4StartDrag
14598 b4StartDrag: function(x, y) { },
14601 * Abstract method called after a drag/drop object is clicked
14602 * and the drag or mousedown time thresholds have beeen met.
14603 * @method startDrag
14604 * @param {int} X click location
14605 * @param {int} Y click location
14607 startDrag: function(x, y) { /* override this */ },
14610 * Code that executes immediately before the onDrag event
14614 b4Drag: function(e) { },
14617 * Abstract method called during the onMouseMove event while dragging an
14620 * @param {Event} e the mousemove event
14622 onDrag: function(e) { /* override this */ },
14625 * Abstract method called when this element fist begins hovering over
14626 * another DragDrop obj
14627 * @method onDragEnter
14628 * @param {Event} e the mousemove event
14629 * @param {String|DragDrop[]} id In POINT mode, the element
14630 * id this is hovering over. In INTERSECT mode, an array of one or more
14631 * dragdrop items being hovered over.
14633 onDragEnter: function(e, id) { /* override this */ },
14636 * Code that executes immediately before the onDragOver event
14637 * @method b4DragOver
14640 b4DragOver: function(e) { },
14643 * Abstract method called when this element is hovering over another
14645 * @method onDragOver
14646 * @param {Event} e the mousemove event
14647 * @param {String|DragDrop[]} id In POINT mode, the element
14648 * id this is hovering over. In INTERSECT mode, an array of dd items
14649 * being hovered over.
14651 onDragOver: function(e, id) { /* override this */ },
14654 * Code that executes immediately before the onDragOut event
14655 * @method b4DragOut
14658 b4DragOut: function(e) { },
14661 * Abstract method called when we are no longer hovering over an element
14662 * @method onDragOut
14663 * @param {Event} e the mousemove event
14664 * @param {String|DragDrop[]} id In POINT mode, the element
14665 * id this was hovering over. In INTERSECT mode, an array of dd items
14666 * that the mouse is no longer over.
14668 onDragOut: function(e, id) { /* override this */ },
14671 * Code that executes immediately before the onDragDrop event
14672 * @method b4DragDrop
14675 b4DragDrop: function(e) { },
14678 * Abstract method called when this item is dropped on another DragDrop
14680 * @method onDragDrop
14681 * @param {Event} e the mouseup event
14682 * @param {String|DragDrop[]} id In POINT mode, the element
14683 * id this was dropped on. In INTERSECT mode, an array of dd items this
14686 onDragDrop: function(e, id) { /* override this */ },
14689 * Abstract method called when this item is dropped on an area with no
14691 * @method onInvalidDrop
14692 * @param {Event} e the mouseup event
14694 onInvalidDrop: function(e) { /* override this */ },
14697 * Code that executes immediately before the endDrag event
14698 * @method b4EndDrag
14701 b4EndDrag: function(e) { },
14704 * Fired when we are done dragging the object
14706 * @param {Event} e the mouseup event
14708 endDrag: function(e) { /* override this */ },
14711 * Code executed immediately before the onMouseDown event
14712 * @method b4MouseDown
14713 * @param {Event} e the mousedown event
14716 b4MouseDown: function(e) { },
14719 * Event handler that fires when a drag/drop obj gets a mousedown
14720 * @method onMouseDown
14721 * @param {Event} e the mousedown event
14723 onMouseDown: function(e) { /* override this */ },
14726 * Event handler that fires when a drag/drop obj gets a mouseup
14727 * @method onMouseUp
14728 * @param {Event} e the mouseup event
14730 onMouseUp: function(e) { /* override this */ },
14733 * Override the onAvailable method to do what is needed after the initial
14734 * position was determined.
14735 * @method onAvailable
14737 onAvailable: function () {
14741 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14744 defaultPadding : {left:0, right:0, top:0, bottom:0},
14747 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14751 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14752 { dragElId: "existingProxyDiv" });
14753 dd.startDrag = function(){
14754 this.constrainTo("parent-id");
14757 * Or you can initalize it using the {@link Roo.Element} object:
14759 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14760 startDrag : function(){
14761 this.constrainTo("parent-id");
14765 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14766 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14767 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14768 * an object containing the sides to pad. For example: {right:10, bottom:10}
14769 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14771 constrainTo : function(constrainTo, pad, inContent){
14772 if(typeof pad == "number"){
14773 pad = {left: pad, right:pad, top:pad, bottom:pad};
14775 pad = pad || this.defaultPadding;
14776 var b = Roo.get(this.getEl()).getBox();
14777 var ce = Roo.get(constrainTo);
14778 var s = ce.getScroll();
14779 var c, cd = ce.dom;
14780 if(cd == document.body){
14781 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14784 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14788 var topSpace = b.y - c.y;
14789 var leftSpace = b.x - c.x;
14791 this.resetConstraints();
14792 this.setXConstraint(leftSpace - (pad.left||0), // left
14793 c.width - leftSpace - b.width - (pad.right||0) //right
14795 this.setYConstraint(topSpace - (pad.top||0), //top
14796 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14801 * Returns a reference to the linked element
14803 * @return {HTMLElement} the html element
14805 getEl: function() {
14806 if (!this._domRef) {
14807 this._domRef = Roo.getDom(this.id);
14810 return this._domRef;
14814 * Returns a reference to the actual element to drag. By default this is
14815 * the same as the html element, but it can be assigned to another
14816 * element. An example of this can be found in Roo.dd.DDProxy
14817 * @method getDragEl
14818 * @return {HTMLElement} the html element
14820 getDragEl: function() {
14821 return Roo.getDom(this.dragElId);
14825 * Sets up the DragDrop object. Must be called in the constructor of any
14826 * Roo.dd.DragDrop subclass
14828 * @param id the id of the linked element
14829 * @param {String} sGroup the group of related items
14830 * @param {object} config configuration attributes
14832 init: function(id, sGroup, config) {
14833 this.initTarget(id, sGroup, config);
14834 Event.on(this.id, "mousedown", this.handleMouseDown, this);
14835 // Event.on(this.id, "selectstart", Event.preventDefault);
14839 * Initializes Targeting functionality only... the object does not
14840 * get a mousedown handler.
14841 * @method initTarget
14842 * @param id the id of the linked element
14843 * @param {String} sGroup the group of related items
14844 * @param {object} config configuration attributes
14846 initTarget: function(id, sGroup, config) {
14848 // configuration attributes
14849 this.config = config || {};
14851 // create a local reference to the drag and drop manager
14852 this.DDM = Roo.dd.DDM;
14853 // initialize the groups array
14856 // assume that we have an element reference instead of an id if the
14857 // parameter is not a string
14858 if (typeof id !== "string") {
14865 // add to an interaction group
14866 this.addToGroup((sGroup) ? sGroup : "default");
14868 // We don't want to register this as the handle with the manager
14869 // so we just set the id rather than calling the setter.
14870 this.handleElId = id;
14872 // the linked element is the element that gets dragged by default
14873 this.setDragElId(id);
14875 // by default, clicked anchors will not start drag operations.
14876 this.invalidHandleTypes = { A: "A" };
14877 this.invalidHandleIds = {};
14878 this.invalidHandleClasses = [];
14880 this.applyConfig();
14882 this.handleOnAvailable();
14886 * Applies the configuration parameters that were passed into the constructor.
14887 * This is supposed to happen at each level through the inheritance chain. So
14888 * a DDProxy implentation will execute apply config on DDProxy, DD, and
14889 * DragDrop in order to get all of the parameters that are available in
14891 * @method applyConfig
14893 applyConfig: function() {
14895 // configurable properties:
14896 // padding, isTarget, maintainOffset, primaryButtonOnly
14897 this.padding = this.config.padding || [0, 0, 0, 0];
14898 this.isTarget = (this.config.isTarget !== false);
14899 this.maintainOffset = (this.config.maintainOffset);
14900 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
14905 * Executed when the linked element is available
14906 * @method handleOnAvailable
14909 handleOnAvailable: function() {
14910 this.available = true;
14911 this.resetConstraints();
14912 this.onAvailable();
14916 * Configures the padding for the target zone in px. Effectively expands
14917 * (or reduces) the virtual object size for targeting calculations.
14918 * Supports css-style shorthand; if only one parameter is passed, all sides
14919 * will have that padding, and if only two are passed, the top and bottom
14920 * will have the first param, the left and right the second.
14921 * @method setPadding
14922 * @param {int} iTop Top pad
14923 * @param {int} iRight Right pad
14924 * @param {int} iBot Bot pad
14925 * @param {int} iLeft Left pad
14927 setPadding: function(iTop, iRight, iBot, iLeft) {
14928 // this.padding = [iLeft, iRight, iTop, iBot];
14929 if (!iRight && 0 !== iRight) {
14930 this.padding = [iTop, iTop, iTop, iTop];
14931 } else if (!iBot && 0 !== iBot) {
14932 this.padding = [iTop, iRight, iTop, iRight];
14934 this.padding = [iTop, iRight, iBot, iLeft];
14939 * Stores the initial placement of the linked element.
14940 * @method setInitialPosition
14941 * @param {int} diffX the X offset, default 0
14942 * @param {int} diffY the Y offset, default 0
14944 setInitPosition: function(diffX, diffY) {
14945 var el = this.getEl();
14947 if (!this.DDM.verifyEl(el)) {
14951 var dx = diffX || 0;
14952 var dy = diffY || 0;
14954 var p = Dom.getXY( el );
14956 this.initPageX = p[0] - dx;
14957 this.initPageY = p[1] - dy;
14959 this.lastPageX = p[0];
14960 this.lastPageY = p[1];
14963 this.setStartPosition(p);
14967 * Sets the start position of the element. This is set when the obj
14968 * is initialized, the reset when a drag is started.
14969 * @method setStartPosition
14970 * @param pos current position (from previous lookup)
14973 setStartPosition: function(pos) {
14974 var p = pos || Dom.getXY( this.getEl() );
14975 this.deltaSetXY = null;
14977 this.startPageX = p[0];
14978 this.startPageY = p[1];
14982 * Add this instance to a group of related drag/drop objects. All
14983 * instances belong to at least one group, and can belong to as many
14984 * groups as needed.
14985 * @method addToGroup
14986 * @param sGroup {string} the name of the group
14988 addToGroup: function(sGroup) {
14989 this.groups[sGroup] = true;
14990 this.DDM.regDragDrop(this, sGroup);
14994 * Remove's this instance from the supplied interaction group
14995 * @method removeFromGroup
14996 * @param {string} sGroup The group to drop
14998 removeFromGroup: function(sGroup) {
14999 if (this.groups[sGroup]) {
15000 delete this.groups[sGroup];
15003 this.DDM.removeDDFromGroup(this, sGroup);
15007 * Allows you to specify that an element other than the linked element
15008 * will be moved with the cursor during a drag
15009 * @method setDragElId
15010 * @param id {string} the id of the element that will be used to initiate the drag
15012 setDragElId: function(id) {
15013 this.dragElId = id;
15017 * Allows you to specify a child of the linked element that should be
15018 * used to initiate the drag operation. An example of this would be if
15019 * you have a content div with text and links. Clicking anywhere in the
15020 * content area would normally start the drag operation. Use this method
15021 * to specify that an element inside of the content div is the element
15022 * that starts the drag operation.
15023 * @method setHandleElId
15024 * @param id {string} the id of the element that will be used to
15025 * initiate the drag.
15027 setHandleElId: function(id) {
15028 if (typeof id !== "string") {
15031 this.handleElId = id;
15032 this.DDM.regHandle(this.id, id);
15036 * Allows you to set an element outside of the linked element as a drag
15038 * @method setOuterHandleElId
15039 * @param id the id of the element that will be used to initiate the drag
15041 setOuterHandleElId: function(id) {
15042 if (typeof id !== "string") {
15045 Event.on(id, "mousedown",
15046 this.handleMouseDown, this);
15047 this.setHandleElId(id);
15049 this.hasOuterHandles = true;
15053 * Remove all drag and drop hooks for this element
15056 unreg: function() {
15057 Event.un(this.id, "mousedown",
15058 this.handleMouseDown);
15059 this._domRef = null;
15060 this.DDM._remove(this);
15063 destroy : function(){
15068 * Returns true if this instance is locked, or the drag drop mgr is locked
15069 * (meaning that all drag/drop is disabled on the page.)
15071 * @return {boolean} true if this obj or all drag/drop is locked, else
15074 isLocked: function() {
15075 return (this.DDM.isLocked() || this.locked);
15079 * Fired when this object is clicked
15080 * @method handleMouseDown
15082 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15085 handleMouseDown: function(e, oDD){
15086 if (this.primaryButtonOnly && e.button != 0) {
15090 if (this.isLocked()) {
15094 this.DDM.refreshCache(this.groups);
15096 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15097 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15099 if (this.clickValidator(e)) {
15101 // set the initial element position
15102 this.setStartPosition();
15105 this.b4MouseDown(e);
15106 this.onMouseDown(e);
15108 this.DDM.handleMouseDown(e, this);
15110 this.DDM.stopEvent(e);
15118 clickValidator: function(e) {
15119 var target = e.getTarget();
15120 return ( this.isValidHandleChild(target) &&
15121 (this.id == this.handleElId ||
15122 this.DDM.handleWasClicked(target, this.id)) );
15126 * Allows you to specify a tag name that should not start a drag operation
15127 * when clicked. This is designed to facilitate embedding links within a
15128 * drag handle that do something other than start the drag.
15129 * @method addInvalidHandleType
15130 * @param {string} tagName the type of element to exclude
15132 addInvalidHandleType: function(tagName) {
15133 var type = tagName.toUpperCase();
15134 this.invalidHandleTypes[type] = type;
15138 * Lets you to specify an element id for a child of a drag handle
15139 * that should not initiate a drag
15140 * @method addInvalidHandleId
15141 * @param {string} id the element id of the element you wish to ignore
15143 addInvalidHandleId: function(id) {
15144 if (typeof id !== "string") {
15147 this.invalidHandleIds[id] = id;
15151 * Lets you specify a css class of elements that will not initiate a drag
15152 * @method addInvalidHandleClass
15153 * @param {string} cssClass the class of the elements you wish to ignore
15155 addInvalidHandleClass: function(cssClass) {
15156 this.invalidHandleClasses.push(cssClass);
15160 * Unsets an excluded tag name set by addInvalidHandleType
15161 * @method removeInvalidHandleType
15162 * @param {string} tagName the type of element to unexclude
15164 removeInvalidHandleType: function(tagName) {
15165 var type = tagName.toUpperCase();
15166 // this.invalidHandleTypes[type] = null;
15167 delete this.invalidHandleTypes[type];
15171 * Unsets an invalid handle id
15172 * @method removeInvalidHandleId
15173 * @param {string} id the id of the element to re-enable
15175 removeInvalidHandleId: function(id) {
15176 if (typeof id !== "string") {
15179 delete this.invalidHandleIds[id];
15183 * Unsets an invalid css class
15184 * @method removeInvalidHandleClass
15185 * @param {string} cssClass the class of the element(s) you wish to
15188 removeInvalidHandleClass: function(cssClass) {
15189 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15190 if (this.invalidHandleClasses[i] == cssClass) {
15191 delete this.invalidHandleClasses[i];
15197 * Checks the tag exclusion list to see if this click should be ignored
15198 * @method isValidHandleChild
15199 * @param {HTMLElement} node the HTMLElement to evaluate
15200 * @return {boolean} true if this is a valid tag type, false if not
15202 isValidHandleChild: function(node) {
15205 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15208 nodeName = node.nodeName.toUpperCase();
15210 nodeName = node.nodeName;
15212 valid = valid && !this.invalidHandleTypes[nodeName];
15213 valid = valid && !this.invalidHandleIds[node.id];
15215 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15216 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15225 * Create the array of horizontal tick marks if an interval was specified
15226 * in setXConstraint().
15227 * @method setXTicks
15230 setXTicks: function(iStartX, iTickSize) {
15232 this.xTickSize = iTickSize;
15236 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15238 this.xTicks[this.xTicks.length] = i;
15243 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15245 this.xTicks[this.xTicks.length] = i;
15250 this.xTicks.sort(this.DDM.numericSort) ;
15254 * Create the array of vertical tick marks if an interval was specified in
15255 * setYConstraint().
15256 * @method setYTicks
15259 setYTicks: function(iStartY, iTickSize) {
15261 this.yTickSize = iTickSize;
15265 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15267 this.yTicks[this.yTicks.length] = i;
15272 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15274 this.yTicks[this.yTicks.length] = i;
15279 this.yTicks.sort(this.DDM.numericSort) ;
15283 * By default, the element can be dragged any place on the screen. Use
15284 * this method to limit the horizontal travel of the element. Pass in
15285 * 0,0 for the parameters if you want to lock the drag to the y axis.
15286 * @method setXConstraint
15287 * @param {int} iLeft the number of pixels the element can move to the left
15288 * @param {int} iRight the number of pixels the element can move to the
15290 * @param {int} iTickSize optional parameter for specifying that the
15292 * should move iTickSize pixels at a time.
15294 setXConstraint: function(iLeft, iRight, iTickSize) {
15295 this.leftConstraint = iLeft;
15296 this.rightConstraint = iRight;
15298 this.minX = this.initPageX - iLeft;
15299 this.maxX = this.initPageX + iRight;
15300 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15302 this.constrainX = true;
15306 * Clears any constraints applied to this instance. Also clears ticks
15307 * since they can't exist independent of a constraint at this time.
15308 * @method clearConstraints
15310 clearConstraints: function() {
15311 this.constrainX = false;
15312 this.constrainY = false;
15317 * Clears any tick interval defined for this instance
15318 * @method clearTicks
15320 clearTicks: function() {
15321 this.xTicks = null;
15322 this.yTicks = null;
15323 this.xTickSize = 0;
15324 this.yTickSize = 0;
15328 * By default, the element can be dragged any place on the screen. Set
15329 * this to limit the vertical travel of the element. Pass in 0,0 for the
15330 * parameters if you want to lock the drag to the x axis.
15331 * @method setYConstraint
15332 * @param {int} iUp the number of pixels the element can move up
15333 * @param {int} iDown the number of pixels the element can move down
15334 * @param {int} iTickSize optional parameter for specifying that the
15335 * element should move iTickSize pixels at a time.
15337 setYConstraint: function(iUp, iDown, iTickSize) {
15338 this.topConstraint = iUp;
15339 this.bottomConstraint = iDown;
15341 this.minY = this.initPageY - iUp;
15342 this.maxY = this.initPageY + iDown;
15343 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15345 this.constrainY = true;
15350 * resetConstraints must be called if you manually reposition a dd element.
15351 * @method resetConstraints
15352 * @param {boolean} maintainOffset
15354 resetConstraints: function() {
15357 // Maintain offsets if necessary
15358 if (this.initPageX || this.initPageX === 0) {
15359 // figure out how much this thing has moved
15360 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15361 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15363 this.setInitPosition(dx, dy);
15365 // This is the first time we have detected the element's position
15367 this.setInitPosition();
15370 if (this.constrainX) {
15371 this.setXConstraint( this.leftConstraint,
15372 this.rightConstraint,
15376 if (this.constrainY) {
15377 this.setYConstraint( this.topConstraint,
15378 this.bottomConstraint,
15384 * Normally the drag element is moved pixel by pixel, but we can specify
15385 * that it move a number of pixels at a time. This method resolves the
15386 * location when we have it set up like this.
15388 * @param {int} val where we want to place the object
15389 * @param {int[]} tickArray sorted array of valid points
15390 * @return {int} the closest tick
15393 getTick: function(val, tickArray) {
15396 // If tick interval is not defined, it is effectively 1 pixel,
15397 // so we return the value passed to us.
15399 } else if (tickArray[0] >= val) {
15400 // The value is lower than the first tick, so we return the first
15402 return tickArray[0];
15404 for (var i=0, len=tickArray.length; i<len; ++i) {
15406 if (tickArray[next] && tickArray[next] >= val) {
15407 var diff1 = val - tickArray[i];
15408 var diff2 = tickArray[next] - val;
15409 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15413 // The value is larger than the last tick, so we return the last
15415 return tickArray[tickArray.length - 1];
15422 * @return {string} string representation of the dd obj
15424 toString: function() {
15425 return ("DragDrop " + this.id);
15433 * Ext JS Library 1.1.1
15434 * Copyright(c) 2006-2007, Ext JS, LLC.
15436 * Originally Released Under LGPL - original licence link has changed is not relivant.
15439 * <script type="text/javascript">
15444 * The drag and drop utility provides a framework for building drag and drop
15445 * applications. In addition to enabling drag and drop for specific elements,
15446 * the drag and drop elements are tracked by the manager class, and the
15447 * interactions between the various elements are tracked during the drag and
15448 * the implementing code is notified about these important moments.
15451 // Only load the library once. Rewriting the manager class would orphan
15452 // existing drag and drop instances.
15453 if (!Roo.dd.DragDropMgr) {
15456 * @class Roo.dd.DragDropMgr
15457 * DragDropMgr is a singleton that tracks the element interaction for
15458 * all DragDrop items in the window. Generally, you will not call
15459 * this class directly, but it does have helper methods that could
15460 * be useful in your DragDrop implementations.
15463 Roo.dd.DragDropMgr = function() {
15465 var Event = Roo.EventManager;
15470 * Two dimensional Array of registered DragDrop objects. The first
15471 * dimension is the DragDrop item group, the second the DragDrop
15474 * @type {string: string}
15481 * Array of element ids defined as drag handles. Used to determine
15482 * if the element that generated the mousedown event is actually the
15483 * handle and not the html element itself.
15484 * @property handleIds
15485 * @type {string: string}
15492 * the DragDrop object that is currently being dragged
15493 * @property dragCurrent
15501 * the DragDrop object(s) that are being hovered over
15502 * @property dragOvers
15510 * the X distance between the cursor and the object being dragged
15519 * the Y distance between the cursor and the object being dragged
15528 * Flag to determine if we should prevent the default behavior of the
15529 * events we define. By default this is true, but this can be set to
15530 * false if you need the default behavior (not recommended)
15531 * @property preventDefault
15535 preventDefault: true,
15538 * Flag to determine if we should stop the propagation of the events
15539 * we generate. This is true by default but you may want to set it to
15540 * false if the html element contains other features that require the
15542 * @property stopPropagation
15546 stopPropagation: true,
15549 * Internal flag that is set to true when drag and drop has been
15551 * @property initialized
15558 * All drag and drop can be disabled.
15566 * Called the first time an element is registered.
15572 this.initialized = true;
15576 * In point mode, drag and drop interaction is defined by the
15577 * location of the cursor during the drag/drop
15585 * In intersect mode, drag and drop interactio nis defined by the
15586 * overlap of two or more drag and drop objects.
15587 * @property INTERSECT
15594 * The current drag and drop mode. Default: POINT
15602 * Runs method on all drag and drop objects
15603 * @method _execOnAll
15607 _execOnAll: function(sMethod, args) {
15608 for (var i in this.ids) {
15609 for (var j in this.ids[i]) {
15610 var oDD = this.ids[i][j];
15611 if (! this.isTypeOfDD(oDD)) {
15614 oDD[sMethod].apply(oDD, args);
15620 * Drag and drop initialization. Sets up the global event handlers
15625 _onLoad: function() {
15630 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15631 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15632 Event.on(window, "unload", this._onUnload, this, true);
15633 Event.on(window, "resize", this._onResize, this, true);
15634 // Event.on(window, "mouseout", this._test);
15639 * Reset constraints on all drag and drop objs
15640 * @method _onResize
15644 _onResize: function(e) {
15645 this._execOnAll("resetConstraints", []);
15649 * Lock all drag and drop functionality
15653 lock: function() { this.locked = true; },
15656 * Unlock all drag and drop functionality
15660 unlock: function() { this.locked = false; },
15663 * Is drag and drop locked?
15665 * @return {boolean} True if drag and drop is locked, false otherwise.
15668 isLocked: function() { return this.locked; },
15671 * Location cache that is set for all drag drop objects when a drag is
15672 * initiated, cleared when the drag is finished.
15673 * @property locationCache
15680 * Set useCache to false if you want to force object the lookup of each
15681 * drag and drop linked element constantly during a drag.
15682 * @property useCache
15689 * The number of pixels that the mouse needs to move after the
15690 * mousedown before the drag is initiated. Default=3;
15691 * @property clickPixelThresh
15695 clickPixelThresh: 3,
15698 * The number of milliseconds after the mousedown event to initiate the
15699 * drag if we don't get a mouseup event. Default=1000
15700 * @property clickTimeThresh
15704 clickTimeThresh: 350,
15707 * Flag that indicates that either the drag pixel threshold or the
15708 * mousdown time threshold has been met
15709 * @property dragThreshMet
15714 dragThreshMet: false,
15717 * Timeout used for the click time threshold
15718 * @property clickTimeout
15723 clickTimeout: null,
15726 * The X position of the mousedown event stored for later use when a
15727 * drag threshold is met.
15736 * The Y position of the mousedown event stored for later use when a
15737 * drag threshold is met.
15746 * Each DragDrop instance must be registered with the DragDropMgr.
15747 * This is executed in DragDrop.init()
15748 * @method regDragDrop
15749 * @param {DragDrop} oDD the DragDrop object to register
15750 * @param {String} sGroup the name of the group this element belongs to
15753 regDragDrop: function(oDD, sGroup) {
15754 if (!this.initialized) { this.init(); }
15756 if (!this.ids[sGroup]) {
15757 this.ids[sGroup] = {};
15759 this.ids[sGroup][oDD.id] = oDD;
15763 * Removes the supplied dd instance from the supplied group. Executed
15764 * by DragDrop.removeFromGroup, so don't call this function directly.
15765 * @method removeDDFromGroup
15769 removeDDFromGroup: function(oDD, sGroup) {
15770 if (!this.ids[sGroup]) {
15771 this.ids[sGroup] = {};
15774 var obj = this.ids[sGroup];
15775 if (obj && obj[oDD.id]) {
15776 delete obj[oDD.id];
15781 * Unregisters a drag and drop item. This is executed in
15782 * DragDrop.unreg, use that method instead of calling this directly.
15787 _remove: function(oDD) {
15788 for (var g in oDD.groups) {
15789 if (g && this.ids[g][oDD.id]) {
15790 delete this.ids[g][oDD.id];
15793 delete this.handleIds[oDD.id];
15797 * Each DragDrop handle element must be registered. This is done
15798 * automatically when executing DragDrop.setHandleElId()
15799 * @method regHandle
15800 * @param {String} sDDId the DragDrop id this element is a handle for
15801 * @param {String} sHandleId the id of the element that is the drag
15805 regHandle: function(sDDId, sHandleId) {
15806 if (!this.handleIds[sDDId]) {
15807 this.handleIds[sDDId] = {};
15809 this.handleIds[sDDId][sHandleId] = sHandleId;
15813 * Utility function to determine if a given element has been
15814 * registered as a drag drop item.
15815 * @method isDragDrop
15816 * @param {String} id the element id to check
15817 * @return {boolean} true if this element is a DragDrop item,
15821 isDragDrop: function(id) {
15822 return ( this.getDDById(id) ) ? true : false;
15826 * Returns the drag and drop instances that are in all groups the
15827 * passed in instance belongs to.
15828 * @method getRelated
15829 * @param {DragDrop} p_oDD the obj to get related data for
15830 * @param {boolean} bTargetsOnly if true, only return targetable objs
15831 * @return {DragDrop[]} the related instances
15834 getRelated: function(p_oDD, bTargetsOnly) {
15836 for (var i in p_oDD.groups) {
15837 for (j in this.ids[i]) {
15838 var dd = this.ids[i][j];
15839 if (! this.isTypeOfDD(dd)) {
15842 if (!bTargetsOnly || dd.isTarget) {
15843 oDDs[oDDs.length] = dd;
15852 * Returns true if the specified dd target is a legal target for
15853 * the specifice drag obj
15854 * @method isLegalTarget
15855 * @param {DragDrop} the drag obj
15856 * @param {DragDrop} the target
15857 * @return {boolean} true if the target is a legal target for the
15861 isLegalTarget: function (oDD, oTargetDD) {
15862 var targets = this.getRelated(oDD, true);
15863 for (var i=0, len=targets.length;i<len;++i) {
15864 if (targets[i].id == oTargetDD.id) {
15873 * My goal is to be able to transparently determine if an object is
15874 * typeof DragDrop, and the exact subclass of DragDrop. typeof
15875 * returns "object", oDD.constructor.toString() always returns
15876 * "DragDrop" and not the name of the subclass. So for now it just
15877 * evaluates a well-known variable in DragDrop.
15878 * @method isTypeOfDD
15879 * @param {Object} the object to evaluate
15880 * @return {boolean} true if typeof oDD = DragDrop
15883 isTypeOfDD: function (oDD) {
15884 return (oDD && oDD.__ygDragDrop);
15888 * Utility function to determine if a given element has been
15889 * registered as a drag drop handle for the given Drag Drop object.
15891 * @param {String} id the element id to check
15892 * @return {boolean} true if this element is a DragDrop handle, false
15896 isHandle: function(sDDId, sHandleId) {
15897 return ( this.handleIds[sDDId] &&
15898 this.handleIds[sDDId][sHandleId] );
15902 * Returns the DragDrop instance for a given id
15903 * @method getDDById
15904 * @param {String} id the id of the DragDrop object
15905 * @return {DragDrop} the drag drop object, null if it is not found
15908 getDDById: function(id) {
15909 for (var i in this.ids) {
15910 if (this.ids[i][id]) {
15911 return this.ids[i][id];
15918 * Fired after a registered DragDrop object gets the mousedown event.
15919 * Sets up the events required to track the object being dragged
15920 * @method handleMouseDown
15921 * @param {Event} e the event
15922 * @param oDD the DragDrop object being dragged
15926 handleMouseDown: function(e, oDD) {
15928 Roo.QuickTips.disable();
15930 this.currentTarget = e.getTarget();
15932 this.dragCurrent = oDD;
15934 var el = oDD.getEl();
15936 // track start position
15937 this.startX = e.getPageX();
15938 this.startY = e.getPageY();
15940 this.deltaX = this.startX - el.offsetLeft;
15941 this.deltaY = this.startY - el.offsetTop;
15943 this.dragThreshMet = false;
15945 this.clickTimeout = setTimeout(
15947 var DDM = Roo.dd.DDM;
15948 DDM.startDrag(DDM.startX, DDM.startY);
15950 this.clickTimeThresh );
15954 * Fired when either the drag pixel threshol or the mousedown hold
15955 * time threshold has been met.
15956 * @method startDrag
15957 * @param x {int} the X position of the original mousedown
15958 * @param y {int} the Y position of the original mousedown
15961 startDrag: function(x, y) {
15962 clearTimeout(this.clickTimeout);
15963 if (this.dragCurrent) {
15964 this.dragCurrent.b4StartDrag(x, y);
15965 this.dragCurrent.startDrag(x, y);
15967 this.dragThreshMet = true;
15971 * Internal function to handle the mouseup event. Will be invoked
15972 * from the context of the document.
15973 * @method handleMouseUp
15974 * @param {Event} e the event
15978 handleMouseUp: function(e) {
15981 Roo.QuickTips.enable();
15983 if (! this.dragCurrent) {
15987 clearTimeout(this.clickTimeout);
15989 if (this.dragThreshMet) {
15990 this.fireEvents(e, true);
16000 * Utility to stop event propagation and event default, if these
16001 * features are turned on.
16002 * @method stopEvent
16003 * @param {Event} e the event as returned by this.getEvent()
16006 stopEvent: function(e){
16007 if(this.stopPropagation) {
16008 e.stopPropagation();
16011 if (this.preventDefault) {
16012 e.preventDefault();
16017 * Internal function to clean up event handlers after the drag
16018 * operation is complete
16020 * @param {Event} e the event
16024 stopDrag: function(e) {
16025 // Fire the drag end event for the item that was dragged
16026 if (this.dragCurrent) {
16027 if (this.dragThreshMet) {
16028 this.dragCurrent.b4EndDrag(e);
16029 this.dragCurrent.endDrag(e);
16032 this.dragCurrent.onMouseUp(e);
16035 this.dragCurrent = null;
16036 this.dragOvers = {};
16040 * Internal function to handle the mousemove event. Will be invoked
16041 * from the context of the html element.
16043 * @TODO figure out what we can do about mouse events lost when the
16044 * user drags objects beyond the window boundary. Currently we can
16045 * detect this in internet explorer by verifying that the mouse is
16046 * down during the mousemove event. Firefox doesn't give us the
16047 * button state on the mousemove event.
16048 * @method handleMouseMove
16049 * @param {Event} e the event
16053 handleMouseMove: function(e) {
16054 if (! this.dragCurrent) {
16058 // var button = e.which || e.button;
16060 // check for IE mouseup outside of page boundary
16061 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16063 return this.handleMouseUp(e);
16066 if (!this.dragThreshMet) {
16067 var diffX = Math.abs(this.startX - e.getPageX());
16068 var diffY = Math.abs(this.startY - e.getPageY());
16069 if (diffX > this.clickPixelThresh ||
16070 diffY > this.clickPixelThresh) {
16071 this.startDrag(this.startX, this.startY);
16075 if (this.dragThreshMet) {
16076 this.dragCurrent.b4Drag(e);
16077 this.dragCurrent.onDrag(e);
16078 if(!this.dragCurrent.moveOnly){
16079 this.fireEvents(e, false);
16089 * Iterates over all of the DragDrop elements to find ones we are
16090 * hovering over or dropping on
16091 * @method fireEvents
16092 * @param {Event} e the event
16093 * @param {boolean} isDrop is this a drop op or a mouseover op?
16097 fireEvents: function(e, isDrop) {
16098 var dc = this.dragCurrent;
16100 // If the user did the mouse up outside of the window, we could
16101 // get here even though we have ended the drag.
16102 if (!dc || dc.isLocked()) {
16106 var pt = e.getPoint();
16108 // cache the previous dragOver array
16114 var enterEvts = [];
16116 // Check to see if the object(s) we were hovering over is no longer
16117 // being hovered over so we can fire the onDragOut event
16118 for (var i in this.dragOvers) {
16120 var ddo = this.dragOvers[i];
16122 if (! this.isTypeOfDD(ddo)) {
16126 if (! this.isOverTarget(pt, ddo, this.mode)) {
16127 outEvts.push( ddo );
16130 oldOvers[i] = true;
16131 delete this.dragOvers[i];
16134 for (var sGroup in dc.groups) {
16136 if ("string" != typeof sGroup) {
16140 for (i in this.ids[sGroup]) {
16141 var oDD = this.ids[sGroup][i];
16142 if (! this.isTypeOfDD(oDD)) {
16146 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16147 if (this.isOverTarget(pt, oDD, this.mode)) {
16148 // look for drop interactions
16150 dropEvts.push( oDD );
16151 // look for drag enter and drag over interactions
16154 // initial drag over: dragEnter fires
16155 if (!oldOvers[oDD.id]) {
16156 enterEvts.push( oDD );
16157 // subsequent drag overs: dragOver fires
16159 overEvts.push( oDD );
16162 this.dragOvers[oDD.id] = oDD;
16170 if (outEvts.length) {
16171 dc.b4DragOut(e, outEvts);
16172 dc.onDragOut(e, outEvts);
16175 if (enterEvts.length) {
16176 dc.onDragEnter(e, enterEvts);
16179 if (overEvts.length) {
16180 dc.b4DragOver(e, overEvts);
16181 dc.onDragOver(e, overEvts);
16184 if (dropEvts.length) {
16185 dc.b4DragDrop(e, dropEvts);
16186 dc.onDragDrop(e, dropEvts);
16190 // fire dragout events
16192 for (i=0, len=outEvts.length; i<len; ++i) {
16193 dc.b4DragOut(e, outEvts[i].id);
16194 dc.onDragOut(e, outEvts[i].id);
16197 // fire enter events
16198 for (i=0,len=enterEvts.length; i<len; ++i) {
16199 // dc.b4DragEnter(e, oDD.id);
16200 dc.onDragEnter(e, enterEvts[i].id);
16203 // fire over events
16204 for (i=0,len=overEvts.length; i<len; ++i) {
16205 dc.b4DragOver(e, overEvts[i].id);
16206 dc.onDragOver(e, overEvts[i].id);
16209 // fire drop events
16210 for (i=0, len=dropEvts.length; i<len; ++i) {
16211 dc.b4DragDrop(e, dropEvts[i].id);
16212 dc.onDragDrop(e, dropEvts[i].id);
16217 // notify about a drop that did not find a target
16218 if (isDrop && !dropEvts.length) {
16219 dc.onInvalidDrop(e);
16225 * Helper function for getting the best match from the list of drag
16226 * and drop objects returned by the drag and drop events when we are
16227 * in INTERSECT mode. It returns either the first object that the
16228 * cursor is over, or the object that has the greatest overlap with
16229 * the dragged element.
16230 * @method getBestMatch
16231 * @param {DragDrop[]} dds The array of drag and drop objects
16233 * @return {DragDrop} The best single match
16236 getBestMatch: function(dds) {
16238 // Return null if the input is not what we expect
16239 //if (!dds || !dds.length || dds.length == 0) {
16241 // If there is only one item, it wins
16242 //} else if (dds.length == 1) {
16244 var len = dds.length;
16249 // Loop through the targeted items
16250 for (var i=0; i<len; ++i) {
16252 // If the cursor is over the object, it wins. If the
16253 // cursor is over multiple matches, the first one we come
16255 if (dd.cursorIsOver) {
16258 // Otherwise the object with the most overlap wins
16261 winner.overlap.getArea() < dd.overlap.getArea()) {
16272 * Refreshes the cache of the top-left and bottom-right points of the
16273 * drag and drop objects in the specified group(s). This is in the
16274 * format that is stored in the drag and drop instance, so typical
16277 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16281 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16283 * @TODO this really should be an indexed array. Alternatively this
16284 * method could accept both.
16285 * @method refreshCache
16286 * @param {Object} groups an associative array of groups to refresh
16289 refreshCache: function(groups) {
16290 for (var sGroup in groups) {
16291 if ("string" != typeof sGroup) {
16294 for (var i in this.ids[sGroup]) {
16295 var oDD = this.ids[sGroup][i];
16297 if (this.isTypeOfDD(oDD)) {
16298 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16299 var loc = this.getLocation(oDD);
16301 this.locationCache[oDD.id] = loc;
16303 delete this.locationCache[oDD.id];
16304 // this will unregister the drag and drop object if
16305 // the element is not in a usable state
16314 * This checks to make sure an element exists and is in the DOM. The
16315 * main purpose is to handle cases where innerHTML is used to remove
16316 * drag and drop objects from the DOM. IE provides an 'unspecified
16317 * error' when trying to access the offsetParent of such an element
16319 * @param {HTMLElement} el the element to check
16320 * @return {boolean} true if the element looks usable
16323 verifyEl: function(el) {
16328 parent = el.offsetParent;
16331 parent = el.offsetParent;
16342 * Returns a Region object containing the drag and drop element's position
16343 * and size, including the padding configured for it
16344 * @method getLocation
16345 * @param {DragDrop} oDD the drag and drop object to get the
16347 * @return {Roo.lib.Region} a Region object representing the total area
16348 * the element occupies, including any padding
16349 * the instance is configured for.
16352 getLocation: function(oDD) {
16353 if (! this.isTypeOfDD(oDD)) {
16357 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16360 pos= Roo.lib.Dom.getXY(el);
16368 x2 = x1 + el.offsetWidth;
16370 y2 = y1 + el.offsetHeight;
16372 t = y1 - oDD.padding[0];
16373 r = x2 + oDD.padding[1];
16374 b = y2 + oDD.padding[2];
16375 l = x1 - oDD.padding[3];
16377 return new Roo.lib.Region( t, r, b, l );
16381 * Checks the cursor location to see if it over the target
16382 * @method isOverTarget
16383 * @param {Roo.lib.Point} pt The point to evaluate
16384 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16385 * @return {boolean} true if the mouse is over the target
16389 isOverTarget: function(pt, oTarget, intersect) {
16390 // use cache if available
16391 var loc = this.locationCache[oTarget.id];
16392 if (!loc || !this.useCache) {
16393 loc = this.getLocation(oTarget);
16394 this.locationCache[oTarget.id] = loc;
16402 oTarget.cursorIsOver = loc.contains( pt );
16404 // DragDrop is using this as a sanity check for the initial mousedown
16405 // in this case we are done. In POINT mode, if the drag obj has no
16406 // contraints, we are also done. Otherwise we need to evaluate the
16407 // location of the target as related to the actual location of the
16408 // dragged element.
16409 var dc = this.dragCurrent;
16410 if (!dc || !dc.getTargetCoord ||
16411 (!intersect && !dc.constrainX && !dc.constrainY)) {
16412 return oTarget.cursorIsOver;
16415 oTarget.overlap = null;
16417 // Get the current location of the drag element, this is the
16418 // location of the mouse event less the delta that represents
16419 // where the original mousedown happened on the element. We
16420 // need to consider constraints and ticks as well.
16421 var pos = dc.getTargetCoord(pt.x, pt.y);
16423 var el = dc.getDragEl();
16424 var curRegion = new Roo.lib.Region( pos.y,
16425 pos.x + el.offsetWidth,
16426 pos.y + el.offsetHeight,
16429 var overlap = curRegion.intersect(loc);
16432 oTarget.overlap = overlap;
16433 return (intersect) ? true : oTarget.cursorIsOver;
16440 * unload event handler
16441 * @method _onUnload
16445 _onUnload: function(e, me) {
16446 Roo.dd.DragDropMgr.unregAll();
16450 * Cleans up the drag and drop events and objects.
16455 unregAll: function() {
16457 if (this.dragCurrent) {
16459 this.dragCurrent = null;
16462 this._execOnAll("unreg", []);
16464 for (i in this.elementCache) {
16465 delete this.elementCache[i];
16468 this.elementCache = {};
16473 * A cache of DOM elements
16474 * @property elementCache
16481 * Get the wrapper for the DOM element specified
16482 * @method getElWrapper
16483 * @param {String} id the id of the element to get
16484 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16486 * @deprecated This wrapper isn't that useful
16489 getElWrapper: function(id) {
16490 var oWrapper = this.elementCache[id];
16491 if (!oWrapper || !oWrapper.el) {
16492 oWrapper = this.elementCache[id] =
16493 new this.ElementWrapper(Roo.getDom(id));
16499 * Returns the actual DOM element
16500 * @method getElement
16501 * @param {String} id the id of the elment to get
16502 * @return {Object} The element
16503 * @deprecated use Roo.getDom instead
16506 getElement: function(id) {
16507 return Roo.getDom(id);
16511 * Returns the style property for the DOM element (i.e.,
16512 * document.getElById(id).style)
16514 * @param {String} id the id of the elment to get
16515 * @return {Object} The style property of the element
16516 * @deprecated use Roo.getDom instead
16519 getCss: function(id) {
16520 var el = Roo.getDom(id);
16521 return (el) ? el.style : null;
16525 * Inner class for cached elements
16526 * @class DragDropMgr.ElementWrapper
16531 ElementWrapper: function(el) {
16536 this.el = el || null;
16541 this.id = this.el && el.id;
16543 * A reference to the style property
16546 this.css = this.el && el.style;
16550 * Returns the X position of an html element
16552 * @param el the element for which to get the position
16553 * @return {int} the X coordinate
16555 * @deprecated use Roo.lib.Dom.getX instead
16558 getPosX: function(el) {
16559 return Roo.lib.Dom.getX(el);
16563 * Returns the Y position of an html element
16565 * @param el the element for which to get the position
16566 * @return {int} the Y coordinate
16567 * @deprecated use Roo.lib.Dom.getY instead
16570 getPosY: function(el) {
16571 return Roo.lib.Dom.getY(el);
16575 * Swap two nodes. In IE, we use the native method, for others we
16576 * emulate the IE behavior
16578 * @param n1 the first node to swap
16579 * @param n2 the other node to swap
16582 swapNode: function(n1, n2) {
16586 var p = n2.parentNode;
16587 var s = n2.nextSibling;
16590 p.insertBefore(n1, n2);
16591 } else if (n2 == n1.nextSibling) {
16592 p.insertBefore(n2, n1);
16594 n1.parentNode.replaceChild(n2, n1);
16595 p.insertBefore(n1, s);
16601 * Returns the current scroll position
16602 * @method getScroll
16606 getScroll: function () {
16607 var t, l, dde=document.documentElement, db=document.body;
16608 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16610 l = dde.scrollLeft;
16617 return { top: t, left: l };
16621 * Returns the specified element style property
16623 * @param {HTMLElement} el the element
16624 * @param {string} styleProp the style property
16625 * @return {string} The value of the style property
16626 * @deprecated use Roo.lib.Dom.getStyle
16629 getStyle: function(el, styleProp) {
16630 return Roo.fly(el).getStyle(styleProp);
16634 * Gets the scrollTop
16635 * @method getScrollTop
16636 * @return {int} the document's scrollTop
16639 getScrollTop: function () { return this.getScroll().top; },
16642 * Gets the scrollLeft
16643 * @method getScrollLeft
16644 * @return {int} the document's scrollTop
16647 getScrollLeft: function () { return this.getScroll().left; },
16650 * Sets the x/y position of an element to the location of the
16653 * @param {HTMLElement} moveEl The element to move
16654 * @param {HTMLElement} targetEl The position reference element
16657 moveToEl: function (moveEl, targetEl) {
16658 var aCoord = Roo.lib.Dom.getXY(targetEl);
16659 Roo.lib.Dom.setXY(moveEl, aCoord);
16663 * Numeric array sort function
16664 * @method numericSort
16667 numericSort: function(a, b) { return (a - b); },
16671 * @property _timeoutCount
16678 * Trying to make the load order less important. Without this we get
16679 * an error if this file is loaded before the Event Utility.
16680 * @method _addListeners
16684 _addListeners: function() {
16685 var DDM = Roo.dd.DDM;
16686 if ( Roo.lib.Event && document ) {
16689 if (DDM._timeoutCount > 2000) {
16691 setTimeout(DDM._addListeners, 10);
16692 if (document && document.body) {
16693 DDM._timeoutCount += 1;
16700 * Recursively searches the immediate parent and all child nodes for
16701 * the handle element in order to determine wheter or not it was
16703 * @method handleWasClicked
16704 * @param node the html element to inspect
16707 handleWasClicked: function(node, id) {
16708 if (this.isHandle(id, node.id)) {
16711 // check to see if this is a text node child of the one we want
16712 var p = node.parentNode;
16715 if (this.isHandle(id, p.id)) {
16730 // shorter alias, save a few bytes
16731 Roo.dd.DDM = Roo.dd.DragDropMgr;
16732 Roo.dd.DDM._addListeners();
16736 * Ext JS Library 1.1.1
16737 * Copyright(c) 2006-2007, Ext JS, LLC.
16739 * Originally Released Under LGPL - original licence link has changed is not relivant.
16742 * <script type="text/javascript">
16747 * A DragDrop implementation where the linked element follows the
16748 * mouse cursor during a drag.
16749 * @extends Roo.dd.DragDrop
16751 * @param {String} id the id of the linked element
16752 * @param {String} sGroup the group of related DragDrop items
16753 * @param {object} config an object containing configurable attributes
16754 * Valid properties for DD:
16757 Roo.dd.DD = function(id, sGroup, config) {
16759 this.init(id, sGroup, config);
16763 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16766 * When set to true, the utility automatically tries to scroll the browser
16767 * window wehn a drag and drop element is dragged near the viewport boundary.
16768 * Defaults to true.
16775 * Sets the pointer offset to the distance between the linked element's top
16776 * left corner and the location the element was clicked
16777 * @method autoOffset
16778 * @param {int} iPageX the X coordinate of the click
16779 * @param {int} iPageY the Y coordinate of the click
16781 autoOffset: function(iPageX, iPageY) {
16782 var x = iPageX - this.startPageX;
16783 var y = iPageY - this.startPageY;
16784 this.setDelta(x, y);
16788 * Sets the pointer offset. You can call this directly to force the
16789 * offset to be in a particular location (e.g., pass in 0,0 to set it
16790 * to the center of the object)
16792 * @param {int} iDeltaX the distance from the left
16793 * @param {int} iDeltaY the distance from the top
16795 setDelta: function(iDeltaX, iDeltaY) {
16796 this.deltaX = iDeltaX;
16797 this.deltaY = iDeltaY;
16801 * Sets the drag element to the location of the mousedown or click event,
16802 * maintaining the cursor location relative to the location on the element
16803 * that was clicked. Override this if you want to place the element in a
16804 * location other than where the cursor is.
16805 * @method setDragElPos
16806 * @param {int} iPageX the X coordinate of the mousedown or drag event
16807 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16809 setDragElPos: function(iPageX, iPageY) {
16810 // the first time we do this, we are going to check to make sure
16811 // the element has css positioning
16813 var el = this.getDragEl();
16814 this.alignElWithMouse(el, iPageX, iPageY);
16818 * Sets the element to the location of the mousedown or click event,
16819 * maintaining the cursor location relative to the location on the element
16820 * that was clicked. Override this if you want to place the element in a
16821 * location other than where the cursor is.
16822 * @method alignElWithMouse
16823 * @param {HTMLElement} el the element to move
16824 * @param {int} iPageX the X coordinate of the mousedown or drag event
16825 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16827 alignElWithMouse: function(el, iPageX, iPageY) {
16828 var oCoord = this.getTargetCoord(iPageX, iPageY);
16829 var fly = el.dom ? el : Roo.fly(el);
16830 if (!this.deltaSetXY) {
16831 var aCoord = [oCoord.x, oCoord.y];
16833 var newLeft = fly.getLeft(true);
16834 var newTop = fly.getTop(true);
16835 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
16837 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
16840 this.cachePosition(oCoord.x, oCoord.y);
16841 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
16846 * Saves the most recent position so that we can reset the constraints and
16847 * tick marks on-demand. We need to know this so that we can calculate the
16848 * number of pixels the element is offset from its original position.
16849 * @method cachePosition
16850 * @param iPageX the current x position (optional, this just makes it so we
16851 * don't have to look it up again)
16852 * @param iPageY the current y position (optional, this just makes it so we
16853 * don't have to look it up again)
16855 cachePosition: function(iPageX, iPageY) {
16857 this.lastPageX = iPageX;
16858 this.lastPageY = iPageY;
16860 var aCoord = Roo.lib.Dom.getXY(this.getEl());
16861 this.lastPageX = aCoord[0];
16862 this.lastPageY = aCoord[1];
16867 * Auto-scroll the window if the dragged object has been moved beyond the
16868 * visible window boundary.
16869 * @method autoScroll
16870 * @param {int} x the drag element's x position
16871 * @param {int} y the drag element's y position
16872 * @param {int} h the height of the drag element
16873 * @param {int} w the width of the drag element
16876 autoScroll: function(x, y, h, w) {
16879 // The client height
16880 var clientH = Roo.lib.Dom.getViewWidth();
16882 // The client width
16883 var clientW = Roo.lib.Dom.getViewHeight();
16885 // The amt scrolled down
16886 var st = this.DDM.getScrollTop();
16888 // The amt scrolled right
16889 var sl = this.DDM.getScrollLeft();
16891 // Location of the bottom of the element
16894 // Location of the right of the element
16897 // The distance from the cursor to the bottom of the visible area,
16898 // adjusted so that we don't scroll if the cursor is beyond the
16899 // element drag constraints
16900 var toBot = (clientH + st - y - this.deltaY);
16902 // The distance from the cursor to the right of the visible area
16903 var toRight = (clientW + sl - x - this.deltaX);
16906 // How close to the edge the cursor must be before we scroll
16907 // var thresh = (document.all) ? 100 : 40;
16910 // How many pixels to scroll per autoscroll op. This helps to reduce
16911 // clunky scrolling. IE is more sensitive about this ... it needs this
16912 // value to be higher.
16913 var scrAmt = (document.all) ? 80 : 30;
16915 // Scroll down if we are near the bottom of the visible page and the
16916 // obj extends below the crease
16917 if ( bot > clientH && toBot < thresh ) {
16918 window.scrollTo(sl, st + scrAmt);
16921 // Scroll up if the window is scrolled down and the top of the object
16922 // goes above the top border
16923 if ( y < st && st > 0 && y - st < thresh ) {
16924 window.scrollTo(sl, st - scrAmt);
16927 // Scroll right if the obj is beyond the right border and the cursor is
16928 // near the border.
16929 if ( right > clientW && toRight < thresh ) {
16930 window.scrollTo(sl + scrAmt, st);
16933 // Scroll left if the window has been scrolled to the right and the obj
16934 // extends past the left border
16935 if ( x < sl && sl > 0 && x - sl < thresh ) {
16936 window.scrollTo(sl - scrAmt, st);
16942 * Finds the location the element should be placed if we want to move
16943 * it to where the mouse location less the click offset would place us.
16944 * @method getTargetCoord
16945 * @param {int} iPageX the X coordinate of the click
16946 * @param {int} iPageY the Y coordinate of the click
16947 * @return an object that contains the coordinates (Object.x and Object.y)
16950 getTargetCoord: function(iPageX, iPageY) {
16953 var x = iPageX - this.deltaX;
16954 var y = iPageY - this.deltaY;
16956 if (this.constrainX) {
16957 if (x < this.minX) { x = this.minX; }
16958 if (x > this.maxX) { x = this.maxX; }
16961 if (this.constrainY) {
16962 if (y < this.minY) { y = this.minY; }
16963 if (y > this.maxY) { y = this.maxY; }
16966 x = this.getTick(x, this.xTicks);
16967 y = this.getTick(y, this.yTicks);
16974 * Sets up config options specific to this class. Overrides
16975 * Roo.dd.DragDrop, but all versions of this method through the
16976 * inheritance chain are called
16978 applyConfig: function() {
16979 Roo.dd.DD.superclass.applyConfig.call(this);
16980 this.scroll = (this.config.scroll !== false);
16984 * Event that fires prior to the onMouseDown event. Overrides
16987 b4MouseDown: function(e) {
16988 // this.resetConstraints();
16989 this.autoOffset(e.getPageX(),
16994 * Event that fires prior to the onDrag event. Overrides
16997 b4Drag: function(e) {
16998 this.setDragElPos(e.getPageX(),
17002 toString: function() {
17003 return ("DD " + this.id);
17006 //////////////////////////////////////////////////////////////////////////
17007 // Debugging ygDragDrop events that can be overridden
17008 //////////////////////////////////////////////////////////////////////////
17010 startDrag: function(x, y) {
17013 onDrag: function(e) {
17016 onDragEnter: function(e, id) {
17019 onDragOver: function(e, id) {
17022 onDragOut: function(e, id) {
17025 onDragDrop: function(e, id) {
17028 endDrag: function(e) {
17035 * Ext JS Library 1.1.1
17036 * Copyright(c) 2006-2007, Ext JS, LLC.
17038 * Originally Released Under LGPL - original licence link has changed is not relivant.
17041 * <script type="text/javascript">
17045 * @class Roo.dd.DDProxy
17046 * A DragDrop implementation that inserts an empty, bordered div into
17047 * the document that follows the cursor during drag operations. At the time of
17048 * the click, the frame div is resized to the dimensions of the linked html
17049 * element, and moved to the exact location of the linked element.
17051 * References to the "frame" element refer to the single proxy element that
17052 * was created to be dragged in place of all DDProxy elements on the
17055 * @extends Roo.dd.DD
17057 * @param {String} id the id of the linked html element
17058 * @param {String} sGroup the group of related DragDrop objects
17059 * @param {object} config an object containing configurable attributes
17060 * Valid properties for DDProxy in addition to those in DragDrop:
17061 * resizeFrame, centerFrame, dragElId
17063 Roo.dd.DDProxy = function(id, sGroup, config) {
17065 this.init(id, sGroup, config);
17071 * The default drag frame div id
17072 * @property Roo.dd.DDProxy.dragElId
17076 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17078 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17081 * By default we resize the drag frame to be the same size as the element
17082 * we want to drag (this is to get the frame effect). We can turn it off
17083 * if we want a different behavior.
17084 * @property resizeFrame
17090 * By default the frame is positioned exactly where the drag element is, so
17091 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17092 * you do not have constraints on the obj is to have the drag frame centered
17093 * around the cursor. Set centerFrame to true for this effect.
17094 * @property centerFrame
17097 centerFrame: false,
17100 * Creates the proxy element if it does not yet exist
17101 * @method createFrame
17103 createFrame: function() {
17105 var body = document.body;
17107 if (!body || !body.firstChild) {
17108 setTimeout( function() { self.createFrame(); }, 50 );
17112 var div = this.getDragEl();
17115 div = document.createElement("div");
17116 div.id = this.dragElId;
17119 s.position = "absolute";
17120 s.visibility = "hidden";
17122 s.border = "2px solid #aaa";
17125 // appendChild can blow up IE if invoked prior to the window load event
17126 // while rendering a table. It is possible there are other scenarios
17127 // that would cause this to happen as well.
17128 body.insertBefore(div, body.firstChild);
17133 * Initialization for the drag frame element. Must be called in the
17134 * constructor of all subclasses
17135 * @method initFrame
17137 initFrame: function() {
17138 this.createFrame();
17141 applyConfig: function() {
17142 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17144 this.resizeFrame = (this.config.resizeFrame !== false);
17145 this.centerFrame = (this.config.centerFrame);
17146 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17150 * Resizes the drag frame to the dimensions of the clicked object, positions
17151 * it over the object, and finally displays it
17152 * @method showFrame
17153 * @param {int} iPageX X click position
17154 * @param {int} iPageY Y click position
17157 showFrame: function(iPageX, iPageY) {
17158 var el = this.getEl();
17159 var dragEl = this.getDragEl();
17160 var s = dragEl.style;
17162 this._resizeProxy();
17164 if (this.centerFrame) {
17165 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17166 Math.round(parseInt(s.height, 10)/2) );
17169 this.setDragElPos(iPageX, iPageY);
17171 Roo.fly(dragEl).show();
17175 * The proxy is automatically resized to the dimensions of the linked
17176 * element when a drag is initiated, unless resizeFrame is set to false
17177 * @method _resizeProxy
17180 _resizeProxy: function() {
17181 if (this.resizeFrame) {
17182 var el = this.getEl();
17183 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17187 // overrides Roo.dd.DragDrop
17188 b4MouseDown: function(e) {
17189 var x = e.getPageX();
17190 var y = e.getPageY();
17191 this.autoOffset(x, y);
17192 this.setDragElPos(x, y);
17195 // overrides Roo.dd.DragDrop
17196 b4StartDrag: function(x, y) {
17197 // show the drag frame
17198 this.showFrame(x, y);
17201 // overrides Roo.dd.DragDrop
17202 b4EndDrag: function(e) {
17203 Roo.fly(this.getDragEl()).hide();
17206 // overrides Roo.dd.DragDrop
17207 // By default we try to move the element to the last location of the frame.
17208 // This is so that the default behavior mirrors that of Roo.dd.DD.
17209 endDrag: function(e) {
17211 var lel = this.getEl();
17212 var del = this.getDragEl();
17214 // Show the drag frame briefly so we can get its position
17215 del.style.visibility = "";
17218 // Hide the linked element before the move to get around a Safari
17220 lel.style.visibility = "hidden";
17221 Roo.dd.DDM.moveToEl(lel, del);
17222 del.style.visibility = "hidden";
17223 lel.style.visibility = "";
17228 beforeMove : function(){
17232 afterDrag : function(){
17236 toString: function() {
17237 return ("DDProxy " + this.id);
17243 * Ext JS Library 1.1.1
17244 * Copyright(c) 2006-2007, Ext JS, LLC.
17246 * Originally Released Under LGPL - original licence link has changed is not relivant.
17249 * <script type="text/javascript">
17253 * @class Roo.dd.DDTarget
17254 * A DragDrop implementation that does not move, but can be a drop
17255 * target. You would get the same result by simply omitting implementation
17256 * for the event callbacks, but this way we reduce the processing cost of the
17257 * event listener and the callbacks.
17258 * @extends Roo.dd.DragDrop
17260 * @param {String} id the id of the element that is a drop target
17261 * @param {String} sGroup the group of related DragDrop objects
17262 * @param {object} config an object containing configurable attributes
17263 * Valid properties for DDTarget in addition to those in
17267 Roo.dd.DDTarget = function(id, sGroup, config) {
17269 this.initTarget(id, sGroup, config);
17273 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17274 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17275 toString: function() {
17276 return ("DDTarget " + this.id);
17281 * Ext JS Library 1.1.1
17282 * Copyright(c) 2006-2007, Ext JS, LLC.
17284 * Originally Released Under LGPL - original licence link has changed is not relivant.
17287 * <script type="text/javascript">
17292 * @class Roo.dd.ScrollManager
17293 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17294 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17297 Roo.dd.ScrollManager = function(){
17298 var ddm = Roo.dd.DragDropMgr;
17303 var onStop = function(e){
17308 var triggerRefresh = function(){
17309 if(ddm.dragCurrent){
17310 ddm.refreshCache(ddm.dragCurrent.groups);
17314 var doScroll = function(){
17315 if(ddm.dragCurrent){
17316 var dds = Roo.dd.ScrollManager;
17318 if(proc.el.scroll(proc.dir, dds.increment)){
17322 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17327 var clearProc = function(){
17329 clearInterval(proc.id);
17336 var startProc = function(el, dir){
17340 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17343 var onFire = function(e, isDrop){
17344 if(isDrop || !ddm.dragCurrent){ return; }
17345 var dds = Roo.dd.ScrollManager;
17346 if(!dragEl || dragEl != ddm.dragCurrent){
17347 dragEl = ddm.dragCurrent;
17348 // refresh regions on drag start
17349 dds.refreshCache();
17352 var xy = Roo.lib.Event.getXY(e);
17353 var pt = new Roo.lib.Point(xy[0], xy[1]);
17354 for(var id in els){
17355 var el = els[id], r = el._region;
17356 if(r && r.contains(pt) && el.isScrollable()){
17357 if(r.bottom - pt.y <= dds.thresh){
17359 startProc(el, "down");
17362 }else if(r.right - pt.x <= dds.thresh){
17364 startProc(el, "left");
17367 }else if(pt.y - r.top <= dds.thresh){
17369 startProc(el, "up");
17372 }else if(pt.x - r.left <= dds.thresh){
17374 startProc(el, "right");
17383 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17384 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17388 * Registers new overflow element(s) to auto scroll
17389 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17391 register : function(el){
17392 if(el instanceof Array){
17393 for(var i = 0, len = el.length; i < len; i++) {
17394 this.register(el[i]);
17403 * Unregisters overflow element(s) so they are no longer scrolled
17404 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17406 unregister : function(el){
17407 if(el instanceof Array){
17408 for(var i = 0, len = el.length; i < len; i++) {
17409 this.unregister(el[i]);
17418 * The number of pixels from the edge of a container the pointer needs to be to
17419 * trigger scrolling (defaults to 25)
17425 * The number of pixels to scroll in each scroll increment (defaults to 50)
17431 * The frequency of scrolls in milliseconds (defaults to 500)
17437 * True to animate the scroll (defaults to true)
17443 * The animation duration in seconds -
17444 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17450 * Manually trigger a cache refresh.
17452 refreshCache : function(){
17453 for(var id in els){
17454 if(typeof els[id] == 'object'){ // for people extending the object prototype
17455 els[id]._region = els[id].getRegion();
17462 * Ext JS Library 1.1.1
17463 * Copyright(c) 2006-2007, Ext JS, LLC.
17465 * Originally Released Under LGPL - original licence link has changed is not relivant.
17468 * <script type="text/javascript">
17473 * @class Roo.dd.Registry
17474 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17475 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17478 Roo.dd.Registry = function(){
17481 var autoIdSeed = 0;
17483 var getId = function(el, autogen){
17484 if(typeof el == "string"){
17488 if(!id && autogen !== false){
17489 id = "roodd-" + (++autoIdSeed);
17497 * Register a drag drop element
17498 * @param {String|HTMLElement} element The id or DOM node to register
17499 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17500 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17501 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17502 * populated in the data object (if applicable):
17504 Value Description<br />
17505 --------- ------------------------------------------<br />
17506 handles Array of DOM nodes that trigger dragging<br />
17507 for the element being registered<br />
17508 isHandle True if the element passed in triggers<br />
17509 dragging itself, else false
17512 register : function(el, data){
17514 if(typeof el == "string"){
17515 el = document.getElementById(el);
17518 elements[getId(el)] = data;
17519 if(data.isHandle !== false){
17520 handles[data.ddel.id] = data;
17523 var hs = data.handles;
17524 for(var i = 0, len = hs.length; i < len; i++){
17525 handles[getId(hs[i])] = data;
17531 * Unregister a drag drop element
17532 * @param {String|HTMLElement} element The id or DOM node to unregister
17534 unregister : function(el){
17535 var id = getId(el, false);
17536 var data = elements[id];
17538 delete elements[id];
17540 var hs = data.handles;
17541 for(var i = 0, len = hs.length; i < len; i++){
17542 delete handles[getId(hs[i], false)];
17549 * Returns the handle registered for a DOM Node by id
17550 * @param {String|HTMLElement} id The DOM node or id to look up
17551 * @return {Object} handle The custom handle data
17553 getHandle : function(id){
17554 if(typeof id != "string"){ // must be element?
17557 return handles[id];
17561 * Returns the handle that is registered for the DOM node that is the target of the event
17562 * @param {Event} e The event
17563 * @return {Object} handle The custom handle data
17565 getHandleFromEvent : function(e){
17566 var t = Roo.lib.Event.getTarget(e);
17567 return t ? handles[t.id] : null;
17571 * Returns a custom data object that is registered for a DOM node by id
17572 * @param {String|HTMLElement} id The DOM node or id to look up
17573 * @return {Object} data The custom data
17575 getTarget : function(id){
17576 if(typeof id != "string"){ // must be element?
17579 return elements[id];
17583 * Returns a custom data object that is registered for the DOM node that is the target of the event
17584 * @param {Event} e The event
17585 * @return {Object} data The custom data
17587 getTargetFromEvent : function(e){
17588 var t = Roo.lib.Event.getTarget(e);
17589 return t ? elements[t.id] || handles[t.id] : null;
17594 * Ext JS Library 1.1.1
17595 * Copyright(c) 2006-2007, Ext JS, LLC.
17597 * Originally Released Under LGPL - original licence link has changed is not relivant.
17600 * <script type="text/javascript">
17605 * @class Roo.dd.StatusProxy
17606 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17607 * default drag proxy used by all Roo.dd components.
17609 * @param {Object} config
17611 Roo.dd.StatusProxy = function(config){
17612 Roo.apply(this, config);
17613 this.id = this.id || Roo.id();
17614 this.el = new Roo.Layer({
17616 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17617 {tag: "div", cls: "x-dd-drop-icon"},
17618 {tag: "div", cls: "x-dd-drag-ghost"}
17621 shadow: !config || config.shadow !== false
17623 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17624 this.dropStatus = this.dropNotAllowed;
17627 Roo.dd.StatusProxy.prototype = {
17629 * @cfg {String} dropAllowed
17630 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17632 dropAllowed : "x-dd-drop-ok",
17634 * @cfg {String} dropNotAllowed
17635 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17637 dropNotAllowed : "x-dd-drop-nodrop",
17640 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17641 * over the current target element.
17642 * @param {String} cssClass The css class for the new drop status indicator image
17644 setStatus : function(cssClass){
17645 cssClass = cssClass || this.dropNotAllowed;
17646 if(this.dropStatus != cssClass){
17647 this.el.replaceClass(this.dropStatus, cssClass);
17648 this.dropStatus = cssClass;
17653 * Resets the status indicator to the default dropNotAllowed value
17654 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17656 reset : function(clearGhost){
17657 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17658 this.dropStatus = this.dropNotAllowed;
17660 this.ghost.update("");
17665 * Updates the contents of the ghost element
17666 * @param {String} html The html that will replace the current innerHTML of the ghost element
17668 update : function(html){
17669 if(typeof html == "string"){
17670 this.ghost.update(html);
17672 this.ghost.update("");
17673 html.style.margin = "0";
17674 this.ghost.dom.appendChild(html);
17676 // ensure float = none set?? cant remember why though.
17677 var el = this.ghost.dom.firstChild;
17679 Roo.fly(el).setStyle('float', 'none');
17684 * Returns the underlying proxy {@link Roo.Layer}
17685 * @return {Roo.Layer} el
17687 getEl : function(){
17692 * Returns the ghost element
17693 * @return {Roo.Element} el
17695 getGhost : function(){
17701 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17703 hide : function(clear){
17711 * Stops the repair animation if it's currently running
17714 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17720 * Displays this proxy
17727 * Force the Layer to sync its shadow and shim positions to the element
17734 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17735 * invalid drop operation by the item being dragged.
17736 * @param {Array} xy The XY position of the element ([x, y])
17737 * @param {Function} callback The function to call after the repair is complete
17738 * @param {Object} scope The scope in which to execute the callback
17740 repair : function(xy, callback, scope){
17741 this.callback = callback;
17742 this.scope = scope;
17743 if(xy && this.animRepair !== false){
17744 this.el.addClass("x-dd-drag-repair");
17745 this.el.hideUnders(true);
17746 this.anim = this.el.shift({
17747 duration: this.repairDuration || .5,
17751 callback: this.afterRepair,
17755 this.afterRepair();
17760 afterRepair : function(){
17762 if(typeof this.callback == "function"){
17763 this.callback.call(this.scope || this);
17765 this.callback = null;
17770 * Ext JS Library 1.1.1
17771 * Copyright(c) 2006-2007, Ext JS, LLC.
17773 * Originally Released Under LGPL - original licence link has changed is not relivant.
17776 * <script type="text/javascript">
17780 * @class Roo.dd.DragSource
17781 * @extends Roo.dd.DDProxy
17782 * A simple class that provides the basic implementation needed to make any element draggable.
17784 * @param {String/HTMLElement/Element} el The container element
17785 * @param {Object} config
17787 Roo.dd.DragSource = function(el, config){
17788 this.el = Roo.get(el);
17789 this.dragData = {};
17791 Roo.apply(this, config);
17794 this.proxy = new Roo.dd.StatusProxy();
17797 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17798 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17800 this.dragging = false;
17803 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17805 * @cfg {String} dropAllowed
17806 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17808 dropAllowed : "x-dd-drop-ok",
17810 * @cfg {String} dropNotAllowed
17811 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17813 dropNotAllowed : "x-dd-drop-nodrop",
17816 * Returns the data object associated with this drag source
17817 * @return {Object} data An object containing arbitrary data
17819 getDragData : function(e){
17820 return this.dragData;
17824 onDragEnter : function(e, id){
17825 var target = Roo.dd.DragDropMgr.getDDById(id);
17826 this.cachedTarget = target;
17827 if(this.beforeDragEnter(target, e, id) !== false){
17828 if(target.isNotifyTarget){
17829 var status = target.notifyEnter(this, e, this.dragData);
17830 this.proxy.setStatus(status);
17832 this.proxy.setStatus(this.dropAllowed);
17835 if(this.afterDragEnter){
17837 * An empty function by default, but provided so that you can perform a custom action
17838 * when the dragged item enters the drop target by providing an implementation.
17839 * @param {Roo.dd.DragDrop} target The drop target
17840 * @param {Event} e The event object
17841 * @param {String} id The id of the dragged element
17842 * @method afterDragEnter
17844 this.afterDragEnter(target, e, id);
17850 * An empty function by default, but provided so that you can perform a custom action
17851 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
17852 * @param {Roo.dd.DragDrop} target The drop target
17853 * @param {Event} e The event object
17854 * @param {String} id The id of the dragged element
17855 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17857 beforeDragEnter : function(target, e, id){
17862 alignElWithMouse: function() {
17863 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
17868 onDragOver : function(e, id){
17869 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17870 if(this.beforeDragOver(target, e, id) !== false){
17871 if(target.isNotifyTarget){
17872 var status = target.notifyOver(this, e, this.dragData);
17873 this.proxy.setStatus(status);
17876 if(this.afterDragOver){
17878 * An empty function by default, but provided so that you can perform a custom action
17879 * while the dragged item is over the drop target by providing an implementation.
17880 * @param {Roo.dd.DragDrop} target The drop target
17881 * @param {Event} e The event object
17882 * @param {String} id The id of the dragged element
17883 * @method afterDragOver
17885 this.afterDragOver(target, e, id);
17891 * An empty function by default, but provided so that you can perform a custom action
17892 * while the dragged item is over the drop target and optionally cancel the onDragOver.
17893 * @param {Roo.dd.DragDrop} target The drop target
17894 * @param {Event} e The event object
17895 * @param {String} id The id of the dragged element
17896 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17898 beforeDragOver : function(target, e, id){
17903 onDragOut : function(e, id){
17904 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17905 if(this.beforeDragOut(target, e, id) !== false){
17906 if(target.isNotifyTarget){
17907 target.notifyOut(this, e, this.dragData);
17909 this.proxy.reset();
17910 if(this.afterDragOut){
17912 * An empty function by default, but provided so that you can perform a custom action
17913 * after the dragged item is dragged out of the target without dropping.
17914 * @param {Roo.dd.DragDrop} target The drop target
17915 * @param {Event} e The event object
17916 * @param {String} id The id of the dragged element
17917 * @method afterDragOut
17919 this.afterDragOut(target, e, id);
17922 this.cachedTarget = null;
17926 * An empty function by default, but provided so that you can perform a custom action before the dragged
17927 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
17928 * @param {Roo.dd.DragDrop} target The drop target
17929 * @param {Event} e The event object
17930 * @param {String} id The id of the dragged element
17931 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17933 beforeDragOut : function(target, e, id){
17938 onDragDrop : function(e, id){
17939 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17940 if(this.beforeDragDrop(target, e, id) !== false){
17941 if(target.isNotifyTarget){
17942 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
17943 this.onValidDrop(target, e, id);
17945 this.onInvalidDrop(target, e, id);
17948 this.onValidDrop(target, e, id);
17951 if(this.afterDragDrop){
17953 * An empty function by default, but provided so that you can perform a custom action
17954 * after a valid drag drop has occurred by providing an implementation.
17955 * @param {Roo.dd.DragDrop} target The drop target
17956 * @param {Event} e The event object
17957 * @param {String} id The id of the dropped element
17958 * @method afterDragDrop
17960 this.afterDragDrop(target, e, id);
17963 delete this.cachedTarget;
17967 * An empty function by default, but provided so that you can perform a custom action before the dragged
17968 * item is dropped onto the target and optionally cancel the onDragDrop.
17969 * @param {Roo.dd.DragDrop} target The drop target
17970 * @param {Event} e The event object
17971 * @param {String} id The id of the dragged element
17972 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
17974 beforeDragDrop : function(target, e, id){
17979 onValidDrop : function(target, e, id){
17981 if(this.afterValidDrop){
17983 * An empty function by default, but provided so that you can perform a custom action
17984 * after a valid drop has occurred by providing an implementation.
17985 * @param {Object} target The target DD
17986 * @param {Event} e The event object
17987 * @param {String} id The id of the dropped element
17988 * @method afterInvalidDrop
17990 this.afterValidDrop(target, e, id);
17995 getRepairXY : function(e, data){
17996 return this.el.getXY();
18000 onInvalidDrop : function(target, e, id){
18001 this.beforeInvalidDrop(target, e, id);
18002 if(this.cachedTarget){
18003 if(this.cachedTarget.isNotifyTarget){
18004 this.cachedTarget.notifyOut(this, e, this.dragData);
18006 this.cacheTarget = null;
18008 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18010 if(this.afterInvalidDrop){
18012 * An empty function by default, but provided so that you can perform a custom action
18013 * after an invalid drop has occurred by providing an implementation.
18014 * @param {Event} e The event object
18015 * @param {String} id The id of the dropped element
18016 * @method afterInvalidDrop
18018 this.afterInvalidDrop(e, id);
18023 afterRepair : function(){
18025 this.el.highlight(this.hlColor || "c3daf9");
18027 this.dragging = false;
18031 * An empty function by default, but provided so that you can perform a custom action after an invalid
18032 * drop has occurred.
18033 * @param {Roo.dd.DragDrop} target The drop target
18034 * @param {Event} e The event object
18035 * @param {String} id The id of the dragged element
18036 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18038 beforeInvalidDrop : function(target, e, id){
18043 handleMouseDown : function(e){
18044 if(this.dragging) {
18047 var data = this.getDragData(e);
18048 if(data && this.onBeforeDrag(data, e) !== false){
18049 this.dragData = data;
18051 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18056 * An empty function by default, but provided so that you can perform a custom action before the initial
18057 * drag event begins and optionally cancel it.
18058 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18059 * @param {Event} e The event object
18060 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18062 onBeforeDrag : function(data, e){
18067 * An empty function by default, but provided so that you can perform a custom action once the initial
18068 * drag event has begun. The drag cannot be canceled from this function.
18069 * @param {Number} x The x position of the click on the dragged object
18070 * @param {Number} y The y position of the click on the dragged object
18072 onStartDrag : Roo.emptyFn,
18074 // private - YUI override
18075 startDrag : function(x, y){
18076 this.proxy.reset();
18077 this.dragging = true;
18078 this.proxy.update("");
18079 this.onInitDrag(x, y);
18084 onInitDrag : function(x, y){
18085 var clone = this.el.dom.cloneNode(true);
18086 clone.id = Roo.id(); // prevent duplicate ids
18087 this.proxy.update(clone);
18088 this.onStartDrag(x, y);
18093 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18094 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18096 getProxy : function(){
18101 * Hides the drag source's {@link Roo.dd.StatusProxy}
18103 hideProxy : function(){
18105 this.proxy.reset(true);
18106 this.dragging = false;
18110 triggerCacheRefresh : function(){
18111 Roo.dd.DDM.refreshCache(this.groups);
18114 // private - override to prevent hiding
18115 b4EndDrag: function(e) {
18118 // private - override to prevent moving
18119 endDrag : function(e){
18120 this.onEndDrag(this.dragData, e);
18124 onEndDrag : function(data, e){
18127 // private - pin to cursor
18128 autoOffset : function(x, y) {
18129 this.setDelta(-12, -20);
18133 * Ext JS Library 1.1.1
18134 * Copyright(c) 2006-2007, Ext JS, LLC.
18136 * Originally Released Under LGPL - original licence link has changed is not relivant.
18139 * <script type="text/javascript">
18144 * @class Roo.dd.DropTarget
18145 * @extends Roo.dd.DDTarget
18146 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18147 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18149 * @param {String/HTMLElement/Element} el The container element
18150 * @param {Object} config
18152 Roo.dd.DropTarget = function(el, config){
18153 this.el = Roo.get(el);
18155 Roo.apply(this, config);
18157 if(this.containerScroll){
18158 Roo.dd.ScrollManager.register(this.el);
18161 Roo.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18166 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18168 * @cfg {String} overClass
18169 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18172 * @cfg {String} dropAllowed
18173 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18175 dropAllowed : "x-dd-drop-ok",
18177 * @cfg {String} dropNotAllowed
18178 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18180 dropNotAllowed : "x-dd-drop-nodrop",
18186 isNotifyTarget : true,
18189 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18190 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18191 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18192 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18193 * @param {Event} e The event
18194 * @param {Object} data An object containing arbitrary data supplied by the drag source
18195 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18196 * underlying {@link Roo.dd.StatusProxy} can be updated
18198 notifyEnter : function(dd, e, data){
18199 if(this.overClass){
18200 this.el.addClass(this.overClass);
18202 return this.dropAllowed;
18206 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18207 * This method will be called on every mouse movement while the drag source is over the drop target.
18208 * This default implementation simply returns the dropAllowed config value.
18209 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18210 * @param {Event} e The event
18211 * @param {Object} data An object containing arbitrary data supplied by the drag source
18212 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18213 * underlying {@link Roo.dd.StatusProxy} can be updated
18215 notifyOver : function(dd, e, data){
18216 return this.dropAllowed;
18220 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18221 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18222 * overClass (if any) from the drop element.
18223 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18224 * @param {Event} e The event
18225 * @param {Object} data An object containing arbitrary data supplied by the drag source
18227 notifyOut : function(dd, e, data){
18228 if(this.overClass){
18229 this.el.removeClass(this.overClass);
18234 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18235 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18236 * implementation that does something to process the drop event and returns true so that the drag source's
18237 * repair action does not run.
18238 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18239 * @param {Event} e The event
18240 * @param {Object} data An object containing arbitrary data supplied by the drag source
18241 * @return {Boolean} True if the drop was valid, else false
18243 notifyDrop : function(dd, e, data){
18248 * Ext JS Library 1.1.1
18249 * Copyright(c) 2006-2007, Ext JS, LLC.
18251 * Originally Released Under LGPL - original licence link has changed is not relivant.
18254 * <script type="text/javascript">
18259 * @class Roo.dd.DragZone
18260 * @extends Roo.dd.DragSource
18261 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18262 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18264 * @param {String/HTMLElement/Element} el The container element
18265 * @param {Object} config
18267 Roo.dd.DragZone = function(el, config){
18268 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18269 if(this.containerScroll){
18270 Roo.dd.ScrollManager.register(this.el);
18274 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18276 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18277 * for auto scrolling during drag operations.
18280 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18281 * method after a failed drop (defaults to "c3daf9" - light blue)
18285 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18286 * for a valid target to drag based on the mouse down. Override this method
18287 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18288 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18289 * @param {EventObject} e The mouse down event
18290 * @return {Object} The dragData
18292 getDragData : function(e){
18293 return Roo.dd.Registry.getHandleFromEvent(e);
18297 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18298 * this.dragData.ddel
18299 * @param {Number} x The x position of the click on the dragged object
18300 * @param {Number} y The y position of the click on the dragged object
18301 * @return {Boolean} true to continue the drag, false to cancel
18303 onInitDrag : function(x, y){
18304 this.proxy.update(this.dragData.ddel.cloneNode(true));
18305 this.onStartDrag(x, y);
18310 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18312 afterRepair : function(){
18314 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18316 this.dragging = false;
18320 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18321 * the XY of this.dragData.ddel
18322 * @param {EventObject} e The mouse up event
18323 * @return {Array} The xy location (e.g. [100, 200])
18325 getRepairXY : function(e){
18326 return Roo.Element.fly(this.dragData.ddel).getXY();
18330 * Ext JS Library 1.1.1
18331 * Copyright(c) 2006-2007, Ext JS, LLC.
18333 * Originally Released Under LGPL - original licence link has changed is not relivant.
18336 * <script type="text/javascript">
18339 * @class Roo.dd.DropZone
18340 * @extends Roo.dd.DropTarget
18341 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18342 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18344 * @param {String/HTMLElement/Element} el The container element
18345 * @param {Object} config
18347 Roo.dd.DropZone = function(el, config){
18348 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18351 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18353 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18354 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18355 * provide your own custom lookup.
18356 * @param {Event} e The event
18357 * @return {Object} data The custom data
18359 getTargetFromEvent : function(e){
18360 return Roo.dd.Registry.getTargetFromEvent(e);
18364 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18365 * that it has registered. This method has no default implementation and should be overridden to provide
18366 * node-specific processing if necessary.
18367 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18368 * {@link #getTargetFromEvent} for this node)
18369 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18370 * @param {Event} e The event
18371 * @param {Object} data An object containing arbitrary data supplied by the drag source
18373 onNodeEnter : function(n, dd, e, data){
18378 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18379 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18380 * overridden to provide the proper feedback.
18381 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18382 * {@link #getTargetFromEvent} for this node)
18383 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18384 * @param {Event} e The event
18385 * @param {Object} data An object containing arbitrary data supplied by the drag source
18386 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18387 * underlying {@link Roo.dd.StatusProxy} can be updated
18389 onNodeOver : function(n, dd, e, data){
18390 return this.dropAllowed;
18394 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18395 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18396 * node-specific processing if necessary.
18397 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18398 * {@link #getTargetFromEvent} for this node)
18399 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18400 * @param {Event} e The event
18401 * @param {Object} data An object containing arbitrary data supplied by the drag source
18403 onNodeOut : function(n, dd, e, data){
18408 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18409 * the drop node. The default implementation returns false, so it should be overridden to provide the
18410 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18411 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18412 * {@link #getTargetFromEvent} for this node)
18413 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18414 * @param {Event} e The event
18415 * @param {Object} data An object containing arbitrary data supplied by the drag source
18416 * @return {Boolean} True if the drop was valid, else false
18418 onNodeDrop : function(n, dd, e, data){
18423 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18424 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18425 * it should be overridden to provide the proper feedback if necessary.
18426 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18427 * @param {Event} e The event
18428 * @param {Object} data An object containing arbitrary data supplied by the drag source
18429 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18430 * underlying {@link Roo.dd.StatusProxy} can be updated
18432 onContainerOver : function(dd, e, data){
18433 return this.dropNotAllowed;
18437 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18438 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18439 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18440 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18441 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18442 * @param {Event} e The event
18443 * @param {Object} data An object containing arbitrary data supplied by the drag source
18444 * @return {Boolean} True if the drop was valid, else false
18446 onContainerDrop : function(dd, e, data){
18451 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18452 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18453 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18454 * you should override this method and provide a custom implementation.
18455 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18456 * @param {Event} e The event
18457 * @param {Object} data An object containing arbitrary data supplied by the drag source
18458 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18459 * underlying {@link Roo.dd.StatusProxy} can be updated
18461 notifyEnter : function(dd, e, data){
18462 return this.dropNotAllowed;
18466 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18467 * This method will be called on every mouse movement while the drag source is over the drop zone.
18468 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18469 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18470 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18471 * registered node, it will call {@link #onContainerOver}.
18472 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18473 * @param {Event} e The event
18474 * @param {Object} data An object containing arbitrary data supplied by the drag source
18475 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18476 * underlying {@link Roo.dd.StatusProxy} can be updated
18478 notifyOver : function(dd, e, data){
18479 var n = this.getTargetFromEvent(e);
18480 if(!n){ // not over valid drop target
18481 if(this.lastOverNode){
18482 this.onNodeOut(this.lastOverNode, dd, e, data);
18483 this.lastOverNode = null;
18485 return this.onContainerOver(dd, e, data);
18487 if(this.lastOverNode != n){
18488 if(this.lastOverNode){
18489 this.onNodeOut(this.lastOverNode, dd, e, data);
18491 this.onNodeEnter(n, dd, e, data);
18492 this.lastOverNode = n;
18494 return this.onNodeOver(n, dd, e, data);
18498 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18499 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18500 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18501 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18502 * @param {Event} e The event
18503 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18505 notifyOut : function(dd, e, data){
18506 if(this.lastOverNode){
18507 this.onNodeOut(this.lastOverNode, dd, e, data);
18508 this.lastOverNode = null;
18513 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18514 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18515 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18516 * otherwise it will call {@link #onContainerDrop}.
18517 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18518 * @param {Event} e The event
18519 * @param {Object} data An object containing arbitrary data supplied by the drag source
18520 * @return {Boolean} True if the drop was valid, else false
18522 notifyDrop : function(dd, e, data){
18523 if(this.lastOverNode){
18524 this.onNodeOut(this.lastOverNode, dd, e, data);
18525 this.lastOverNode = null;
18527 var n = this.getTargetFromEvent(e);
18529 this.onNodeDrop(n, dd, e, data) :
18530 this.onContainerDrop(dd, e, data);
18534 triggerCacheRefresh : function(){
18535 Roo.dd.DDM.refreshCache(this.groups);
18539 * Ext JS Library 1.1.1
18540 * Copyright(c) 2006-2007, Ext JS, LLC.
18542 * Originally Released Under LGPL - original licence link has changed is not relivant.
18545 * <script type="text/javascript">
18550 * @class Roo.data.SortTypes
18552 * Defines the default sorting (casting?) comparison functions used when sorting data.
18554 Roo.data.SortTypes = {
18556 * Default sort that does nothing
18557 * @param {Mixed} s The value being converted
18558 * @return {Mixed} The comparison value
18560 none : function(s){
18565 * The regular expression used to strip tags
18569 stripTagsRE : /<\/?[^>]+>/gi,
18572 * Strips all HTML tags to sort on text only
18573 * @param {Mixed} s The value being converted
18574 * @return {String} The comparison value
18576 asText : function(s){
18577 return String(s).replace(this.stripTagsRE, "");
18581 * Strips all HTML tags to sort on text only - Case insensitive
18582 * @param {Mixed} s The value being converted
18583 * @return {String} The comparison value
18585 asUCText : function(s){
18586 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18590 * Case insensitive string
18591 * @param {Mixed} s The value being converted
18592 * @return {String} The comparison value
18594 asUCString : function(s) {
18595 return String(s).toUpperCase();
18600 * @param {Mixed} s The value being converted
18601 * @return {Number} The comparison value
18603 asDate : function(s) {
18607 if(s instanceof Date){
18608 return s.getTime();
18610 return Date.parse(String(s));
18615 * @param {Mixed} s The value being converted
18616 * @return {Float} The comparison value
18618 asFloat : function(s) {
18619 var val = parseFloat(String(s).replace(/,/g, ""));
18620 if(isNaN(val)) val = 0;
18626 * @param {Mixed} s The value being converted
18627 * @return {Number} The comparison value
18629 asInt : function(s) {
18630 var val = parseInt(String(s).replace(/,/g, ""));
18631 if(isNaN(val)) val = 0;
18636 * Ext JS Library 1.1.1
18637 * Copyright(c) 2006-2007, Ext JS, LLC.
18639 * Originally Released Under LGPL - original licence link has changed is not relivant.
18642 * <script type="text/javascript">
18646 * @class Roo.data.Record
18647 * Instances of this class encapsulate both record <em>definition</em> information, and record
18648 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18649 * to access Records cached in an {@link Roo.data.Store} object.<br>
18651 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18652 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18655 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18657 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18658 * {@link #create}. The parameters are the same.
18659 * @param {Array} data An associative Array of data values keyed by the field name.
18660 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18661 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18662 * not specified an integer id is generated.
18664 Roo.data.Record = function(data, id){
18665 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18670 * Generate a constructor for a specific record layout.
18671 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18672 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18673 * Each field definition object may contain the following properties: <ul>
18674 * <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,
18675 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18676 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18677 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18678 * is being used, then this is a string containing the javascript expression to reference the data relative to
18679 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18680 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18681 * this may be omitted.</p></li>
18682 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18683 * <ul><li>auto (Default, implies no conversion)</li>
18688 * <li>date</li></ul></p></li>
18689 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18690 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18691 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18692 * by the Reader into an object that will be stored in the Record. It is passed the
18693 * following parameters:<ul>
18694 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18696 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18698 * <br>usage:<br><pre><code>
18699 var TopicRecord = Roo.data.Record.create(
18700 {name: 'title', mapping: 'topic_title'},
18701 {name: 'author', mapping: 'username'},
18702 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18703 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18704 {name: 'lastPoster', mapping: 'user2'},
18705 {name: 'excerpt', mapping: 'post_text'}
18708 var myNewRecord = new TopicRecord({
18709 title: 'Do my job please',
18712 lastPost: new Date(),
18713 lastPoster: 'Animal',
18714 excerpt: 'No way dude!'
18716 myStore.add(myNewRecord);
18721 Roo.data.Record.create = function(o){
18722 var f = function(){
18723 f.superclass.constructor.apply(this, arguments);
18725 Roo.extend(f, Roo.data.Record);
18726 var p = f.prototype;
18727 p.fields = new Roo.util.MixedCollection(false, function(field){
18730 for(var i = 0, len = o.length; i < len; i++){
18731 p.fields.add(new Roo.data.Field(o[i]));
18733 f.getField = function(name){
18734 return p.fields.get(name);
18739 Roo.data.Record.AUTO_ID = 1000;
18740 Roo.data.Record.EDIT = 'edit';
18741 Roo.data.Record.REJECT = 'reject';
18742 Roo.data.Record.COMMIT = 'commit';
18744 Roo.data.Record.prototype = {
18746 * Readonly flag - true if this record has been modified.
18755 join : function(store){
18756 this.store = store;
18760 * Set the named field to the specified value.
18761 * @param {String} name The name of the field to set.
18762 * @param {Object} value The value to set the field to.
18764 set : function(name, value){
18765 if(this.data[name] == value){
18769 if(!this.modified){
18770 this.modified = {};
18772 if(typeof this.modified[name] == 'undefined'){
18773 this.modified[name] = this.data[name];
18775 this.data[name] = value;
18777 this.store.afterEdit(this);
18782 * Get the value of the named field.
18783 * @param {String} name The name of the field to get the value of.
18784 * @return {Object} The value of the field.
18786 get : function(name){
18787 return this.data[name];
18791 beginEdit : function(){
18792 this.editing = true;
18793 this.modified = {};
18797 cancelEdit : function(){
18798 this.editing = false;
18799 delete this.modified;
18803 endEdit : function(){
18804 this.editing = false;
18805 if(this.dirty && this.store){
18806 this.store.afterEdit(this);
18811 * Usually called by the {@link Roo.data.Store} which owns the Record.
18812 * Rejects all changes made to the Record since either creation, or the last commit operation.
18813 * Modified fields are reverted to their original values.
18815 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18816 * of reject operations.
18818 reject : function(){
18819 var m = this.modified;
18821 if(typeof m[n] != "function"){
18822 this.data[n] = m[n];
18825 this.dirty = false;
18826 delete this.modified;
18827 this.editing = false;
18829 this.store.afterReject(this);
18834 * Usually called by the {@link Roo.data.Store} which owns the Record.
18835 * Commits all changes made to the Record since either creation, or the last commit operation.
18837 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18838 * of commit operations.
18840 commit : function(){
18841 this.dirty = false;
18842 delete this.modified;
18843 this.editing = false;
18845 this.store.afterCommit(this);
18850 hasError : function(){
18851 return this.error != null;
18855 clearError : function(){
18860 * Creates a copy of this record.
18861 * @param {String} id (optional) A new record id if you don't want to use this record's id
18864 copy : function(newId) {
18865 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
18869 * Ext JS Library 1.1.1
18870 * Copyright(c) 2006-2007, Ext JS, LLC.
18872 * Originally Released Under LGPL - original licence link has changed is not relivant.
18875 * <script type="text/javascript">
18881 * @class Roo.data.Store
18882 * @extends Roo.util.Observable
18883 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
18884 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
18886 * 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
18887 * has no knowledge of the format of the data returned by the Proxy.<br>
18889 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
18890 * instances from the data object. These records are cached and made available through accessor functions.
18892 * Creates a new Store.
18893 * @param {Object} config A config object containing the objects needed for the Store to access data,
18894 * and read the data into Records.
18896 Roo.data.Store = function(config){
18897 this.data = new Roo.util.MixedCollection(false);
18898 this.data.getKey = function(o){
18901 this.baseParams = {};
18903 this.paramNames = {
18910 if(config && config.data){
18911 this.inlineData = config.data;
18912 delete config.data;
18915 Roo.apply(this, config);
18917 if(this.reader){ // reader passed
18918 this.reader = Roo.factory(this.reader, Roo.data);
18919 this.reader.xmodule = this.xmodule || false;
18920 if(!this.recordType){
18921 this.recordType = this.reader.recordType;
18923 if(this.reader.onMetaChange){
18924 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
18928 if(this.recordType){
18929 this.fields = this.recordType.prototype.fields;
18931 this.modified = [];
18935 * @event datachanged
18936 * Fires when the data cache has changed, and a widget which is using this Store
18937 * as a Record cache should refresh its view.
18938 * @param {Store} this
18940 datachanged : true,
18942 * @event metachange
18943 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
18944 * @param {Store} this
18945 * @param {Object} meta The JSON metadata
18950 * Fires when Records have been added to the Store
18951 * @param {Store} this
18952 * @param {Roo.data.Record[]} records The array of Records added
18953 * @param {Number} index The index at which the record(s) were added
18958 * Fires when a Record has been removed from the Store
18959 * @param {Store} this
18960 * @param {Roo.data.Record} record The Record that was removed
18961 * @param {Number} index The index at which the record was removed
18966 * Fires when a Record has been updated
18967 * @param {Store} this
18968 * @param {Roo.data.Record} record The Record that was updated
18969 * @param {String} operation The update operation being performed. Value may be one of:
18971 Roo.data.Record.EDIT
18972 Roo.data.Record.REJECT
18973 Roo.data.Record.COMMIT
18979 * Fires when the data cache has been cleared.
18980 * @param {Store} this
18984 * @event beforeload
18985 * Fires before a request is made for a new data object. If the beforeload handler returns false
18986 * the load action will be canceled.
18987 * @param {Store} this
18988 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18993 * Fires after a new set of Records has been loaded.
18994 * @param {Store} this
18995 * @param {Roo.data.Record[]} records The Records that were loaded
18996 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19000 * @event loadexception
19001 * Fires if an exception occurs in the Proxy during loading.
19002 * Called with the signature of the Proxy's "loadexception" event.
19003 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19006 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19007 * @param {Object} load options
19008 * @param {Object} jsonData from your request (normally this contains the Exception)
19010 loadexception : true
19014 this.proxy = Roo.factory(this.proxy, Roo.data);
19015 this.proxy.xmodule = this.xmodule || false;
19016 this.relayEvents(this.proxy, ["loadexception"]);
19018 this.sortToggle = {};
19020 Roo.data.Store.superclass.constructor.call(this);
19022 if(this.inlineData){
19023 this.loadData(this.inlineData);
19024 delete this.inlineData;
19027 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19029 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19030 * without a remote query - used by combo/forms at present.
19034 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19037 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19040 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19041 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19044 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19045 * on any HTTP request
19048 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19051 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19052 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19054 remoteSort : false,
19057 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19058 * loaded or when a record is removed. (defaults to false).
19060 pruneModifiedRecords : false,
19063 lastOptions : null,
19066 * Add Records to the Store and fires the add event.
19067 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19069 add : function(records){
19070 records = [].concat(records);
19071 for(var i = 0, len = records.length; i < len; i++){
19072 records[i].join(this);
19074 var index = this.data.length;
19075 this.data.addAll(records);
19076 this.fireEvent("add", this, records, index);
19080 * Remove a Record from the Store and fires the remove event.
19081 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19083 remove : function(record){
19084 var index = this.data.indexOf(record);
19085 this.data.removeAt(index);
19086 if(this.pruneModifiedRecords){
19087 this.modified.remove(record);
19089 this.fireEvent("remove", this, record, index);
19093 * Remove all Records from the Store and fires the clear event.
19095 removeAll : function(){
19097 if(this.pruneModifiedRecords){
19098 this.modified = [];
19100 this.fireEvent("clear", this);
19104 * Inserts Records to the Store at the given index and fires the add event.
19105 * @param {Number} index The start index at which to insert the passed Records.
19106 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19108 insert : function(index, records){
19109 records = [].concat(records);
19110 for(var i = 0, len = records.length; i < len; i++){
19111 this.data.insert(index, records[i]);
19112 records[i].join(this);
19114 this.fireEvent("add", this, records, index);
19118 * Get the index within the cache of the passed Record.
19119 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19120 * @return {Number} The index of the passed Record. Returns -1 if not found.
19122 indexOf : function(record){
19123 return this.data.indexOf(record);
19127 * Get the index within the cache of the Record with the passed id.
19128 * @param {String} id The id of the Record to find.
19129 * @return {Number} The index of the Record. Returns -1 if not found.
19131 indexOfId : function(id){
19132 return this.data.indexOfKey(id);
19136 * Get the Record with the specified id.
19137 * @param {String} id The id of the Record to find.
19138 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19140 getById : function(id){
19141 return this.data.key(id);
19145 * Get the Record at the specified index.
19146 * @param {Number} index The index of the Record to find.
19147 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19149 getAt : function(index){
19150 return this.data.itemAt(index);
19154 * Returns a range of Records between specified indices.
19155 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19156 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19157 * @return {Roo.data.Record[]} An array of Records
19159 getRange : function(start, end){
19160 return this.data.getRange(start, end);
19164 storeOptions : function(o){
19165 o = Roo.apply({}, o);
19168 this.lastOptions = o;
19172 * Loads the Record cache from the configured Proxy using the configured Reader.
19174 * If using remote paging, then the first load call must specify the <em>start</em>
19175 * and <em>limit</em> properties in the options.params property to establish the initial
19176 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19178 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19179 * and this call will return before the new data has been loaded. Perform any post-processing
19180 * in a callback function, or in a "load" event handler.</strong>
19182 * @param {Object} options An object containing properties which control loading options:<ul>
19183 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19184 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19185 * passed the following arguments:<ul>
19186 * <li>r : Roo.data.Record[]</li>
19187 * <li>options: Options object from the load call</li>
19188 * <li>success: Boolean success indicator</li></ul></li>
19189 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19190 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19193 load : function(options){
19194 options = options || {};
19195 if(this.fireEvent("beforeload", this, options) !== false){
19196 this.storeOptions(options);
19197 var p = Roo.apply(options.params || {}, this.baseParams);
19198 if(this.sortInfo && this.remoteSort){
19199 var pn = this.paramNames;
19200 p[pn["sort"]] = this.sortInfo.field;
19201 p[pn["dir"]] = this.sortInfo.direction;
19203 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19208 * Reloads the Record cache from the configured Proxy using the configured Reader and
19209 * the options from the last load operation performed.
19210 * @param {Object} options (optional) An object containing properties which may override the options
19211 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19212 * the most recently used options are reused).
19214 reload : function(options){
19215 this.load(Roo.applyIf(options||{}, this.lastOptions));
19219 // Called as a callback by the Reader during a load operation.
19220 loadRecords : function(o, options, success){
19221 if(!o || success === false){
19222 if(success !== false){
19223 this.fireEvent("load", this, [], options);
19225 if(options.callback){
19226 options.callback.call(options.scope || this, [], options, false);
19230 // if data returned failure - throw an exception.
19231 if (o.success === false) {
19232 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19235 var r = o.records, t = o.totalRecords || r.length;
19236 if(!options || options.add !== true){
19237 if(this.pruneModifiedRecords){
19238 this.modified = [];
19240 for(var i = 0, len = r.length; i < len; i++){
19244 this.data = this.snapshot;
19245 delete this.snapshot;
19248 this.data.addAll(r);
19249 this.totalLength = t;
19251 this.fireEvent("datachanged", this);
19253 this.totalLength = Math.max(t, this.data.length+r.length);
19256 this.fireEvent("load", this, r, options);
19257 if(options.callback){
19258 options.callback.call(options.scope || this, r, options, true);
19263 * Loads data from a passed data block. A Reader which understands the format of the data
19264 * must have been configured in the constructor.
19265 * @param {Object} data The data block from which to read the Records. The format of the data expected
19266 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19267 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19269 loadData : function(o, append){
19270 var r = this.reader.readRecords(o);
19271 this.loadRecords(r, {add: append}, true);
19275 * Gets the number of cached records.
19277 * <em>If using paging, this may not be the total size of the dataset. If the data object
19278 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19279 * the data set size</em>
19281 getCount : function(){
19282 return this.data.length || 0;
19286 * Gets the total number of records in the dataset as returned by the server.
19288 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19289 * the dataset size</em>
19291 getTotalCount : function(){
19292 return this.totalLength || 0;
19296 * Returns the sort state of the Store as an object with two properties:
19298 field {String} The name of the field by which the Records are sorted
19299 direction {String} The sort order, "ASC" or "DESC"
19302 getSortState : function(){
19303 return this.sortInfo;
19307 applySort : function(){
19308 if(this.sortInfo && !this.remoteSort){
19309 var s = this.sortInfo, f = s.field;
19310 var st = this.fields.get(f).sortType;
19311 var fn = function(r1, r2){
19312 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19313 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19315 this.data.sort(s.direction, fn);
19316 if(this.snapshot && this.snapshot != this.data){
19317 this.snapshot.sort(s.direction, fn);
19323 * Sets the default sort column and order to be used by the next load operation.
19324 * @param {String} fieldName The name of the field to sort by.
19325 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19327 setDefaultSort : function(field, dir){
19328 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19332 * Sort the Records.
19333 * If remote sorting is used, the sort is performed on the server, and the cache is
19334 * reloaded. If local sorting is used, the cache is sorted internally.
19335 * @param {String} fieldName The name of the field to sort by.
19336 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19338 sort : function(fieldName, dir){
19339 var f = this.fields.get(fieldName);
19341 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19342 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19347 this.sortToggle[f.name] = dir;
19348 this.sortInfo = {field: f.name, direction: dir};
19349 if(!this.remoteSort){
19351 this.fireEvent("datachanged", this);
19353 this.load(this.lastOptions);
19358 * Calls the specified function for each of the Records in the cache.
19359 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19360 * Returning <em>false</em> aborts and exits the iteration.
19361 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19363 each : function(fn, scope){
19364 this.data.each(fn, scope);
19368 * Gets all records modified since the last commit. Modified records are persisted across load operations
19369 * (e.g., during paging).
19370 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19372 getModifiedRecords : function(){
19373 return this.modified;
19377 createFilterFn : function(property, value, anyMatch){
19378 if(!value.exec){ // not a regex
19379 value = String(value);
19380 if(value.length == 0){
19383 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19385 return function(r){
19386 return value.test(r.data[property]);
19391 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19392 * @param {String} property A field on your records
19393 * @param {Number} start The record index to start at (defaults to 0)
19394 * @param {Number} end The last record index to include (defaults to length - 1)
19395 * @return {Number} The sum
19397 sum : function(property, start, end){
19398 var rs = this.data.items, v = 0;
19399 start = start || 0;
19400 end = (end || end === 0) ? end : rs.length-1;
19402 for(var i = start; i <= end; i++){
19403 v += (rs[i].data[property] || 0);
19409 * Filter the records by a specified property.
19410 * @param {String} field A field on your records
19411 * @param {String/RegExp} value Either a string that the field
19412 * should start with or a RegExp to test against the field
19413 * @param {Boolean} anyMatch True to match any part not just the beginning
19415 filter : function(property, value, anyMatch){
19416 var fn = this.createFilterFn(property, value, anyMatch);
19417 return fn ? this.filterBy(fn) : this.clearFilter();
19421 * Filter by a function. The specified function will be called with each
19422 * record in this data source. If the function returns true the record is included,
19423 * otherwise it is filtered.
19424 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19425 * @param {Object} scope (optional) The scope of the function (defaults to this)
19427 filterBy : function(fn, scope){
19428 this.snapshot = this.snapshot || this.data;
19429 this.data = this.queryBy(fn, scope||this);
19430 this.fireEvent("datachanged", this);
19434 * Query the records by a specified property.
19435 * @param {String} field A field on your records
19436 * @param {String/RegExp} value Either a string that the field
19437 * should start with or a RegExp to test against the field
19438 * @param {Boolean} anyMatch True to match any part not just the beginning
19439 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19441 query : function(property, value, anyMatch){
19442 var fn = this.createFilterFn(property, value, anyMatch);
19443 return fn ? this.queryBy(fn) : this.data.clone();
19447 * Query by a function. The specified function will be called with each
19448 * record in this data source. If the function returns true the record is included
19450 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19451 * @param {Object} scope (optional) The scope of the function (defaults to this)
19452 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19454 queryBy : function(fn, scope){
19455 var data = this.snapshot || this.data;
19456 return data.filterBy(fn, scope||this);
19460 * Collects unique values for a particular dataIndex from this store.
19461 * @param {String} dataIndex The property to collect
19462 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19463 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19464 * @return {Array} An array of the unique values
19466 collect : function(dataIndex, allowNull, bypassFilter){
19467 var d = (bypassFilter === true && this.snapshot) ?
19468 this.snapshot.items : this.data.items;
19469 var v, sv, r = [], l = {};
19470 for(var i = 0, len = d.length; i < len; i++){
19471 v = d[i].data[dataIndex];
19473 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19482 * Revert to a view of the Record cache with no filtering applied.
19483 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19485 clearFilter : function(suppressEvent){
19486 if(this.snapshot && this.snapshot != this.data){
19487 this.data = this.snapshot;
19488 delete this.snapshot;
19489 if(suppressEvent !== true){
19490 this.fireEvent("datachanged", this);
19496 afterEdit : function(record){
19497 if(this.modified.indexOf(record) == -1){
19498 this.modified.push(record);
19500 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19504 afterReject : function(record){
19505 this.modified.remove(record);
19506 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19510 afterCommit : function(record){
19511 this.modified.remove(record);
19512 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19516 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19517 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19519 commitChanges : function(){
19520 var m = this.modified.slice(0);
19521 this.modified = [];
19522 for(var i = 0, len = m.length; i < len; i++){
19528 * Cancel outstanding changes on all changed records.
19530 rejectChanges : function(){
19531 var m = this.modified.slice(0);
19532 this.modified = [];
19533 for(var i = 0, len = m.length; i < len; i++){
19538 onMetaChange : function(meta, rtype, o){
19539 this.recordType = rtype;
19540 this.fields = rtype.prototype.fields;
19541 delete this.snapshot;
19542 this.sortInfo = meta.sortInfo;
19543 this.modified = [];
19544 this.fireEvent('metachange', this, this.reader.meta);
19548 * Ext JS Library 1.1.1
19549 * Copyright(c) 2006-2007, Ext JS, LLC.
19551 * Originally Released Under LGPL - original licence link has changed is not relivant.
19554 * <script type="text/javascript">
19558 * @class Roo.data.SimpleStore
19559 * @extends Roo.data.Store
19560 * Small helper class to make creating Stores from Array data easier.
19561 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19562 * @cfg {Array} fields An array of field definition objects, or field name strings.
19563 * @cfg {Array} data The multi-dimensional array of data
19565 * @param {Object} config
19567 Roo.data.SimpleStore = function(config){
19568 Roo.data.SimpleStore.superclass.constructor.call(this, {
19570 reader: new Roo.data.ArrayReader({
19573 Roo.data.Record.create(config.fields)
19575 proxy : new Roo.data.MemoryProxy(config.data)
19579 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19581 * Ext JS Library 1.1.1
19582 * Copyright(c) 2006-2007, Ext JS, LLC.
19584 * Originally Released Under LGPL - original licence link has changed is not relivant.
19587 * <script type="text/javascript">
19592 * @extends Roo.data.Store
19593 * @class Roo.data.JsonStore
19594 * Small helper class to make creating Stores for JSON data easier. <br/>
19596 var store = new Roo.data.JsonStore({
19597 url: 'get-images.php',
19599 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19602 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19603 * JsonReader and HttpProxy (unless inline data is provided).</b>
19604 * @cfg {Array} fields An array of field definition objects, or field name strings.
19606 * @param {Object} config
19608 Roo.data.JsonStore = function(c){
19609 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19610 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19611 reader: new Roo.data.JsonReader(c, c.fields)
19614 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19616 * Ext JS Library 1.1.1
19617 * Copyright(c) 2006-2007, Ext JS, LLC.
19619 * Originally Released Under LGPL - original licence link has changed is not relivant.
19622 * <script type="text/javascript">
19626 Roo.data.Field = function(config){
19627 if(typeof config == "string"){
19628 config = {name: config};
19630 Roo.apply(this, config);
19633 this.type = "auto";
19636 var st = Roo.data.SortTypes;
19637 // named sortTypes are supported, here we look them up
19638 if(typeof this.sortType == "string"){
19639 this.sortType = st[this.sortType];
19642 // set default sortType for strings and dates
19643 if(!this.sortType){
19646 this.sortType = st.asUCString;
19649 this.sortType = st.asDate;
19652 this.sortType = st.none;
19657 var stripRe = /[\$,%]/g;
19659 // prebuilt conversion function for this field, instead of
19660 // switching every time we're reading a value
19662 var cv, dateFormat = this.dateFormat;
19667 cv = function(v){ return v; };
19670 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19674 return v !== undefined && v !== null && v !== '' ?
19675 parseInt(String(v).replace(stripRe, ""), 10) : '';
19680 return v !== undefined && v !== null && v !== '' ?
19681 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19686 cv = function(v){ return v === true || v === "true" || v == 1; };
19693 if(v instanceof Date){
19697 if(dateFormat == "timestamp"){
19698 return new Date(v*1000);
19700 return Date.parseDate(v, dateFormat);
19702 var parsed = Date.parse(v);
19703 return parsed ? new Date(parsed) : null;
19712 Roo.data.Field.prototype = {
19720 * Ext JS Library 1.1.1
19721 * Copyright(c) 2006-2007, Ext JS, LLC.
19723 * Originally Released Under LGPL - original licence link has changed is not relivant.
19726 * <script type="text/javascript">
19729 // Base class for reading structured data from a data source. This class is intended to be
19730 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19733 * @class Roo.data.DataReader
19734 * Base class for reading structured data from a data source. This class is intended to be
19735 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19738 Roo.data.DataReader = function(meta, recordType){
19742 this.recordType = recordType instanceof Array ?
19743 Roo.data.Record.create(recordType) : recordType;
19746 Roo.data.DataReader.prototype = {
19748 * Create an empty record
19749 * @param {Object} data (optional) - overlay some values
19750 * @return {Roo.data.Record} record created.
19752 newRow : function(d) {
19754 this.recordType.prototype.fields.each(function(c) {
19756 case 'int' : da[c.name] = 0; break;
19757 case 'date' : da[c.name] = new Date(); break;
19758 case 'float' : da[c.name] = 0.0; break;
19759 case 'boolean' : da[c.name] = false; break;
19760 default : da[c.name] = ""; break;
19764 return new this.recordType(Roo.apply(da, d));
19769 * Ext JS Library 1.1.1
19770 * Copyright(c) 2006-2007, Ext JS, LLC.
19772 * Originally Released Under LGPL - original licence link has changed is not relivant.
19775 * <script type="text/javascript">
19779 * @class Roo.data.DataProxy
19780 * @extends Roo.data.Observable
19781 * This class is an abstract base class for implementations which provide retrieval of
19782 * unformatted data objects.<br>
19784 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19785 * (of the appropriate type which knows how to parse the data object) to provide a block of
19786 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19788 * Custom implementations must implement the load method as described in
19789 * {@link Roo.data.HttpProxy#load}.
19791 Roo.data.DataProxy = function(){
19794 * @event beforeload
19795 * Fires before a network request is made to retrieve a data object.
19796 * @param {Object} This DataProxy object.
19797 * @param {Object} params The params parameter to the load function.
19802 * Fires before the load method's callback is called.
19803 * @param {Object} This DataProxy object.
19804 * @param {Object} o The data object.
19805 * @param {Object} arg The callback argument object passed to the load function.
19809 * @event loadexception
19810 * Fires if an Exception occurs during data retrieval.
19811 * @param {Object} This DataProxy object.
19812 * @param {Object} o The data object.
19813 * @param {Object} arg The callback argument object passed to the load function.
19814 * @param {Object} e The Exception.
19816 loadexception : true
19818 Roo.data.DataProxy.superclass.constructor.call(this);
19821 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
19824 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
19828 * Ext JS Library 1.1.1
19829 * Copyright(c) 2006-2007, Ext JS, LLC.
19831 * Originally Released Under LGPL - original licence link has changed is not relivant.
19834 * <script type="text/javascript">
19837 * @class Roo.data.MemoryProxy
19838 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
19839 * to the Reader when its load method is called.
19841 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
19843 Roo.data.MemoryProxy = function(data){
19847 Roo.data.MemoryProxy.superclass.constructor.call(this);
19851 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
19853 * Load data from the requested source (in this case an in-memory
19854 * data object passed to the constructor), read the data object into
19855 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
19856 * process that block using the passed callback.
19857 * @param {Object} params This parameter is not used by the MemoryProxy class.
19858 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19859 * object into a block of Roo.data.Records.
19860 * @param {Function} callback The function into which to pass the block of Roo.data.records.
19861 * The function must be passed <ul>
19862 * <li>The Record block object</li>
19863 * <li>The "arg" argument from the load function</li>
19864 * <li>A boolean success indicator</li>
19866 * @param {Object} scope The scope in which to call the callback
19867 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19869 load : function(params, reader, callback, scope, arg){
19870 params = params || {};
19873 result = reader.readRecords(this.data);
19875 this.fireEvent("loadexception", this, arg, null, e);
19876 callback.call(scope, null, arg, false);
19879 callback.call(scope, result, arg, true);
19883 update : function(params, records){
19888 * Ext JS Library 1.1.1
19889 * Copyright(c) 2006-2007, Ext JS, LLC.
19891 * Originally Released Under LGPL - original licence link has changed is not relivant.
19894 * <script type="text/javascript">
19897 * @class Roo.data.HttpProxy
19898 * @extends Roo.data.DataProxy
19899 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
19900 * configured to reference a certain URL.<br><br>
19902 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
19903 * from which the running page was served.<br><br>
19905 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
19907 * Be aware that to enable the browser to parse an XML document, the server must set
19908 * the Content-Type header in the HTTP response to "text/xml".
19910 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
19911 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
19912 * will be used to make the request.
19914 Roo.data.HttpProxy = function(conn){
19915 Roo.data.HttpProxy.superclass.constructor.call(this);
19916 // is conn a conn config or a real conn?
19918 this.useAjax = !conn || !conn.events;
19922 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
19923 // thse are take from connection...
19926 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
19929 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
19930 * extra parameters to each request made by this object. (defaults to undefined)
19933 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
19934 * to each request made by this object. (defaults to undefined)
19937 * @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)
19940 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
19943 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
19949 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
19953 * Return the {@link Roo.data.Connection} object being used by this Proxy.
19954 * @return {Connection} The Connection object. This object may be used to subscribe to events on
19955 * a finer-grained basis than the DataProxy events.
19957 getConnection : function(){
19958 return this.useAjax ? Roo.Ajax : this.conn;
19962 * Load data from the configured {@link Roo.data.Connection}, read the data object into
19963 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
19964 * process that block using the passed callback.
19965 * @param {Object} params An object containing properties which are to be used as HTTP parameters
19966 * for the request to the remote server.
19967 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19968 * object into a block of Roo.data.Records.
19969 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
19970 * The function must be passed <ul>
19971 * <li>The Record block object</li>
19972 * <li>The "arg" argument from the load function</li>
19973 * <li>A boolean success indicator</li>
19975 * @param {Object} scope The scope in which to call the callback
19976 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19978 load : function(params, reader, callback, scope, arg){
19979 if(this.fireEvent("beforeload", this, params) !== false){
19981 params : params || {},
19983 callback : callback,
19988 callback : this.loadResponse,
19992 Roo.applyIf(o, this.conn);
19993 if(this.activeRequest){
19994 Roo.Ajax.abort(this.activeRequest);
19996 this.activeRequest = Roo.Ajax.request(o);
19998 this.conn.request(o);
20001 callback.call(scope||this, null, arg, false);
20006 loadResponse : function(o, success, response){
20007 delete this.activeRequest;
20009 this.fireEvent("loadexception", this, o, response);
20010 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20015 result = o.reader.read(response);
20017 this.fireEvent("loadexception", this, o, response, e);
20018 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20022 this.fireEvent("load", this, o, o.request.arg);
20023 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20027 update : function(dataSet){
20032 updateResponse : function(dataSet){
20037 * Ext JS Library 1.1.1
20038 * Copyright(c) 2006-2007, Ext JS, LLC.
20040 * Originally Released Under LGPL - original licence link has changed is not relivant.
20043 * <script type="text/javascript">
20047 * @class Roo.data.ScriptTagProxy
20048 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20049 * other than the originating domain of the running page.<br><br>
20051 * <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
20052 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20054 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20055 * source code that is used as the source inside a <script> tag.<br><br>
20057 * In order for the browser to process the returned data, the server must wrap the data object
20058 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20059 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20060 * depending on whether the callback name was passed:
20063 boolean scriptTag = false;
20064 String cb = request.getParameter("callback");
20067 response.setContentType("text/javascript");
20069 response.setContentType("application/x-json");
20071 Writer out = response.getWriter();
20073 out.write(cb + "(");
20075 out.print(dataBlock.toJsonString());
20082 * @param {Object} config A configuration object.
20084 Roo.data.ScriptTagProxy = function(config){
20085 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20086 Roo.apply(this, config);
20087 this.head = document.getElementsByTagName("head")[0];
20090 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20092 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20094 * @cfg {String} url The URL from which to request the data object.
20097 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20101 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20102 * the server the name of the callback function set up by the load call to process the returned data object.
20103 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20104 * javascript output which calls this named function passing the data object as its only parameter.
20106 callbackParam : "callback",
20108 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20109 * name to the request.
20114 * Load data from the configured URL, read the data object into
20115 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20116 * process that block using the passed callback.
20117 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20118 * for the request to the remote server.
20119 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20120 * object into a block of Roo.data.Records.
20121 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20122 * The function must be passed <ul>
20123 * <li>The Record block object</li>
20124 * <li>The "arg" argument from the load function</li>
20125 * <li>A boolean success indicator</li>
20127 * @param {Object} scope The scope in which to call the callback
20128 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20130 load : function(params, reader, callback, scope, arg){
20131 if(this.fireEvent("beforeload", this, params) !== false){
20133 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20135 var url = this.url;
20136 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20138 url += "&_dc=" + (new Date().getTime());
20140 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20143 cb : "stcCallback"+transId,
20144 scriptId : "stcScript"+transId,
20148 callback : callback,
20154 window[trans.cb] = function(o){
20155 conn.handleResponse(o, trans);
20158 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20160 if(this.autoAbort !== false){
20164 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20166 var script = document.createElement("script");
20167 script.setAttribute("src", url);
20168 script.setAttribute("type", "text/javascript");
20169 script.setAttribute("id", trans.scriptId);
20170 this.head.appendChild(script);
20172 this.trans = trans;
20174 callback.call(scope||this, null, arg, false);
20179 isLoading : function(){
20180 return this.trans ? true : false;
20184 * Abort the current server request.
20186 abort : function(){
20187 if(this.isLoading()){
20188 this.destroyTrans(this.trans);
20193 destroyTrans : function(trans, isLoaded){
20194 this.head.removeChild(document.getElementById(trans.scriptId));
20195 clearTimeout(trans.timeoutId);
20197 window[trans.cb] = undefined;
20199 delete window[trans.cb];
20202 // if hasn't been loaded, wait for load to remove it to prevent script error
20203 window[trans.cb] = function(){
20204 window[trans.cb] = undefined;
20206 delete window[trans.cb];
20213 handleResponse : function(o, trans){
20214 this.trans = false;
20215 this.destroyTrans(trans, true);
20218 result = trans.reader.readRecords(o);
20220 this.fireEvent("loadexception", this, o, trans.arg, e);
20221 trans.callback.call(trans.scope||window, null, trans.arg, false);
20224 this.fireEvent("load", this, o, trans.arg);
20225 trans.callback.call(trans.scope||window, result, trans.arg, true);
20229 handleFailure : function(trans){
20230 this.trans = false;
20231 this.destroyTrans(trans, false);
20232 this.fireEvent("loadexception", this, null, trans.arg);
20233 trans.callback.call(trans.scope||window, null, trans.arg, false);
20237 * Ext JS Library 1.1.1
20238 * Copyright(c) 2006-2007, Ext JS, LLC.
20240 * Originally Released Under LGPL - original licence link has changed is not relivant.
20243 * <script type="text/javascript">
20247 * @class Roo.data.JsonReader
20248 * @extends Roo.data.DataReader
20249 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20250 * based on mappings in a provided Roo.data.Record constructor.
20254 var RecordDef = Roo.data.Record.create([
20255 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20256 {name: 'occupation'} // This field will use "occupation" as the mapping.
20258 var myReader = new Roo.data.JsonReader({
20259 totalProperty: "results", // The property which contains the total dataset size (optional)
20260 root: "rows", // The property which contains an Array of row objects
20261 id: "id" // The property within each row object that provides an ID for the record (optional)
20265 * This would consume a JSON file like this:
20267 { 'results': 2, 'rows': [
20268 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20269 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20272 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20273 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20274 * paged from the remote server.
20275 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20276 * @cfg {String} root name of the property which contains the Array of row objects.
20277 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20279 * Create a new JsonReader
20280 * @param {Object} meta Metadata configuration options
20281 * @param {Object} recordType Either an Array of field definition objects,
20282 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20284 Roo.data.JsonReader = function(meta, recordType){
20287 // set some defaults:
20288 Roo.applyIf(meta, {
20289 totalProperty: 'total',
20290 successProperty : 'success',
20295 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20297 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20299 * This method is only used by a DataProxy which has retrieved data from a remote server.
20300 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20301 * @return {Object} data A data block which is used by an Roo.data.Store object as
20302 * a cache of Roo.data.Records.
20304 read : function(response){
20305 var json = response.responseText;
20307 var o = eval("("+json+")");
20309 throw {message: "JsonReader.read: Json object not found"};
20314 this.meta = o.metaData;
20315 this.recordType = Roo.data.Record.create(o.metaData.fields);
20316 this.onMetaChange(this.meta, this.recordType, o);
20318 return this.readRecords(o);
20321 // private function a store will implement
20322 onMetaChange : function(meta, recordType, o){
20329 simpleAccess: function(obj, subsc) {
20336 getJsonAccessor: function(){
20338 return function(expr) {
20340 return(re.test(expr))
20341 ? new Function("obj", "return obj." + expr)
20346 return Roo.emptyFn;
20351 * Create a data block containing Roo.data.Records from an XML document.
20352 * @param {Object} o An object which contains an Array of row objects in the property specified
20353 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20354 * which contains the total size of the dataset.
20355 * @return {Object} data A data block which is used by an Roo.data.Store object as
20356 * a cache of Roo.data.Records.
20358 readRecords : function(o){
20360 * After any data loads, the raw JSON data is available for further custom processing.
20364 var s = this.meta, Record = this.recordType,
20365 f = Record.prototype.fields, fi = f.items, fl = f.length;
20367 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20369 if(s.totalProperty) {
20370 this.getTotal = this.getJsonAccessor(s.totalProperty);
20372 if(s.successProperty) {
20373 this.getSuccess = this.getJsonAccessor(s.successProperty);
20375 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20377 var g = this.getJsonAccessor(s.id);
20378 this.getId = function(rec) {
20380 return (r === undefined || r === "") ? null : r;
20383 this.getId = function(){return null;};
20386 for(var i = 0; i < fl; i++){
20388 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20389 this.ef[i] = this.getJsonAccessor(map);
20393 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20394 if(s.totalProperty){
20395 var v = parseInt(this.getTotal(o), 10);
20400 if(s.successProperty){
20401 var v = this.getSuccess(o);
20402 if(v === false || v === 'false'){
20407 for(var i = 0; i < c; i++){
20410 var id = this.getId(n);
20411 for(var j = 0; j < fl; j++){
20413 var v = this.ef[j](n);
20414 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20416 var record = new Record(values, id);
20418 records[i] = record;
20423 totalRecords : totalRecords
20428 * Ext JS Library 1.1.1
20429 * Copyright(c) 2006-2007, Ext JS, LLC.
20431 * Originally Released Under LGPL - original licence link has changed is not relivant.
20434 * <script type="text/javascript">
20438 * @class Roo.data.XmlReader
20439 * @extends Roo.data.DataReader
20440 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20441 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20443 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20444 * header in the HTTP response must be set to "text/xml".</em>
20448 var RecordDef = Roo.data.Record.create([
20449 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20450 {name: 'occupation'} // This field will use "occupation" as the mapping.
20452 var myReader = new Roo.data.XmlReader({
20453 totalRecords: "results", // The element which contains the total dataset size (optional)
20454 record: "row", // The repeated element which contains row information
20455 id: "id" // The element within the row that provides an ID for the record (optional)
20459 * This would consume an XML file like this:
20463 <results>2</results>
20466 <name>Bill</name>
20467 <occupation>Gardener</occupation>
20471 <name>Ben</name>
20472 <occupation>Horticulturalist</occupation>
20476 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20477 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20478 * paged from the remote server.
20479 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20480 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20481 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20482 * a record identifier value.
20484 * Create a new XmlReader
20485 * @param {Object} meta Metadata configuration options
20486 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20487 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20488 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20490 Roo.data.XmlReader = function(meta, recordType){
20492 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20494 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20496 * This method is only used by a DataProxy which has retrieved data from a remote server.
20497 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20498 * to contain a method called 'responseXML' that returns an XML document object.
20499 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20500 * a cache of Roo.data.Records.
20502 read : function(response){
20503 var doc = response.responseXML;
20505 throw {message: "XmlReader.read: XML Document not available"};
20507 return this.readRecords(doc);
20511 * Create a data block containing Roo.data.Records from an XML document.
20512 * @param {Object} doc A parsed XML document.
20513 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20514 * a cache of Roo.data.Records.
20516 readRecords : function(doc){
20518 * After any data loads/reads, the raw XML Document is available for further custom processing.
20519 * @type XMLDocument
20521 this.xmlData = doc;
20522 var root = doc.documentElement || doc;
20523 var q = Roo.DomQuery;
20524 var recordType = this.recordType, fields = recordType.prototype.fields;
20525 var sid = this.meta.id;
20526 var totalRecords = 0, success = true;
20527 if(this.meta.totalRecords){
20528 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20531 if(this.meta.success){
20532 var sv = q.selectValue(this.meta.success, root, true);
20533 success = sv !== false && sv !== 'false';
20536 var ns = q.select(this.meta.record, root);
20537 for(var i = 0, len = ns.length; i < len; i++) {
20540 var id = sid ? q.selectValue(sid, n) : undefined;
20541 for(var j = 0, jlen = fields.length; j < jlen; j++){
20542 var f = fields.items[j];
20543 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20545 values[f.name] = v;
20547 var record = new recordType(values, id);
20549 records[records.length] = record;
20555 totalRecords : totalRecords || records.length
20560 * Ext JS Library 1.1.1
20561 * Copyright(c) 2006-2007, Ext JS, LLC.
20563 * Originally Released Under LGPL - original licence link has changed is not relivant.
20566 * <script type="text/javascript">
20570 * @class Roo.data.ArrayReader
20571 * @extends Roo.data.DataReader
20572 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20573 * Each element of that Array represents a row of data fields. The
20574 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20575 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20579 var RecordDef = Roo.data.Record.create([
20580 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20581 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20583 var myReader = new Roo.data.ArrayReader({
20584 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20588 * This would consume an Array like this:
20590 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20592 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20594 * Create a new JsonReader
20595 * @param {Object} meta Metadata configuration options.
20596 * @param {Object} recordType Either an Array of field definition objects
20597 * as specified to {@link Roo.data.Record#create},
20598 * or an {@link Roo.data.Record} object
20599 * created using {@link Roo.data.Record#create}.
20601 Roo.data.ArrayReader = function(meta, recordType){
20602 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20605 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20607 * Create a data block containing Roo.data.Records from an XML document.
20608 * @param {Object} o An Array of row objects which represents the dataset.
20609 * @return {Object} data A data block which is used by an Roo.data.Store object as
20610 * a cache of Roo.data.Records.
20612 readRecords : function(o){
20613 var sid = this.meta ? this.meta.id : null;
20614 var recordType = this.recordType, fields = recordType.prototype.fields;
20617 for(var i = 0; i < root.length; i++){
20620 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20621 for(var j = 0, jlen = fields.length; j < jlen; j++){
20622 var f = fields.items[j];
20623 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20624 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20626 values[f.name] = v;
20628 var record = new recordType(values, id);
20630 records[records.length] = record;
20634 totalRecords : records.length
20639 * Ext JS Library 1.1.1
20640 * Copyright(c) 2006-2007, Ext JS, LLC.
20642 * Originally Released Under LGPL - original licence link has changed is not relivant.
20645 * <script type="text/javascript">
20650 * @class Roo.data.Tree
20651 * @extends Roo.util.Observable
20652 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20653 * in the tree have most standard DOM functionality.
20655 * @param {Node} root (optional) The root node
20657 Roo.data.Tree = function(root){
20658 this.nodeHash = {};
20660 * The root node for this tree
20665 this.setRootNode(root);
20670 * Fires when a new child node is appended to a node in this tree.
20671 * @param {Tree} tree The owner tree
20672 * @param {Node} parent The parent node
20673 * @param {Node} node The newly appended node
20674 * @param {Number} index The index of the newly appended node
20679 * Fires when a child node is removed from a node in this tree.
20680 * @param {Tree} tree The owner tree
20681 * @param {Node} parent The parent node
20682 * @param {Node} node The child node removed
20687 * Fires when a node is moved to a new location in the tree
20688 * @param {Tree} tree The owner tree
20689 * @param {Node} node The node moved
20690 * @param {Node} oldParent The old parent of this node
20691 * @param {Node} newParent The new parent of this node
20692 * @param {Number} index The index it was moved to
20697 * Fires when a new child node is inserted in a node in this tree.
20698 * @param {Tree} tree The owner tree
20699 * @param {Node} parent The parent node
20700 * @param {Node} node The child node inserted
20701 * @param {Node} refNode The child node the node was inserted before
20705 * @event beforeappend
20706 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20707 * @param {Tree} tree The owner tree
20708 * @param {Node} parent The parent node
20709 * @param {Node} node The child node to be appended
20711 "beforeappend" : true,
20713 * @event beforeremove
20714 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20715 * @param {Tree} tree The owner tree
20716 * @param {Node} parent The parent node
20717 * @param {Node} node The child node to be removed
20719 "beforeremove" : true,
20721 * @event beforemove
20722 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20723 * @param {Tree} tree The owner tree
20724 * @param {Node} node The node being moved
20725 * @param {Node} oldParent The parent of the node
20726 * @param {Node} newParent The new parent the node is moving to
20727 * @param {Number} index The index it is being moved to
20729 "beforemove" : true,
20731 * @event beforeinsert
20732 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20733 * @param {Tree} tree The owner tree
20734 * @param {Node} parent The parent node
20735 * @param {Node} node The child node to be inserted
20736 * @param {Node} refNode The child node the node is being inserted before
20738 "beforeinsert" : true
20741 Roo.data.Tree.superclass.constructor.call(this);
20744 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20745 pathSeparator: "/",
20747 proxyNodeEvent : function(){
20748 return this.fireEvent.apply(this, arguments);
20752 * Returns the root node for this tree.
20755 getRootNode : function(){
20760 * Sets the root node for this tree.
20761 * @param {Node} node
20764 setRootNode : function(node){
20766 node.ownerTree = this;
20767 node.isRoot = true;
20768 this.registerNode(node);
20773 * Gets a node in this tree by its id.
20774 * @param {String} id
20777 getNodeById : function(id){
20778 return this.nodeHash[id];
20781 registerNode : function(node){
20782 this.nodeHash[node.id] = node;
20785 unregisterNode : function(node){
20786 delete this.nodeHash[node.id];
20789 toString : function(){
20790 return "[Tree"+(this.id?" "+this.id:"")+"]";
20795 * @class Roo.data.Node
20796 * @extends Roo.util.Observable
20797 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
20798 * @cfg {String} id The id for this node. If one is not specified, one is generated.
20800 * @param {Object} attributes The attributes/config for the node
20802 Roo.data.Node = function(attributes){
20804 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
20807 this.attributes = attributes || {};
20808 this.leaf = this.attributes.leaf;
20810 * The node id. @type String
20812 this.id = this.attributes.id;
20814 this.id = Roo.id(null, "ynode-");
20815 this.attributes.id = this.id;
20818 * All child nodes of this node. @type Array
20820 this.childNodes = [];
20821 if(!this.childNodes.indexOf){ // indexOf is a must
20822 this.childNodes.indexOf = function(o){
20823 for(var i = 0, len = this.length; i < len; i++){
20824 if(this[i] == o) return i;
20830 * The parent node for this node. @type Node
20832 this.parentNode = null;
20834 * The first direct child node of this node, or null if this node has no child nodes. @type Node
20836 this.firstChild = null;
20838 * The last direct child node of this node, or null if this node has no child nodes. @type Node
20840 this.lastChild = null;
20842 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
20844 this.previousSibling = null;
20846 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
20848 this.nextSibling = null;
20853 * Fires when a new child node is appended
20854 * @param {Tree} tree The owner tree
20855 * @param {Node} this This node
20856 * @param {Node} node The newly appended node
20857 * @param {Number} index The index of the newly appended node
20862 * Fires when a child node is removed
20863 * @param {Tree} tree The owner tree
20864 * @param {Node} this This node
20865 * @param {Node} node The removed node
20870 * Fires when this node is moved to a new location in the tree
20871 * @param {Tree} tree The owner tree
20872 * @param {Node} this This node
20873 * @param {Node} oldParent The old parent of this node
20874 * @param {Node} newParent The new parent of this node
20875 * @param {Number} index The index it was moved to
20880 * Fires when a new child node is inserted.
20881 * @param {Tree} tree The owner tree
20882 * @param {Node} this This node
20883 * @param {Node} node The child node inserted
20884 * @param {Node} refNode The child node the node was inserted before
20888 * @event beforeappend
20889 * Fires before a new child is appended, return false to cancel the append.
20890 * @param {Tree} tree The owner tree
20891 * @param {Node} this This node
20892 * @param {Node} node The child node to be appended
20894 "beforeappend" : true,
20896 * @event beforeremove
20897 * Fires before a child is removed, return false to cancel the remove.
20898 * @param {Tree} tree The owner tree
20899 * @param {Node} this This node
20900 * @param {Node} node The child node to be removed
20902 "beforeremove" : true,
20904 * @event beforemove
20905 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
20906 * @param {Tree} tree The owner tree
20907 * @param {Node} this This node
20908 * @param {Node} oldParent The parent of this node
20909 * @param {Node} newParent The new parent this node is moving to
20910 * @param {Number} index The index it is being moved to
20912 "beforemove" : true,
20914 * @event beforeinsert
20915 * Fires before a new child is inserted, return false to cancel the insert.
20916 * @param {Tree} tree The owner tree
20917 * @param {Node} this This node
20918 * @param {Node} node The child node to be inserted
20919 * @param {Node} refNode The child node the node is being inserted before
20921 "beforeinsert" : true
20923 this.listeners = this.attributes.listeners;
20924 Roo.data.Node.superclass.constructor.call(this);
20927 Roo.extend(Roo.data.Node, Roo.util.Observable, {
20928 fireEvent : function(evtName){
20929 // first do standard event for this node
20930 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
20933 // then bubble it up to the tree if the event wasn't cancelled
20934 var ot = this.getOwnerTree();
20936 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
20944 * Returns true if this node is a leaf
20945 * @return {Boolean}
20947 isLeaf : function(){
20948 return this.leaf === true;
20952 setFirstChild : function(node){
20953 this.firstChild = node;
20957 setLastChild : function(node){
20958 this.lastChild = node;
20963 * Returns true if this node is the last child of its parent
20964 * @return {Boolean}
20966 isLast : function(){
20967 return (!this.parentNode ? true : this.parentNode.lastChild == this);
20971 * Returns true if this node is the first child of its parent
20972 * @return {Boolean}
20974 isFirst : function(){
20975 return (!this.parentNode ? true : this.parentNode.firstChild == this);
20978 hasChildNodes : function(){
20979 return !this.isLeaf() && this.childNodes.length > 0;
20983 * Insert node(s) as the last child node of this node.
20984 * @param {Node/Array} node The node or Array of nodes to append
20985 * @return {Node} The appended node if single append, or null if an array was passed
20987 appendChild : function(node){
20989 if(node instanceof Array){
20991 }else if(arguments.length > 1){
20994 // if passed an array or multiple args do them one by one
20996 for(var i = 0, len = multi.length; i < len; i++) {
20997 this.appendChild(multi[i]);
21000 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21003 var index = this.childNodes.length;
21004 var oldParent = node.parentNode;
21005 // it's a move, make sure we move it cleanly
21007 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21010 oldParent.removeChild(node);
21012 index = this.childNodes.length;
21014 this.setFirstChild(node);
21016 this.childNodes.push(node);
21017 node.parentNode = this;
21018 var ps = this.childNodes[index-1];
21020 node.previousSibling = ps;
21021 ps.nextSibling = node;
21023 node.previousSibling = null;
21025 node.nextSibling = null;
21026 this.setLastChild(node);
21027 node.setOwnerTree(this.getOwnerTree());
21028 this.fireEvent("append", this.ownerTree, this, node, index);
21030 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21037 * Removes a child node from this node.
21038 * @param {Node} node The node to remove
21039 * @return {Node} The removed node
21041 removeChild : function(node){
21042 var index = this.childNodes.indexOf(node);
21046 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21050 // remove it from childNodes collection
21051 this.childNodes.splice(index, 1);
21054 if(node.previousSibling){
21055 node.previousSibling.nextSibling = node.nextSibling;
21057 if(node.nextSibling){
21058 node.nextSibling.previousSibling = node.previousSibling;
21061 // update child refs
21062 if(this.firstChild == node){
21063 this.setFirstChild(node.nextSibling);
21065 if(this.lastChild == node){
21066 this.setLastChild(node.previousSibling);
21069 node.setOwnerTree(null);
21070 // clear any references from the node
21071 node.parentNode = null;
21072 node.previousSibling = null;
21073 node.nextSibling = null;
21074 this.fireEvent("remove", this.ownerTree, this, node);
21079 * Inserts the first node before the second node in this nodes childNodes collection.
21080 * @param {Node} node The node to insert
21081 * @param {Node} refNode The node to insert before (if null the node is appended)
21082 * @return {Node} The inserted node
21084 insertBefore : function(node, refNode){
21085 if(!refNode){ // like standard Dom, refNode can be null for append
21086 return this.appendChild(node);
21089 if(node == refNode){
21093 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21096 var index = this.childNodes.indexOf(refNode);
21097 var oldParent = node.parentNode;
21098 var refIndex = index;
21100 // when moving internally, indexes will change after remove
21101 if(oldParent == this && this.childNodes.indexOf(node) < index){
21105 // it's a move, make sure we move it cleanly
21107 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21110 oldParent.removeChild(node);
21113 this.setFirstChild(node);
21115 this.childNodes.splice(refIndex, 0, node);
21116 node.parentNode = this;
21117 var ps = this.childNodes[refIndex-1];
21119 node.previousSibling = ps;
21120 ps.nextSibling = node;
21122 node.previousSibling = null;
21124 node.nextSibling = refNode;
21125 refNode.previousSibling = node;
21126 node.setOwnerTree(this.getOwnerTree());
21127 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21129 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21135 * Returns the child node at the specified index.
21136 * @param {Number} index
21139 item : function(index){
21140 return this.childNodes[index];
21144 * Replaces one child node in this node with another.
21145 * @param {Node} newChild The replacement node
21146 * @param {Node} oldChild The node to replace
21147 * @return {Node} The replaced node
21149 replaceChild : function(newChild, oldChild){
21150 this.insertBefore(newChild, oldChild);
21151 this.removeChild(oldChild);
21156 * Returns the index of a child node
21157 * @param {Node} node
21158 * @return {Number} The index of the node or -1 if it was not found
21160 indexOf : function(child){
21161 return this.childNodes.indexOf(child);
21165 * Returns the tree this node is in.
21168 getOwnerTree : function(){
21169 // if it doesn't have one, look for one
21170 if(!this.ownerTree){
21174 this.ownerTree = p.ownerTree;
21180 return this.ownerTree;
21184 * Returns depth of this node (the root node has a depth of 0)
21187 getDepth : function(){
21190 while(p.parentNode){
21198 setOwnerTree : function(tree){
21199 // if it's move, we need to update everyone
21200 if(tree != this.ownerTree){
21201 if(this.ownerTree){
21202 this.ownerTree.unregisterNode(this);
21204 this.ownerTree = tree;
21205 var cs = this.childNodes;
21206 for(var i = 0, len = cs.length; i < len; i++) {
21207 cs[i].setOwnerTree(tree);
21210 tree.registerNode(this);
21216 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21217 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21218 * @return {String} The path
21220 getPath : function(attr){
21221 attr = attr || "id";
21222 var p = this.parentNode;
21223 var b = [this.attributes[attr]];
21225 b.unshift(p.attributes[attr]);
21228 var sep = this.getOwnerTree().pathSeparator;
21229 return sep + b.join(sep);
21233 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21234 * function call will be the scope provided or the current node. The arguments to the function
21235 * will be the args provided or the current node. If the function returns false at any point,
21236 * the bubble is stopped.
21237 * @param {Function} fn The function to call
21238 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21239 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21241 bubble : function(fn, scope, args){
21244 if(fn.call(scope || p, args || p) === false){
21252 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21253 * function call will be the scope provided or the current node. The arguments to the function
21254 * will be the args provided or the current node. If the function returns false at any point,
21255 * the cascade is stopped on that branch.
21256 * @param {Function} fn The function to call
21257 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21258 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21260 cascade : function(fn, scope, args){
21261 if(fn.call(scope || this, args || this) !== false){
21262 var cs = this.childNodes;
21263 for(var i = 0, len = cs.length; i < len; i++) {
21264 cs[i].cascade(fn, scope, args);
21270 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21271 * function call will be the scope provided or the current node. The arguments to the function
21272 * will be the args provided or the current node. If the function returns false at any point,
21273 * the iteration stops.
21274 * @param {Function} fn The function to call
21275 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21276 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21278 eachChild : function(fn, scope, args){
21279 var cs = this.childNodes;
21280 for(var i = 0, len = cs.length; i < len; i++) {
21281 if(fn.call(scope || this, args || cs[i]) === false){
21288 * Finds the first child that has the attribute with the specified value.
21289 * @param {String} attribute The attribute name
21290 * @param {Mixed} value The value to search for
21291 * @return {Node} The found child or null if none was found
21293 findChild : function(attribute, value){
21294 var cs = this.childNodes;
21295 for(var i = 0, len = cs.length; i < len; i++) {
21296 if(cs[i].attributes[attribute] == value){
21304 * Finds the first child by a custom function. The child matches if the function passed
21306 * @param {Function} fn
21307 * @param {Object} scope (optional)
21308 * @return {Node} The found child or null if none was found
21310 findChildBy : function(fn, scope){
21311 var cs = this.childNodes;
21312 for(var i = 0, len = cs.length; i < len; i++) {
21313 if(fn.call(scope||cs[i], cs[i]) === true){
21321 * Sorts this nodes children using the supplied sort function
21322 * @param {Function} fn
21323 * @param {Object} scope (optional)
21325 sort : function(fn, scope){
21326 var cs = this.childNodes;
21327 var len = cs.length;
21329 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21331 for(var i = 0; i < len; i++){
21333 n.previousSibling = cs[i-1];
21334 n.nextSibling = cs[i+1];
21336 this.setFirstChild(n);
21339 this.setLastChild(n);
21346 * Returns true if this node is an ancestor (at any point) of the passed node.
21347 * @param {Node} node
21348 * @return {Boolean}
21350 contains : function(node){
21351 return node.isAncestor(this);
21355 * Returns true if the passed node is an ancestor (at any point) of this node.
21356 * @param {Node} node
21357 * @return {Boolean}
21359 isAncestor : function(node){
21360 var p = this.parentNode;
21370 toString : function(){
21371 return "[Node"+(this.id?" "+this.id:"")+"]";
21375 * Ext JS Library 1.1.1
21376 * Copyright(c) 2006-2007, Ext JS, LLC.
21378 * Originally Released Under LGPL - original licence link has changed is not relivant.
21381 * <script type="text/javascript">
21386 * @class Roo.ComponentMgr
21387 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21390 Roo.ComponentMgr = function(){
21391 var all = new Roo.util.MixedCollection();
21395 * Registers a component.
21396 * @param {Roo.Component} c The component
21398 register : function(c){
21403 * Unregisters a component.
21404 * @param {Roo.Component} c The component
21406 unregister : function(c){
21411 * Returns a component by id
21412 * @param {String} id The component id
21414 get : function(id){
21415 return all.get(id);
21419 * Registers a function that will be called when a specified component is added to ComponentMgr
21420 * @param {String} id The component id
21421 * @param {Funtction} fn The callback function
21422 * @param {Object} scope The scope of the callback
21424 onAvailable : function(id, fn, scope){
21425 all.on("add", function(index, o){
21427 fn.call(scope || o, o);
21428 all.un("add", fn, scope);
21435 * Ext JS Library 1.1.1
21436 * Copyright(c) 2006-2007, Ext JS, LLC.
21438 * Originally Released Under LGPL - original licence link has changed is not relivant.
21441 * <script type="text/javascript">
21445 * @class Roo.Component
21446 * @extends Roo.util.Observable
21447 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21448 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21449 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21450 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21451 * All visual components (widgets) that require rendering into a layout should subclass Component.
21453 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21454 * 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
21455 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21457 Roo.Component = function(config){
21458 config = config || {};
21459 if(config.tagName || config.dom || typeof config == "string"){ // element object
21460 config = {el: config, id: config.id || config};
21462 this.initialConfig = config;
21464 Roo.apply(this, config);
21468 * Fires after the component is disabled.
21469 * @param {Roo.Component} this
21474 * Fires after the component is enabled.
21475 * @param {Roo.Component} this
21479 * @event beforeshow
21480 * Fires before the component is shown. Return false to stop the show.
21481 * @param {Roo.Component} this
21486 * Fires after the component is shown.
21487 * @param {Roo.Component} this
21491 * @event beforehide
21492 * Fires before the component is hidden. Return false to stop the hide.
21493 * @param {Roo.Component} this
21498 * Fires after the component is hidden.
21499 * @param {Roo.Component} this
21503 * @event beforerender
21504 * Fires before the component is rendered. Return false to stop the render.
21505 * @param {Roo.Component} this
21507 beforerender : true,
21510 * Fires after the component is rendered.
21511 * @param {Roo.Component} this
21515 * @event beforedestroy
21516 * Fires before the component is destroyed. Return false to stop the destroy.
21517 * @param {Roo.Component} this
21519 beforedestroy : true,
21522 * Fires after the component is destroyed.
21523 * @param {Roo.Component} this
21528 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21530 Roo.ComponentMgr.register(this);
21531 Roo.Component.superclass.constructor.call(this);
21532 this.initComponent();
21533 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21534 this.render(this.renderTo);
21535 delete this.renderTo;
21540 Roo.Component.AUTO_ID = 1000;
21542 Roo.extend(Roo.Component, Roo.util.Observable, {
21544 * @property {Boolean} hidden
21545 * true if this component is hidden. Read-only.
21549 * true if this component is disabled. Read-only.
21553 * true if this component has been rendered. Read-only.
21557 /** @cfg {String} disableClass
21558 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21560 disabledClass : "x-item-disabled",
21561 /** @cfg {Boolean} allowDomMove
21562 * Whether the component can move the Dom node when rendering (defaults to true).
21564 allowDomMove : true,
21565 /** @cfg {String} hideMode
21566 * How this component should hidden. Supported values are
21567 * "visibility" (css visibility), "offsets" (negative offset position) and
21568 * "display" (css display) - defaults to "display".
21570 hideMode: 'display',
21573 ctype : "Roo.Component",
21575 /** @cfg {String} actionMode
21576 * which property holds the element that used for hide() / show() / disable() / enable()
21582 getActionEl : function(){
21583 return this[this.actionMode];
21586 initComponent : Roo.emptyFn,
21588 * If this is a lazy rendering component, render it to its container element.
21589 * @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.
21591 render : function(container, position){
21592 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21593 if(!container && this.el){
21594 this.el = Roo.get(this.el);
21595 container = this.el.dom.parentNode;
21596 this.allowDomMove = false;
21598 this.container = Roo.get(container);
21599 this.rendered = true;
21600 if(position !== undefined){
21601 if(typeof position == 'number'){
21602 position = this.container.dom.childNodes[position];
21604 position = Roo.getDom(position);
21607 this.onRender(this.container, position || null);
21609 this.el.addClass(this.cls);
21613 this.el.applyStyles(this.style);
21616 this.fireEvent("render", this);
21617 this.afterRender(this.container);
21629 // default function is not really useful
21630 onRender : function(ct, position){
21632 this.el = Roo.get(this.el);
21633 if(this.allowDomMove !== false){
21634 ct.dom.insertBefore(this.el.dom, position);
21640 getAutoCreate : function(){
21641 var cfg = typeof this.autoCreate == "object" ?
21642 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21643 if(this.id && !cfg.id){
21650 afterRender : Roo.emptyFn,
21653 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21654 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21656 destroy : function(){
21657 if(this.fireEvent("beforedestroy", this) !== false){
21658 this.purgeListeners();
21659 this.beforeDestroy();
21661 this.el.removeAllListeners();
21663 if(this.actionMode == "container"){
21664 this.container.remove();
21668 Roo.ComponentMgr.unregister(this);
21669 this.fireEvent("destroy", this);
21674 beforeDestroy : function(){
21679 onDestroy : function(){
21684 * Returns the underlying {@link Roo.Element}.
21685 * @return {Roo.Element} The element
21687 getEl : function(){
21692 * Returns the id of this component.
21695 getId : function(){
21700 * Try to focus this component.
21701 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21702 * @return {Roo.Component} this
21704 focus : function(selectText){
21707 if(selectText === true){
21708 this.el.dom.select();
21723 * Disable this component.
21724 * @return {Roo.Component} this
21726 disable : function(){
21730 this.disabled = true;
21731 this.fireEvent("disable", this);
21736 onDisable : function(){
21737 this.getActionEl().addClass(this.disabledClass);
21738 this.el.dom.disabled = true;
21742 * Enable this component.
21743 * @return {Roo.Component} this
21745 enable : function(){
21749 this.disabled = false;
21750 this.fireEvent("enable", this);
21755 onEnable : function(){
21756 this.getActionEl().removeClass(this.disabledClass);
21757 this.el.dom.disabled = false;
21761 * Convenience function for setting disabled/enabled by boolean.
21762 * @param {Boolean} disabled
21764 setDisabled : function(disabled){
21765 this[disabled ? "disable" : "enable"]();
21769 * Show this component.
21770 * @return {Roo.Component} this
21773 if(this.fireEvent("beforeshow", this) !== false){
21774 this.hidden = false;
21778 this.fireEvent("show", this);
21784 onShow : function(){
21785 var ae = this.getActionEl();
21786 if(this.hideMode == 'visibility'){
21787 ae.dom.style.visibility = "visible";
21788 }else if(this.hideMode == 'offsets'){
21789 ae.removeClass('x-hidden');
21791 ae.dom.style.display = "";
21796 * Hide this component.
21797 * @return {Roo.Component} this
21800 if(this.fireEvent("beforehide", this) !== false){
21801 this.hidden = true;
21805 this.fireEvent("hide", this);
21811 onHide : function(){
21812 var ae = this.getActionEl();
21813 if(this.hideMode == 'visibility'){
21814 ae.dom.style.visibility = "hidden";
21815 }else if(this.hideMode == 'offsets'){
21816 ae.addClass('x-hidden');
21818 ae.dom.style.display = "none";
21823 * Convenience function to hide or show this component by boolean.
21824 * @param {Boolean} visible True to show, false to hide
21825 * @return {Roo.Component} this
21827 setVisible: function(visible){
21837 * Returns true if this component is visible.
21839 isVisible : function(){
21840 return this.getActionEl().isVisible();
21843 cloneConfig : function(overrides){
21844 overrides = overrides || {};
21845 var id = overrides.id || Roo.id();
21846 var cfg = Roo.applyIf(overrides, this.initialConfig);
21847 cfg.id = id; // prevent dup id
21848 return new this.constructor(cfg);
21852 * Ext JS Library 1.1.1
21853 * Copyright(c) 2006-2007, Ext JS, LLC.
21855 * Originally Released Under LGPL - original licence link has changed is not relivant.
21858 * <script type="text/javascript">
21863 * @extends Roo.Element
21864 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
21865 * automatic maintaining of shadow/shim positions.
21866 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
21867 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
21868 * you can pass a string with a CSS class name. False turns off the shadow.
21869 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
21870 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
21871 * @cfg {String} cls CSS class to add to the element
21872 * @cfg {Number} zindex Starting z-index (defaults to 11000)
21873 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
21875 * @param {Object} config An object with config options.
21876 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
21879 Roo.Layer = function(config, existingEl){
21880 config = config || {};
21881 var dh = Roo.DomHelper;
21882 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
21884 this.dom = Roo.getDom(existingEl);
21887 var o = config.dh || {tag: "div", cls: "x-layer"};
21888 this.dom = dh.append(pel, o);
21891 this.addClass(config.cls);
21893 this.constrain = config.constrain !== false;
21894 this.visibilityMode = Roo.Element.VISIBILITY;
21896 this.id = this.dom.id = config.id;
21898 this.id = Roo.id(this.dom);
21900 this.zindex = config.zindex || this.getZIndex();
21901 this.position("absolute", this.zindex);
21903 this.shadowOffset = config.shadowOffset || 4;
21904 this.shadow = new Roo.Shadow({
21905 offset : this.shadowOffset,
21906 mode : config.shadow
21909 this.shadowOffset = 0;
21911 this.useShim = config.shim !== false && Roo.useShims;
21912 this.useDisplay = config.useDisplay;
21916 var supr = Roo.Element.prototype;
21918 // shims are shared among layer to keep from having 100 iframes
21921 Roo.extend(Roo.Layer, Roo.Element, {
21923 getZIndex : function(){
21924 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
21927 getShim : function(){
21934 var shim = shims.shift();
21936 shim = this.createShim();
21937 shim.enableDisplayMode('block');
21938 shim.dom.style.display = 'none';
21939 shim.dom.style.visibility = 'visible';
21941 var pn = this.dom.parentNode;
21942 if(shim.dom.parentNode != pn){
21943 pn.insertBefore(shim.dom, this.dom);
21945 shim.setStyle('z-index', this.getZIndex()-2);
21950 hideShim : function(){
21952 this.shim.setDisplayed(false);
21953 shims.push(this.shim);
21958 disableShadow : function(){
21960 this.shadowDisabled = true;
21961 this.shadow.hide();
21962 this.lastShadowOffset = this.shadowOffset;
21963 this.shadowOffset = 0;
21967 enableShadow : function(show){
21969 this.shadowDisabled = false;
21970 this.shadowOffset = this.lastShadowOffset;
21971 delete this.lastShadowOffset;
21979 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
21980 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
21981 sync : function(doShow){
21982 var sw = this.shadow;
21983 if(!this.updating && this.isVisible() && (sw || this.useShim)){
21984 var sh = this.getShim();
21986 var w = this.getWidth(),
21987 h = this.getHeight();
21989 var l = this.getLeft(true),
21990 t = this.getTop(true);
21992 if(sw && !this.shadowDisabled){
21993 if(doShow && !sw.isVisible()){
21996 sw.realign(l, t, w, h);
22002 // fit the shim behind the shadow, so it is shimmed too
22003 var a = sw.adjusts, s = sh.dom.style;
22004 s.left = (Math.min(l, l+a.l))+"px";
22005 s.top = (Math.min(t, t+a.t))+"px";
22006 s.width = (w+a.w)+"px";
22007 s.height = (h+a.h)+"px";
22014 sh.setLeftTop(l, t);
22021 destroy : function(){
22024 this.shadow.hide();
22026 this.removeAllListeners();
22027 var pn = this.dom.parentNode;
22029 pn.removeChild(this.dom);
22031 Roo.Element.uncache(this.id);
22034 remove : function(){
22039 beginUpdate : function(){
22040 this.updating = true;
22044 endUpdate : function(){
22045 this.updating = false;
22050 hideUnders : function(negOffset){
22052 this.shadow.hide();
22058 constrainXY : function(){
22059 if(this.constrain){
22060 var vw = Roo.lib.Dom.getViewWidth(),
22061 vh = Roo.lib.Dom.getViewHeight();
22062 var s = Roo.get(document).getScroll();
22064 var xy = this.getXY();
22065 var x = xy[0], y = xy[1];
22066 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22067 // only move it if it needs it
22069 // first validate right/bottom
22070 if((x + w) > vw+s.left){
22071 x = vw - w - this.shadowOffset;
22074 if((y + h) > vh+s.top){
22075 y = vh - h - this.shadowOffset;
22078 // then make sure top/left isn't negative
22089 var ay = this.avoidY;
22090 if(y <= ay && (y+h) >= ay){
22096 supr.setXY.call(this, xy);
22102 isVisible : function(){
22103 return this.visible;
22107 showAction : function(){
22108 this.visible = true; // track visibility to prevent getStyle calls
22109 if(this.useDisplay === true){
22110 this.setDisplayed("");
22111 }else if(this.lastXY){
22112 supr.setXY.call(this, this.lastXY);
22113 }else if(this.lastLT){
22114 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22119 hideAction : function(){
22120 this.visible = false;
22121 if(this.useDisplay === true){
22122 this.setDisplayed(false);
22124 this.setLeftTop(-10000,-10000);
22128 // overridden Element method
22129 setVisible : function(v, a, d, c, e){
22134 var cb = function(){
22139 }.createDelegate(this);
22140 supr.setVisible.call(this, true, true, d, cb, e);
22143 this.hideUnders(true);
22152 }.createDelegate(this);
22154 supr.setVisible.call(this, v, a, d, cb, e);
22163 storeXY : function(xy){
22164 delete this.lastLT;
22168 storeLeftTop : function(left, top){
22169 delete this.lastXY;
22170 this.lastLT = [left, top];
22174 beforeFx : function(){
22175 this.beforeAction();
22176 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22180 afterFx : function(){
22181 Roo.Layer.superclass.afterFx.apply(this, arguments);
22182 this.sync(this.isVisible());
22186 beforeAction : function(){
22187 if(!this.updating && this.shadow){
22188 this.shadow.hide();
22192 // overridden Element method
22193 setLeft : function(left){
22194 this.storeLeftTop(left, this.getTop(true));
22195 supr.setLeft.apply(this, arguments);
22199 setTop : function(top){
22200 this.storeLeftTop(this.getLeft(true), top);
22201 supr.setTop.apply(this, arguments);
22205 setLeftTop : function(left, top){
22206 this.storeLeftTop(left, top);
22207 supr.setLeftTop.apply(this, arguments);
22211 setXY : function(xy, a, d, c, e){
22213 this.beforeAction();
22215 var cb = this.createCB(c);
22216 supr.setXY.call(this, xy, a, d, cb, e);
22223 createCB : function(c){
22234 // overridden Element method
22235 setX : function(x, a, d, c, e){
22236 this.setXY([x, this.getY()], a, d, c, e);
22239 // overridden Element method
22240 setY : function(y, a, d, c, e){
22241 this.setXY([this.getX(), y], a, d, c, e);
22244 // overridden Element method
22245 setSize : function(w, h, a, d, c, e){
22246 this.beforeAction();
22247 var cb = this.createCB(c);
22248 supr.setSize.call(this, w, h, a, d, cb, e);
22254 // overridden Element method
22255 setWidth : function(w, a, d, c, e){
22256 this.beforeAction();
22257 var cb = this.createCB(c);
22258 supr.setWidth.call(this, w, a, d, cb, e);
22264 // overridden Element method
22265 setHeight : function(h, a, d, c, e){
22266 this.beforeAction();
22267 var cb = this.createCB(c);
22268 supr.setHeight.call(this, h, a, d, cb, e);
22274 // overridden Element method
22275 setBounds : function(x, y, w, h, a, d, c, e){
22276 this.beforeAction();
22277 var cb = this.createCB(c);
22279 this.storeXY([x, y]);
22280 supr.setXY.call(this, [x, y]);
22281 supr.setSize.call(this, w, h, a, d, cb, e);
22284 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22290 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22291 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22292 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22293 * @param {Number} zindex The new z-index to set
22294 * @return {this} The Layer
22296 setZIndex : function(zindex){
22297 this.zindex = zindex;
22298 this.setStyle("z-index", zindex + 2);
22300 this.shadow.setZIndex(zindex + 1);
22303 this.shim.setStyle("z-index", zindex);
22309 * Ext JS Library 1.1.1
22310 * Copyright(c) 2006-2007, Ext JS, LLC.
22312 * Originally Released Under LGPL - original licence link has changed is not relivant.
22315 * <script type="text/javascript">
22320 * @class Roo.Shadow
22321 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22322 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22323 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22325 * Create a new Shadow
22326 * @param {Object} config The config object
22328 Roo.Shadow = function(config){
22329 Roo.apply(this, config);
22330 if(typeof this.mode != "string"){
22331 this.mode = this.defaultMode;
22333 var o = this.offset, a = {h: 0};
22334 var rad = Math.floor(this.offset/2);
22335 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22341 a.l -= this.offset + rad;
22342 a.t -= this.offset + rad;
22353 a.l -= (this.offset - rad);
22354 a.t -= this.offset + rad;
22356 a.w -= (this.offset - rad)*2;
22367 a.l -= (this.offset - rad);
22368 a.t -= (this.offset - rad);
22370 a.w -= (this.offset + rad + 1);
22371 a.h -= (this.offset + rad);
22380 Roo.Shadow.prototype = {
22382 * @cfg {String} mode
22383 * The shadow display mode. Supports the following options:<br />
22384 * sides: Shadow displays on both sides and bottom only<br />
22385 * frame: Shadow displays equally on all four sides<br />
22386 * drop: Traditional bottom-right drop shadow (default)
22389 * @cfg {String} offset
22390 * The number of pixels to offset the shadow from the element (defaults to 4)
22395 defaultMode: "drop",
22398 * Displays the shadow under the target element
22399 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22401 show : function(target){
22402 target = Roo.get(target);
22404 this.el = Roo.Shadow.Pool.pull();
22405 if(this.el.dom.nextSibling != target.dom){
22406 this.el.insertBefore(target);
22409 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22411 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22414 target.getLeft(true),
22415 target.getTop(true),
22419 this.el.dom.style.display = "block";
22423 * Returns true if the shadow is visible, else false
22425 isVisible : function(){
22426 return this.el ? true : false;
22430 * Direct alignment when values are already available. Show must be called at least once before
22431 * calling this method to ensure it is initialized.
22432 * @param {Number} left The target element left position
22433 * @param {Number} top The target element top position
22434 * @param {Number} width The target element width
22435 * @param {Number} height The target element height
22437 realign : function(l, t, w, h){
22441 var a = this.adjusts, d = this.el.dom, s = d.style;
22443 s.left = (l+a.l)+"px";
22444 s.top = (t+a.t)+"px";
22445 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22446 if(s.width != sws || s.height != shs){
22450 var cn = d.childNodes;
22451 var sww = Math.max(0, (sw-12))+"px";
22452 cn[0].childNodes[1].style.width = sww;
22453 cn[1].childNodes[1].style.width = sww;
22454 cn[2].childNodes[1].style.width = sww;
22455 cn[1].style.height = Math.max(0, (sh-12))+"px";
22461 * Hides this shadow
22465 this.el.dom.style.display = "none";
22466 Roo.Shadow.Pool.push(this.el);
22472 * Adjust the z-index of this shadow
22473 * @param {Number} zindex The new z-index
22475 setZIndex : function(z){
22478 this.el.setStyle("z-index", z);
22483 // Private utility class that manages the internal Shadow cache
22484 Roo.Shadow.Pool = function(){
22486 var markup = Roo.isIE ?
22487 '<div class="x-ie-shadow"></div>' :
22488 '<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>';
22491 var sh = p.shift();
22493 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22494 sh.autoBoxAdjust = false;
22499 push : function(sh){
22505 * Ext JS Library 1.1.1
22506 * Copyright(c) 2006-2007, Ext JS, LLC.
22508 * Originally Released Under LGPL - original licence link has changed is not relivant.
22511 * <script type="text/javascript">
22515 * @class Roo.BoxComponent
22516 * @extends Roo.Component
22517 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22518 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22519 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22520 * layout containers.
22522 * @param {Roo.Element/String/Object} config The configuration options.
22524 Roo.BoxComponent = function(config){
22525 Roo.Component.call(this, config);
22529 * Fires after the component is resized.
22530 * @param {Roo.Component} this
22531 * @param {Number} adjWidth The box-adjusted width that was set
22532 * @param {Number} adjHeight The box-adjusted height that was set
22533 * @param {Number} rawWidth The width that was originally specified
22534 * @param {Number} rawHeight The height that was originally specified
22539 * Fires after the component is moved.
22540 * @param {Roo.Component} this
22541 * @param {Number} x The new x position
22542 * @param {Number} y The new y position
22548 Roo.extend(Roo.BoxComponent, Roo.Component, {
22549 // private, set in afterRender to signify that the component has been rendered
22551 // private, used to defer height settings to subclasses
22552 deferHeight: false,
22553 /** @cfg {Number} width
22554 * width (optional) size of component
22556 /** @cfg {Number} height
22557 * height (optional) size of component
22561 * Sets the width and height of the component. This method fires the resize event. This method can accept
22562 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22563 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22564 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22565 * @return {Roo.BoxComponent} this
22567 setSize : function(w, h){
22568 // support for standard size objects
22569 if(typeof w == 'object'){
22574 if(!this.boxReady){
22580 // prevent recalcs when not needed
22581 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22584 this.lastSize = {width: w, height: h};
22586 var adj = this.adjustSize(w, h);
22587 var aw = adj.width, ah = adj.height;
22588 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22589 var rz = this.getResizeEl();
22590 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22591 rz.setSize(aw, ah);
22592 }else if(!this.deferHeight && ah !== undefined){
22594 }else if(aw !== undefined){
22597 this.onResize(aw, ah, w, h);
22598 this.fireEvent('resize', this, aw, ah, w, h);
22604 * Gets the current size of the component's underlying element.
22605 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22607 getSize : function(){
22608 return this.el.getSize();
22612 * Gets the current XY position of the component's underlying element.
22613 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22614 * @return {Array} The XY position of the element (e.g., [100, 200])
22616 getPosition : function(local){
22617 if(local === true){
22618 return [this.el.getLeft(true), this.el.getTop(true)];
22620 return this.xy || this.el.getXY();
22624 * Gets the current box measurements of the component's underlying element.
22625 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22626 * @returns {Object} box An object in the format {x, y, width, height}
22628 getBox : function(local){
22629 var s = this.el.getSize();
22631 s.x = this.el.getLeft(true);
22632 s.y = this.el.getTop(true);
22634 var xy = this.xy || this.el.getXY();
22642 * Sets the current box measurements of the component's underlying element.
22643 * @param {Object} box An object in the format {x, y, width, height}
22644 * @returns {Roo.BoxComponent} this
22646 updateBox : function(box){
22647 this.setSize(box.width, box.height);
22648 this.setPagePosition(box.x, box.y);
22653 getResizeEl : function(){
22654 return this.resizeEl || this.el;
22658 getPositionEl : function(){
22659 return this.positionEl || this.el;
22663 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22664 * This method fires the move event.
22665 * @param {Number} left The new left
22666 * @param {Number} top The new top
22667 * @returns {Roo.BoxComponent} this
22669 setPosition : function(x, y){
22672 if(!this.boxReady){
22675 var adj = this.adjustPosition(x, y);
22676 var ax = adj.x, ay = adj.y;
22678 var el = this.getPositionEl();
22679 if(ax !== undefined || ay !== undefined){
22680 if(ax !== undefined && ay !== undefined){
22681 el.setLeftTop(ax, ay);
22682 }else if(ax !== undefined){
22684 }else if(ay !== undefined){
22687 this.onPosition(ax, ay);
22688 this.fireEvent('move', this, ax, ay);
22694 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22695 * This method fires the move event.
22696 * @param {Number} x The new x position
22697 * @param {Number} y The new y position
22698 * @returns {Roo.BoxComponent} this
22700 setPagePosition : function(x, y){
22703 if(!this.boxReady){
22706 if(x === undefined || y === undefined){ // cannot translate undefined points
22709 var p = this.el.translatePoints(x, y);
22710 this.setPosition(p.left, p.top);
22715 onRender : function(ct, position){
22716 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22718 this.resizeEl = Roo.get(this.resizeEl);
22720 if(this.positionEl){
22721 this.positionEl = Roo.get(this.positionEl);
22726 afterRender : function(){
22727 Roo.BoxComponent.superclass.afterRender.call(this);
22728 this.boxReady = true;
22729 this.setSize(this.width, this.height);
22730 if(this.x || this.y){
22731 this.setPosition(this.x, this.y);
22733 if(this.pageX || this.pageY){
22734 this.setPagePosition(this.pageX, this.pageY);
22739 * Force the component's size to recalculate based on the underlying element's current height and width.
22740 * @returns {Roo.BoxComponent} this
22742 syncSize : function(){
22743 delete this.lastSize;
22744 this.setSize(this.el.getWidth(), this.el.getHeight());
22749 * Called after the component is resized, this method is empty by default but can be implemented by any
22750 * subclass that needs to perform custom logic after a resize occurs.
22751 * @param {Number} adjWidth The box-adjusted width that was set
22752 * @param {Number} adjHeight The box-adjusted height that was set
22753 * @param {Number} rawWidth The width that was originally specified
22754 * @param {Number} rawHeight The height that was originally specified
22756 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22761 * Called after the component is moved, this method is empty by default but can be implemented by any
22762 * subclass that needs to perform custom logic after a move occurs.
22763 * @param {Number} x The new x position
22764 * @param {Number} y The new y position
22766 onPosition : function(x, y){
22771 adjustSize : function(w, h){
22772 if(this.autoWidth){
22775 if(this.autoHeight){
22778 return {width : w, height: h};
22782 adjustPosition : function(x, y){
22783 return {x : x, y: y};
22787 * Ext JS Library 1.1.1
22788 * Copyright(c) 2006-2007, Ext JS, LLC.
22790 * Originally Released Under LGPL - original licence link has changed is not relivant.
22793 * <script type="text/javascript">
22798 * @class Roo.SplitBar
22799 * @extends Roo.util.Observable
22800 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
22804 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
22805 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
22806 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
22807 split.minSize = 100;
22808 split.maxSize = 600;
22809 split.animate = true;
22810 split.on('moved', splitterMoved);
22813 * Create a new SplitBar
22814 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
22815 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
22816 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22817 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
22818 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
22819 position of the SplitBar).
22821 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
22824 this.el = Roo.get(dragElement, true);
22825 this.el.dom.unselectable = "on";
22827 this.resizingEl = Roo.get(resizingElement, true);
22831 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22832 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
22835 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
22838 * The minimum size of the resizing element. (Defaults to 0)
22844 * The maximum size of the resizing element. (Defaults to 2000)
22847 this.maxSize = 2000;
22850 * Whether to animate the transition to the new size
22853 this.animate = false;
22856 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
22859 this.useShim = false;
22864 if(!existingProxy){
22866 this.proxy = Roo.SplitBar.createProxy(this.orientation);
22868 this.proxy = Roo.get(existingProxy).dom;
22871 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
22874 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
22877 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
22880 this.dragSpecs = {};
22883 * @private The adapter to use to positon and resize elements
22885 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
22886 this.adapter.init(this);
22888 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22890 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
22891 this.el.addClass("x-splitbar-h");
22894 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
22895 this.el.addClass("x-splitbar-v");
22901 * Fires when the splitter is moved (alias for {@link #event-moved})
22902 * @param {Roo.SplitBar} this
22903 * @param {Number} newSize the new width or height
22908 * Fires when the splitter is moved
22909 * @param {Roo.SplitBar} this
22910 * @param {Number} newSize the new width or height
22914 * @event beforeresize
22915 * Fires before the splitter is dragged
22916 * @param {Roo.SplitBar} this
22918 "beforeresize" : true,
22920 "beforeapply" : true
22923 Roo.util.Observable.call(this);
22926 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
22927 onStartProxyDrag : function(x, y){
22928 this.fireEvent("beforeresize", this);
22930 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
22932 o.enableDisplayMode("block");
22933 // all splitbars share the same overlay
22934 Roo.SplitBar.prototype.overlay = o;
22936 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
22937 this.overlay.show();
22938 Roo.get(this.proxy).setDisplayed("block");
22939 var size = this.adapter.getElementSize(this);
22940 this.activeMinSize = this.getMinimumSize();;
22941 this.activeMaxSize = this.getMaximumSize();;
22942 var c1 = size - this.activeMinSize;
22943 var c2 = Math.max(this.activeMaxSize - size, 0);
22944 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22945 this.dd.resetConstraints();
22946 this.dd.setXConstraint(
22947 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
22948 this.placement == Roo.SplitBar.LEFT ? c2 : c1
22950 this.dd.setYConstraint(0, 0);
22952 this.dd.resetConstraints();
22953 this.dd.setXConstraint(0, 0);
22954 this.dd.setYConstraint(
22955 this.placement == Roo.SplitBar.TOP ? c1 : c2,
22956 this.placement == Roo.SplitBar.TOP ? c2 : c1
22959 this.dragSpecs.startSize = size;
22960 this.dragSpecs.startPoint = [x, y];
22961 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
22965 * @private Called after the drag operation by the DDProxy
22967 onEndProxyDrag : function(e){
22968 Roo.get(this.proxy).setDisplayed(false);
22969 var endPoint = Roo.lib.Event.getXY(e);
22971 this.overlay.hide();
22974 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22975 newSize = this.dragSpecs.startSize +
22976 (this.placement == Roo.SplitBar.LEFT ?
22977 endPoint[0] - this.dragSpecs.startPoint[0] :
22978 this.dragSpecs.startPoint[0] - endPoint[0]
22981 newSize = this.dragSpecs.startSize +
22982 (this.placement == Roo.SplitBar.TOP ?
22983 endPoint[1] - this.dragSpecs.startPoint[1] :
22984 this.dragSpecs.startPoint[1] - endPoint[1]
22987 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
22988 if(newSize != this.dragSpecs.startSize){
22989 if(this.fireEvent('beforeapply', this, newSize) !== false){
22990 this.adapter.setElementSize(this, newSize);
22991 this.fireEvent("moved", this, newSize);
22992 this.fireEvent("resize", this, newSize);
22998 * Get the adapter this SplitBar uses
22999 * @return The adapter object
23001 getAdapter : function(){
23002 return this.adapter;
23006 * Set the adapter this SplitBar uses
23007 * @param {Object} adapter A SplitBar adapter object
23009 setAdapter : function(adapter){
23010 this.adapter = adapter;
23011 this.adapter.init(this);
23015 * Gets the minimum size for the resizing element
23016 * @return {Number} The minimum size
23018 getMinimumSize : function(){
23019 return this.minSize;
23023 * Sets the minimum size for the resizing element
23024 * @param {Number} minSize The minimum size
23026 setMinimumSize : function(minSize){
23027 this.minSize = minSize;
23031 * Gets the maximum size for the resizing element
23032 * @return {Number} The maximum size
23034 getMaximumSize : function(){
23035 return this.maxSize;
23039 * Sets the maximum size for the resizing element
23040 * @param {Number} maxSize The maximum size
23042 setMaximumSize : function(maxSize){
23043 this.maxSize = maxSize;
23047 * Sets the initialize size for the resizing element
23048 * @param {Number} size The initial size
23050 setCurrentSize : function(size){
23051 var oldAnimate = this.animate;
23052 this.animate = false;
23053 this.adapter.setElementSize(this, size);
23054 this.animate = oldAnimate;
23058 * Destroy this splitbar.
23059 * @param {Boolean} removeEl True to remove the element
23061 destroy : function(removeEl){
23063 this.shim.remove();
23066 this.proxy.parentNode.removeChild(this.proxy);
23074 * @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.
23076 Roo.SplitBar.createProxy = function(dir){
23077 var proxy = new Roo.Element(document.createElement("div"));
23078 proxy.unselectable();
23079 var cls = 'x-splitbar-proxy';
23080 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23081 document.body.appendChild(proxy.dom);
23086 * @class Roo.SplitBar.BasicLayoutAdapter
23087 * Default Adapter. It assumes the splitter and resizing element are not positioned
23088 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23090 Roo.SplitBar.BasicLayoutAdapter = function(){
23093 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23094 // do nothing for now
23095 init : function(s){
23099 * Called before drag operations to get the current size of the resizing element.
23100 * @param {Roo.SplitBar} s The SplitBar using this adapter
23102 getElementSize : function(s){
23103 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23104 return s.resizingEl.getWidth();
23106 return s.resizingEl.getHeight();
23111 * Called after drag operations to set the size of the resizing element.
23112 * @param {Roo.SplitBar} s The SplitBar using this adapter
23113 * @param {Number} newSize The new size to set
23114 * @param {Function} onComplete A function to be invoked when resizing is complete
23116 setElementSize : function(s, newSize, onComplete){
23117 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23119 s.resizingEl.setWidth(newSize);
23121 onComplete(s, newSize);
23124 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23129 s.resizingEl.setHeight(newSize);
23131 onComplete(s, newSize);
23134 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23141 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23142 * @extends Roo.SplitBar.BasicLayoutAdapter
23143 * Adapter that moves the splitter element to align with the resized sizing element.
23144 * Used with an absolute positioned SplitBar.
23145 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23146 * document.body, make sure you assign an id to the body element.
23148 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23149 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23150 this.container = Roo.get(container);
23153 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23154 init : function(s){
23155 this.basic.init(s);
23158 getElementSize : function(s){
23159 return this.basic.getElementSize(s);
23162 setElementSize : function(s, newSize, onComplete){
23163 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23166 moveSplitter : function(s){
23167 var yes = Roo.SplitBar;
23168 switch(s.placement){
23170 s.el.setX(s.resizingEl.getRight());
23173 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23176 s.el.setY(s.resizingEl.getBottom());
23179 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23186 * Orientation constant - Create a vertical SplitBar
23190 Roo.SplitBar.VERTICAL = 1;
23193 * Orientation constant - Create a horizontal SplitBar
23197 Roo.SplitBar.HORIZONTAL = 2;
23200 * Placement constant - The resizing element is to the left of the splitter element
23204 Roo.SplitBar.LEFT = 1;
23207 * Placement constant - The resizing element is to the right of the splitter element
23211 Roo.SplitBar.RIGHT = 2;
23214 * Placement constant - The resizing element is positioned above the splitter element
23218 Roo.SplitBar.TOP = 3;
23221 * Placement constant - The resizing element is positioned under splitter element
23225 Roo.SplitBar.BOTTOM = 4;
23228 * Ext JS Library 1.1.1
23229 * Copyright(c) 2006-2007, Ext JS, LLC.
23231 * Originally Released Under LGPL - original licence link has changed is not relivant.
23234 * <script type="text/javascript">
23239 * @extends Roo.util.Observable
23240 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23241 * This class also supports single and multi selection modes. <br>
23242 * Create a data model bound view:
23244 var store = new Roo.data.Store(...);
23246 var view = new Roo.View("my-element",
23247 '<div id="{0}">{2} - {1}</div>', // auto create template
23249 singleSelect: true,
23250 selectedClass: "ydataview-selected",
23254 // listen for node click?
23255 view.on("click", function(vw, index, node, e){
23256 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23260 dataModel.load("foobar.xml");
23262 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23264 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23265 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23267 * Create a new View
23268 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
23269 * @param {String/DomHelper.Template} tpl The rendering template or a string to create a template with
23270 * @param {Object} config The config object
23272 Roo.View = function(container, tpl, config){
23273 this.el = Roo.get(container);
23274 if(typeof tpl == "string"){
23275 tpl = new Roo.Template(tpl);
23279 * The template used by this View
23280 * @type {Roo.DomHelper.Template}
23284 Roo.apply(this, config);
23289 * @event beforeclick
23290 * Fires before a click is processed. Returns false to cancel the default action.
23291 * @param {Roo.View} this
23292 * @param {Number} index The index of the target node
23293 * @param {HTMLElement} node The target node
23294 * @param {Roo.EventObject} e The raw event object
23296 "beforeclick" : true,
23299 * Fires when a template node is clicked.
23300 * @param {Roo.View} this
23301 * @param {Number} index The index of the target node
23302 * @param {HTMLElement} node The target node
23303 * @param {Roo.EventObject} e The raw event object
23308 * Fires when a template node is double clicked.
23309 * @param {Roo.View} this
23310 * @param {Number} index The index of the target node
23311 * @param {HTMLElement} node The target node
23312 * @param {Roo.EventObject} e The raw event object
23316 * @event contextmenu
23317 * Fires when a template node is right clicked.
23318 * @param {Roo.View} this
23319 * @param {Number} index The index of the target node
23320 * @param {HTMLElement} node The target node
23321 * @param {Roo.EventObject} e The raw event object
23323 "contextmenu" : true,
23325 * @event selectionchange
23326 * Fires when the selected nodes change.
23327 * @param {Roo.View} this
23328 * @param {Array} selections Array of the selected nodes
23330 "selectionchange" : true,
23333 * @event beforeselect
23334 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23335 * @param {Roo.View} this
23336 * @param {HTMLElement} node The node to be selected
23337 * @param {Array} selections Array of currently selected nodes
23339 "beforeselect" : true
23343 "click": this.onClick,
23344 "dblclick": this.onDblClick,
23345 "contextmenu": this.onContextMenu,
23349 this.selections = [];
23351 this.cmp = new Roo.CompositeElementLite([]);
23353 this.store = Roo.factory(this.store, Roo.data);
23354 this.setStore(this.store, true);
23356 Roo.View.superclass.constructor.call(this);
23359 Roo.extend(Roo.View, Roo.util.Observable, {
23361 * The css class to add to selected nodes
23362 * @type {Roo.DomHelper.Template}
23364 selectedClass : "x-view-selected",
23368 * Returns the element this view is bound to.
23369 * @return {Roo.Element}
23371 getEl : function(){
23376 * Refreshes the view.
23378 refresh : function(){
23380 this.clearSelections();
23381 this.el.update("");
23383 var records = this.store.getRange();
23384 if(records.length < 1){
23385 this.el.update(this.emptyText);
23388 for(var i = 0, len = records.length; i < len; i++){
23389 var data = this.prepareData(records[i].data, i, records[i]);
23390 html[html.length] = t.apply(data);
23392 this.el.update(html.join(""));
23393 this.nodes = this.el.dom.childNodes;
23394 this.updateIndexes(0);
23398 * Function to override to reformat the data that is sent to
23399 * the template for each node.
23400 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23401 * a JSON object for an UpdateManager bound view).
23403 prepareData : function(data){
23407 onUpdate : function(ds, record){
23408 this.clearSelections();
23409 var index = this.store.indexOf(record);
23410 var n = this.nodes[index];
23411 this.tpl.insertBefore(n, this.prepareData(record.data));
23412 n.parentNode.removeChild(n);
23413 this.updateIndexes(index, index);
23416 onAdd : function(ds, records, index){
23417 this.clearSelections();
23418 if(this.nodes.length == 0){
23422 var n = this.nodes[index];
23423 for(var i = 0, len = records.length; i < len; i++){
23424 var d = this.prepareData(records[i].data);
23426 this.tpl.insertBefore(n, d);
23428 this.tpl.append(this.el, d);
23431 this.updateIndexes(index);
23434 onRemove : function(ds, record, index){
23435 this.clearSelections();
23436 this.el.dom.removeChild(this.nodes[index]);
23437 this.updateIndexes(index);
23441 * Refresh an individual node.
23442 * @param {Number} index
23444 refreshNode : function(index){
23445 this.onUpdate(this.store, this.store.getAt(index));
23448 updateIndexes : function(startIndex, endIndex){
23449 var ns = this.nodes;
23450 startIndex = startIndex || 0;
23451 endIndex = endIndex || ns.length - 1;
23452 for(var i = startIndex; i <= endIndex; i++){
23453 ns[i].nodeIndex = i;
23458 * Changes the data store this view uses and refresh the view.
23459 * @param {Store} store
23461 setStore : function(store, initial){
23462 if(!initial && this.store){
23463 this.store.un("datachanged", this.refresh);
23464 this.store.un("add", this.onAdd);
23465 this.store.un("remove", this.onRemove);
23466 this.store.un("update", this.onUpdate);
23467 this.store.un("clear", this.refresh);
23471 store.on("datachanged", this.refresh, this);
23472 store.on("add", this.onAdd, this);
23473 store.on("remove", this.onRemove, this);
23474 store.on("update", this.onUpdate, this);
23475 store.on("clear", this.refresh, this);
23484 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23485 * @param {HTMLElement} node
23486 * @return {HTMLElement} The template node
23488 findItemFromChild : function(node){
23489 var el = this.el.dom;
23490 if(!node || node.parentNode == el){
23493 var p = node.parentNode;
23494 while(p && p != el){
23495 if(p.parentNode == el){
23504 onClick : function(e){
23505 var item = this.findItemFromChild(e.getTarget());
23507 var index = this.indexOf(item);
23508 if(this.onItemClick(item, index, e) !== false){
23509 this.fireEvent("click", this, index, item, e);
23512 this.clearSelections();
23517 onContextMenu : function(e){
23518 var item = this.findItemFromChild(e.getTarget());
23520 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23525 onDblClick : function(e){
23526 var item = this.findItemFromChild(e.getTarget());
23528 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23532 onItemClick : function(item, index, e){
23533 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23536 if(this.multiSelect || this.singleSelect){
23537 if(this.multiSelect && e.shiftKey && this.lastSelection){
23538 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23540 this.select(item, this.multiSelect && e.ctrlKey);
23541 this.lastSelection = item;
23543 e.preventDefault();
23549 * Get the number of selected nodes.
23552 getSelectionCount : function(){
23553 return this.selections.length;
23557 * Get the currently selected nodes.
23558 * @return {Array} An array of HTMLElements
23560 getSelectedNodes : function(){
23561 return this.selections;
23565 * Get the indexes of the selected nodes.
23568 getSelectedIndexes : function(){
23569 var indexes = [], s = this.selections;
23570 for(var i = 0, len = s.length; i < len; i++){
23571 indexes.push(s[i].nodeIndex);
23577 * Clear all selections
23578 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23580 clearSelections : function(suppressEvent){
23581 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23582 this.cmp.elements = this.selections;
23583 this.cmp.removeClass(this.selectedClass);
23584 this.selections = [];
23585 if(!suppressEvent){
23586 this.fireEvent("selectionchange", this, this.selections);
23592 * Returns true if the passed node is selected
23593 * @param {HTMLElement/Number} node The node or node index
23594 * @return {Boolean}
23596 isSelected : function(node){
23597 var s = this.selections;
23601 node = this.getNode(node);
23602 return s.indexOf(node) !== -1;
23607 * @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
23608 * @param {Boolean} keepExisting (optional) true to keep existing selections
23609 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23611 select : function(nodeInfo, keepExisting, suppressEvent){
23612 if(nodeInfo instanceof Array){
23614 this.clearSelections(true);
23616 for(var i = 0, len = nodeInfo.length; i < len; i++){
23617 this.select(nodeInfo[i], true, true);
23620 var node = this.getNode(nodeInfo);
23621 if(node && !this.isSelected(node)){
23623 this.clearSelections(true);
23625 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23626 Roo.fly(node).addClass(this.selectedClass);
23627 this.selections.push(node);
23628 if(!suppressEvent){
23629 this.fireEvent("selectionchange", this, this.selections);
23637 * Gets a template node.
23638 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23639 * @return {HTMLElement} The node or null if it wasn't found
23641 getNode : function(nodeInfo){
23642 if(typeof nodeInfo == "string"){
23643 return document.getElementById(nodeInfo);
23644 }else if(typeof nodeInfo == "number"){
23645 return this.nodes[nodeInfo];
23651 * Gets a range template nodes.
23652 * @param {Number} startIndex
23653 * @param {Number} endIndex
23654 * @return {Array} An array of nodes
23656 getNodes : function(start, end){
23657 var ns = this.nodes;
23658 start = start || 0;
23659 end = typeof end == "undefined" ? ns.length - 1 : end;
23662 for(var i = start; i <= end; i++){
23666 for(var i = start; i >= end; i--){
23674 * Finds the index of the passed node
23675 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23676 * @return {Number} The index of the node or -1
23678 indexOf : function(node){
23679 node = this.getNode(node);
23680 if(typeof node.nodeIndex == "number"){
23681 return node.nodeIndex;
23683 var ns = this.nodes;
23684 for(var i = 0, len = ns.length; i < len; i++){
23694 * Ext JS Library 1.1.1
23695 * Copyright(c) 2006-2007, Ext JS, LLC.
23697 * Originally Released Under LGPL - original licence link has changed is not relivant.
23700 * <script type="text/javascript">
23704 * @class Roo.JsonView
23705 * @extends Roo.View
23706 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23708 var view = new Roo.JsonView("my-element",
23709 '<div id="{id}">{foo} - {bar}</div>', // auto create template
23710 { multiSelect: true, jsonRoot: "data" }
23713 // listen for node click?
23714 view.on("click", function(vw, index, node, e){
23715 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23718 // direct load of JSON data
23719 view.load("foobar.php");
23721 // Example from my blog list
23722 var tpl = new Roo.Template(
23723 '<div class="entry">' +
23724 '<a class="entry-title" href="{link}">{title}</a>' +
23725 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23726 "</div><hr />"
23729 var moreView = new Roo.JsonView("entry-list", tpl, {
23732 moreView.on("beforerender", this.sortEntries, this);
23734 url: "/blog/get-posts.php",
23735 params: "allposts=true",
23736 text: "Loading Blog Entries..."
23740 * Create a new JsonView
23741 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
23742 * @param {Template} tpl The rendering template
23743 * @param {Object} config The config object
23745 Roo.JsonView = function(container, tpl, config){
23746 Roo.JsonView.superclass.constructor.call(this, container, tpl, config);
23748 var um = this.el.getUpdateManager();
23749 um.setRenderer(this);
23750 um.on("update", this.onLoad, this);
23751 um.on("failure", this.onLoadException, this);
23754 * @event beforerender
23755 * Fires before rendering of the downloaded JSON data.
23756 * @param {Roo.JsonView} this
23757 * @param {Object} data The JSON data loaded
23761 * Fires when data is loaded.
23762 * @param {Roo.JsonView} this
23763 * @param {Object} data The JSON data loaded
23764 * @param {Object} response The raw Connect response object
23767 * @event loadexception
23768 * Fires when loading fails.
23769 * @param {Roo.JsonView} this
23770 * @param {Object} response The raw Connect response object
23773 'beforerender' : true,
23775 'loadexception' : true
23778 Roo.extend(Roo.JsonView, Roo.View, {
23780 * The root property in the loaded JSON object that contains the data
23786 * Refreshes the view.
23788 refresh : function(){
23789 this.clearSelections();
23790 this.el.update("");
23792 var o = this.jsonData;
23793 if(o && o.length > 0){
23794 for(var i = 0, len = o.length; i < len; i++){
23795 var data = this.prepareData(o[i], i, o);
23796 html[html.length] = this.tpl.apply(data);
23799 html.push(this.emptyText);
23801 this.el.update(html.join(""));
23802 this.nodes = this.el.dom.childNodes;
23803 this.updateIndexes(0);
23807 * 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.
23808 * @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:
23811 url: "your-url.php",
23812 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
23813 callback: yourFunction,
23814 scope: yourObject, //(optional scope)
23817 text: "Loading...",
23822 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
23823 * 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.
23824 * @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}
23825 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
23826 * @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.
23829 var um = this.el.getUpdateManager();
23830 um.update.apply(um, arguments);
23833 render : function(el, response){
23834 this.clearSelections();
23835 this.el.update("");
23838 o = Roo.util.JSON.decode(response.responseText);
23841 o = /** eval:var:o */ eval("o." + this.jsonRoot);
23846 * The current JSON data or null
23849 this.beforeRender();
23854 * Get the number of records in the current JSON dataset
23857 getCount : function(){
23858 return this.jsonData ? this.jsonData.length : 0;
23862 * Returns the JSON object for the specified node(s)
23863 * @param {HTMLElement/Array} node The node or an array of nodes
23864 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
23865 * you get the JSON object for the node
23867 getNodeData : function(node){
23868 if(node instanceof Array){
23870 for(var i = 0, len = node.length; i < len; i++){
23871 data.push(this.getNodeData(node[i]));
23875 return this.jsonData[this.indexOf(node)] || null;
23878 beforeRender : function(){
23879 this.snapshot = this.jsonData;
23881 this.sort.apply(this, this.sortInfo);
23883 this.fireEvent("beforerender", this, this.jsonData);
23886 onLoad : function(el, o){
23887 this.fireEvent("load", this, this.jsonData, o);
23890 onLoadException : function(el, o){
23891 this.fireEvent("loadexception", this, o);
23895 * Filter the data by a specific property.
23896 * @param {String} property A property on your JSON objects
23897 * @param {String/RegExp} value Either string that the property values
23898 * should start with, or a RegExp to test against the property
23900 filter : function(property, value){
23903 var ss = this.snapshot;
23904 if(typeof value == "string"){
23905 var vlen = value.length;
23907 this.clearFilter();
23910 value = value.toLowerCase();
23911 for(var i = 0, len = ss.length; i < len; i++){
23913 if(o[property].substr(0, vlen).toLowerCase() == value){
23917 } else if(value.exec){ // regex?
23918 for(var i = 0, len = ss.length; i < len; i++){
23920 if(value.test(o[property])){
23927 this.jsonData = data;
23933 * Filter by a function. The passed function will be called with each
23934 * object in the current dataset. If the function returns true the value is kept,
23935 * otherwise it is filtered.
23936 * @param {Function} fn
23937 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
23939 filterBy : function(fn, scope){
23942 var ss = this.snapshot;
23943 for(var i = 0, len = ss.length; i < len; i++){
23945 if(fn.call(scope || this, o)){
23949 this.jsonData = data;
23955 * Clears the current filter.
23957 clearFilter : function(){
23958 if(this.snapshot && this.jsonData != this.snapshot){
23959 this.jsonData = this.snapshot;
23966 * Sorts the data for this view and refreshes it.
23967 * @param {String} property A property on your JSON objects to sort on
23968 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
23969 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
23971 sort : function(property, dir, sortType){
23972 this.sortInfo = Array.prototype.slice.call(arguments, 0);
23975 var dsc = dir && dir.toLowerCase() == "desc";
23976 var f = function(o1, o2){
23977 var v1 = sortType ? sortType(o1[p]) : o1[p];
23978 var v2 = sortType ? sortType(o2[p]) : o2[p];
23981 return dsc ? +1 : -1;
23982 } else if(v1 > v2){
23983 return dsc ? -1 : +1;
23988 this.jsonData.sort(f);
23990 if(this.jsonData != this.snapshot){
23991 this.snapshot.sort(f);
23997 * Ext JS Library 1.1.1
23998 * Copyright(c) 2006-2007, Ext JS, LLC.
24000 * Originally Released Under LGPL - original licence link has changed is not relivant.
24003 * <script type="text/javascript">
24008 * @class Roo.ColorPalette
24009 * @extends Roo.Component
24010 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24011 * Here's an example of typical usage:
24013 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24014 cp.render('my-div');
24016 cp.on('select', function(palette, selColor){
24017 // do something with selColor
24021 * Create a new ColorPalette
24022 * @param {Object} config The config object
24024 Roo.ColorPalette = function(config){
24025 Roo.ColorPalette.superclass.constructor.call(this, config);
24029 * Fires when a color is selected
24030 * @param {ColorPalette} this
24031 * @param {String} color The 6-digit color hex code (without the # symbol)
24037 this.on("select", this.handler, this.scope, true);
24040 Roo.extend(Roo.ColorPalette, Roo.Component, {
24042 * @cfg {String} itemCls
24043 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24045 itemCls : "x-color-palette",
24047 * @cfg {String} value
24048 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24049 * the hex codes are case-sensitive.
24052 clickEvent:'click',
24054 ctype: "Roo.ColorPalette",
24057 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24059 allowReselect : false,
24062 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24063 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24064 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24065 * of colors with the width setting until the box is symmetrical.</p>
24066 * <p>You can override individual colors if needed:</p>
24068 var cp = new Roo.ColorPalette();
24069 cp.colors[0] = "FF0000"; // change the first box to red
24072 Or you can provide a custom array of your own for complete control:
24074 var cp = new Roo.ColorPalette();
24075 cp.colors = ["000000", "993300", "333300"];
24080 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24081 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24082 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24083 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24084 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24088 onRender : function(container, position){
24089 var t = new Roo.MasterTemplate(
24090 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24092 var c = this.colors;
24093 for(var i = 0, len = c.length; i < len; i++){
24096 var el = document.createElement("div");
24097 el.className = this.itemCls;
24099 container.dom.insertBefore(el, position);
24100 this.el = Roo.get(el);
24101 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24102 if(this.clickEvent != 'click'){
24103 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24108 afterRender : function(){
24109 Roo.ColorPalette.superclass.afterRender.call(this);
24111 var s = this.value;
24118 handleClick : function(e, t){
24119 e.preventDefault();
24120 if(!this.disabled){
24121 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24122 this.select(c.toUpperCase());
24127 * Selects the specified color in the palette (fires the select event)
24128 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24130 select : function(color){
24131 color = color.replace("#", "");
24132 if(color != this.value || this.allowReselect){
24135 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24137 el.child("a.color-"+color).addClass("x-color-palette-sel");
24138 this.value = color;
24139 this.fireEvent("select", this, color);
24144 * Ext JS Library 1.1.1
24145 * Copyright(c) 2006-2007, Ext JS, LLC.
24147 * Originally Released Under LGPL - original licence link has changed is not relivant.
24150 * <script type="text/javascript">
24154 * @class Roo.DatePicker
24155 * @extends Roo.Component
24156 * Simple date picker class.
24158 * Create a new DatePicker
24159 * @param {Object} config The config object
24161 Roo.DatePicker = function(config){
24162 Roo.DatePicker.superclass.constructor.call(this, config);
24164 this.value = config && config.value ?
24165 config.value.clearTime() : new Date().clearTime();
24170 * Fires when a date is selected
24171 * @param {DatePicker} this
24172 * @param {Date} date The selected date
24178 this.on("select", this.handler, this.scope || this);
24180 // build the disabledDatesRE
24181 if(!this.disabledDatesRE && this.disabledDates){
24182 var dd = this.disabledDates;
24184 for(var i = 0; i < dd.length; i++){
24186 if(i != dd.length-1) re += "|";
24188 this.disabledDatesRE = new RegExp(re + ")");
24192 Roo.extend(Roo.DatePicker, Roo.Component, {
24194 * @cfg {String} todayText
24195 * The text to display on the button that selects the current date (defaults to "Today")
24197 todayText : "Today",
24199 * @cfg {String} okText
24200 * The text to display on the ok button
24202 okText : " OK ", //   to give the user extra clicking room
24204 * @cfg {String} cancelText
24205 * The text to display on the cancel button
24207 cancelText : "Cancel",
24209 * @cfg {String} todayTip
24210 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24212 todayTip : "{0} (Spacebar)",
24214 * @cfg {Date} minDate
24215 * Minimum allowable date (JavaScript date object, defaults to null)
24219 * @cfg {Date} maxDate
24220 * Maximum allowable date (JavaScript date object, defaults to null)
24224 * @cfg {String} minText
24225 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24227 minText : "This date is before the minimum date",
24229 * @cfg {String} maxText
24230 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24232 maxText : "This date is after the maximum date",
24234 * @cfg {String} format
24235 * The default date format string which can be overriden for localization support. The format must be
24236 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24240 * @cfg {Array} disabledDays
24241 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24243 disabledDays : null,
24245 * @cfg {String} disabledDaysText
24246 * The tooltip to display when the date falls on a disabled day (defaults to "")
24248 disabledDaysText : "",
24250 * @cfg {RegExp} disabledDatesRE
24251 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24253 disabledDatesRE : null,
24255 * @cfg {String} disabledDatesText
24256 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24258 disabledDatesText : "",
24260 * @cfg {Boolean} constrainToViewport
24261 * True to constrain the date picker to the viewport (defaults to true)
24263 constrainToViewport : true,
24265 * @cfg {Array} monthNames
24266 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24268 monthNames : Date.monthNames,
24270 * @cfg {Array} dayNames
24271 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24273 dayNames : Date.dayNames,
24275 * @cfg {String} nextText
24276 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24278 nextText: 'Next Month (Control+Right)',
24280 * @cfg {String} prevText
24281 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24283 prevText: 'Previous Month (Control+Left)',
24285 * @cfg {String} monthYearText
24286 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24288 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24290 * @cfg {Number} startDay
24291 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24295 * @cfg {Bool} showClear
24296 * Show a clear button (usefull for date form elements that can be blank.)
24302 * Sets the value of the date field
24303 * @param {Date} value The date to set
24305 setValue : function(value){
24306 var old = this.value;
24307 this.value = value.clearTime(true);
24309 this.update(this.value);
24314 * Gets the current selected value of the date field
24315 * @return {Date} The selected date
24317 getValue : function(){
24322 focus : function(){
24324 this.update(this.activeDate);
24329 onRender : function(container, position){
24331 '<table cellspacing="0">',
24332 '<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>',
24333 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24334 var dn = this.dayNames;
24335 for(var i = 0; i < 7; i++){
24336 var d = this.startDay+i;
24340 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24342 m[m.length] = "</tr></thead><tbody><tr>";
24343 for(var i = 0; i < 42; i++) {
24344 if(i % 7 == 0 && i != 0){
24345 m[m.length] = "</tr><tr>";
24347 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24349 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24350 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24352 var el = document.createElement("div");
24353 el.className = "x-date-picker";
24354 el.innerHTML = m.join("");
24356 container.dom.insertBefore(el, position);
24358 this.el = Roo.get(el);
24359 this.eventEl = Roo.get(el.firstChild);
24361 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24362 handler: this.showPrevMonth,
24364 preventDefault:true,
24368 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24369 handler: this.showNextMonth,
24371 preventDefault:true,
24375 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24377 this.monthPicker = this.el.down('div.x-date-mp');
24378 this.monthPicker.enableDisplayMode('block');
24380 var kn = new Roo.KeyNav(this.eventEl, {
24381 "left" : function(e){
24383 this.showPrevMonth() :
24384 this.update(this.activeDate.add("d", -1));
24387 "right" : function(e){
24389 this.showNextMonth() :
24390 this.update(this.activeDate.add("d", 1));
24393 "up" : function(e){
24395 this.showNextYear() :
24396 this.update(this.activeDate.add("d", -7));
24399 "down" : function(e){
24401 this.showPrevYear() :
24402 this.update(this.activeDate.add("d", 7));
24405 "pageUp" : function(e){
24406 this.showNextMonth();
24409 "pageDown" : function(e){
24410 this.showPrevMonth();
24413 "enter" : function(e){
24414 e.stopPropagation();
24421 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24423 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24425 this.el.unselectable();
24427 this.cells = this.el.select("table.x-date-inner tbody td");
24428 this.textNodes = this.el.query("table.x-date-inner tbody span");
24430 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24432 tooltip: this.monthYearText
24435 this.mbtn.on('click', this.showMonthPicker, this);
24436 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24439 var today = (new Date()).dateFormat(this.format);
24441 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24443 text: String.format(this.todayText, today),
24444 tooltip: String.format(this.todayTip, today),
24445 handler: this.selectToday,
24449 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24452 if (this.showClear) {
24454 baseTb.add( new Roo.Toolbar.Fill());
24457 cls: 'x-btn-icon x-btn-clear',
24458 handler: function() {
24460 this.fireEvent("select", this, '');
24470 this.update(this.value);
24473 createMonthPicker : function(){
24474 if(!this.monthPicker.dom.firstChild){
24475 var buf = ['<table border="0" cellspacing="0">'];
24476 for(var i = 0; i < 6; i++){
24478 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24479 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24481 '<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>' :
24482 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24486 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24488 '</button><button type="button" class="x-date-mp-cancel">',
24490 '</button></td></tr>',
24493 this.monthPicker.update(buf.join(''));
24494 this.monthPicker.on('click', this.onMonthClick, this);
24495 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24497 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24498 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24500 this.mpMonths.each(function(m, a, i){
24503 m.dom.xmonth = 5 + Math.round(i * .5);
24505 m.dom.xmonth = Math.round((i-1) * .5);
24511 showMonthPicker : function(){
24512 this.createMonthPicker();
24513 var size = this.el.getSize();
24514 this.monthPicker.setSize(size);
24515 this.monthPicker.child('table').setSize(size);
24517 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24518 this.updateMPMonth(this.mpSelMonth);
24519 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24520 this.updateMPYear(this.mpSelYear);
24522 this.monthPicker.slideIn('t', {duration:.2});
24525 updateMPYear : function(y){
24527 var ys = this.mpYears.elements;
24528 for(var i = 1; i <= 10; i++){
24529 var td = ys[i-1], y2;
24531 y2 = y + Math.round(i * .5);
24532 td.firstChild.innerHTML = y2;
24535 y2 = y - (5-Math.round(i * .5));
24536 td.firstChild.innerHTML = y2;
24539 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24543 updateMPMonth : function(sm){
24544 this.mpMonths.each(function(m, a, i){
24545 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24549 selectMPMonth: function(m){
24553 onMonthClick : function(e, t){
24555 var el = new Roo.Element(t), pn;
24556 if(el.is('button.x-date-mp-cancel')){
24557 this.hideMonthPicker();
24559 else if(el.is('button.x-date-mp-ok')){
24560 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24561 this.hideMonthPicker();
24563 else if(pn = el.up('td.x-date-mp-month', 2)){
24564 this.mpMonths.removeClass('x-date-mp-sel');
24565 pn.addClass('x-date-mp-sel');
24566 this.mpSelMonth = pn.dom.xmonth;
24568 else if(pn = el.up('td.x-date-mp-year', 2)){
24569 this.mpYears.removeClass('x-date-mp-sel');
24570 pn.addClass('x-date-mp-sel');
24571 this.mpSelYear = pn.dom.xyear;
24573 else if(el.is('a.x-date-mp-prev')){
24574 this.updateMPYear(this.mpyear-10);
24576 else if(el.is('a.x-date-mp-next')){
24577 this.updateMPYear(this.mpyear+10);
24581 onMonthDblClick : function(e, t){
24583 var el = new Roo.Element(t), pn;
24584 if(pn = el.up('td.x-date-mp-month', 2)){
24585 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24586 this.hideMonthPicker();
24588 else if(pn = el.up('td.x-date-mp-year', 2)){
24589 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24590 this.hideMonthPicker();
24594 hideMonthPicker : function(disableAnim){
24595 if(this.monthPicker){
24596 if(disableAnim === true){
24597 this.monthPicker.hide();
24599 this.monthPicker.slideOut('t', {duration:.2});
24605 showPrevMonth : function(e){
24606 this.update(this.activeDate.add("mo", -1));
24610 showNextMonth : function(e){
24611 this.update(this.activeDate.add("mo", 1));
24615 showPrevYear : function(){
24616 this.update(this.activeDate.add("y", -1));
24620 showNextYear : function(){
24621 this.update(this.activeDate.add("y", 1));
24625 handleMouseWheel : function(e){
24626 var delta = e.getWheelDelta();
24628 this.showPrevMonth();
24630 } else if(delta < 0){
24631 this.showNextMonth();
24637 handleDateClick : function(e, t){
24639 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24640 this.setValue(new Date(t.dateValue));
24641 this.fireEvent("select", this, this.value);
24646 selectToday : function(){
24647 this.setValue(new Date().clearTime());
24648 this.fireEvent("select", this, this.value);
24652 update : function(date){
24653 var vd = this.activeDate;
24654 this.activeDate = date;
24656 var t = date.getTime();
24657 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24658 this.cells.removeClass("x-date-selected");
24659 this.cells.each(function(c){
24660 if(c.dom.firstChild.dateValue == t){
24661 c.addClass("x-date-selected");
24662 setTimeout(function(){
24663 try{c.dom.firstChild.focus();}catch(e){}
24671 var days = date.getDaysInMonth();
24672 var firstOfMonth = date.getFirstDateOfMonth();
24673 var startingPos = firstOfMonth.getDay()-this.startDay;
24675 if(startingPos <= this.startDay){
24679 var pm = date.add("mo", -1);
24680 var prevStart = pm.getDaysInMonth()-startingPos;
24682 var cells = this.cells.elements;
24683 var textEls = this.textNodes;
24684 days += startingPos;
24686 // convert everything to numbers so it's fast
24687 var day = 86400000;
24688 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24689 var today = new Date().clearTime().getTime();
24690 var sel = date.clearTime().getTime();
24691 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24692 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24693 var ddMatch = this.disabledDatesRE;
24694 var ddText = this.disabledDatesText;
24695 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24696 var ddaysText = this.disabledDaysText;
24697 var format = this.format;
24699 var setCellClass = function(cal, cell){
24701 var t = d.getTime();
24702 cell.firstChild.dateValue = t;
24704 cell.className += " x-date-today";
24705 cell.title = cal.todayText;
24708 cell.className += " x-date-selected";
24709 setTimeout(function(){
24710 try{cell.firstChild.focus();}catch(e){}
24715 cell.className = " x-date-disabled";
24716 cell.title = cal.minText;
24720 cell.className = " x-date-disabled";
24721 cell.title = cal.maxText;
24725 if(ddays.indexOf(d.getDay()) != -1){
24726 cell.title = ddaysText;
24727 cell.className = " x-date-disabled";
24730 if(ddMatch && format){
24731 var fvalue = d.dateFormat(format);
24732 if(ddMatch.test(fvalue)){
24733 cell.title = ddText.replace("%0", fvalue);
24734 cell.className = " x-date-disabled";
24740 for(; i < startingPos; i++) {
24741 textEls[i].innerHTML = (++prevStart);
24742 d.setDate(d.getDate()+1);
24743 cells[i].className = "x-date-prevday";
24744 setCellClass(this, cells[i]);
24746 for(; i < days; i++){
24747 intDay = i - startingPos + 1;
24748 textEls[i].innerHTML = (intDay);
24749 d.setDate(d.getDate()+1);
24750 cells[i].className = "x-date-active";
24751 setCellClass(this, cells[i]);
24754 for(; i < 42; i++) {
24755 textEls[i].innerHTML = (++extraDays);
24756 d.setDate(d.getDate()+1);
24757 cells[i].className = "x-date-nextday";
24758 setCellClass(this, cells[i]);
24761 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
24763 if(!this.internalRender){
24764 var main = this.el.dom.firstChild;
24765 var w = main.offsetWidth;
24766 this.el.setWidth(w + this.el.getBorderWidth("lr"));
24767 Roo.fly(main).setWidth(w);
24768 this.internalRender = true;
24769 // opera does not respect the auto grow header center column
24770 // then, after it gets a width opera refuses to recalculate
24771 // without a second pass
24772 if(Roo.isOpera && !this.secondPass){
24773 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
24774 this.secondPass = true;
24775 this.update.defer(10, this, [date]);
24781 * Ext JS Library 1.1.1
24782 * Copyright(c) 2006-2007, Ext JS, LLC.
24784 * Originally Released Under LGPL - original licence link has changed is not relivant.
24787 * <script type="text/javascript">
24790 * @class Roo.TabPanel
24791 * @extends Roo.util.Observable
24792 * A lightweight tab container.
24796 // basic tabs 1, built from existing content
24797 var tabs = new Roo.TabPanel("tabs1");
24798 tabs.addTab("script", "View Script");
24799 tabs.addTab("markup", "View Markup");
24800 tabs.activate("script");
24802 // more advanced tabs, built from javascript
24803 var jtabs = new Roo.TabPanel("jtabs");
24804 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
24806 // set up the UpdateManager
24807 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
24808 var updater = tab2.getUpdateManager();
24809 updater.setDefaultUrl("ajax1.htm");
24810 tab2.on('activate', updater.refresh, updater, true);
24812 // Use setUrl for Ajax loading
24813 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
24814 tab3.setUrl("ajax2.htm", null, true);
24817 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
24820 jtabs.activate("jtabs-1");
24823 * Create a new TabPanel.
24824 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
24825 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
24827 Roo.TabPanel = function(container, config){
24829 * The container element for this TabPanel.
24830 * @type Roo.Element
24832 this.el = Roo.get(container, true);
24834 if(typeof config == "boolean"){
24835 this.tabPosition = config ? "bottom" : "top";
24837 Roo.apply(this, config);
24840 if(this.tabPosition == "bottom"){
24841 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24842 this.el.addClass("x-tabs-bottom");
24844 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
24845 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
24846 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
24848 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
24850 if(this.tabPosition != "bottom"){
24851 /** The body element that contains {@link Roo.TabPanelItem} bodies.
24852 * @type Roo.Element
24854 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24855 this.el.addClass("x-tabs-top");
24859 this.bodyEl.setStyle("position", "relative");
24861 this.active = null;
24862 this.activateDelegate = this.activate.createDelegate(this);
24867 * Fires when the active tab changes
24868 * @param {Roo.TabPanel} this
24869 * @param {Roo.TabPanelItem} activePanel The new active tab
24873 * @event beforetabchange
24874 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
24875 * @param {Roo.TabPanel} this
24876 * @param {Object} e Set cancel to true on this object to cancel the tab change
24877 * @param {Roo.TabPanelItem} tab The tab being changed to
24879 "beforetabchange" : true
24882 Roo.EventManager.onWindowResize(this.onResize, this);
24883 this.cpad = this.el.getPadding("lr");
24884 this.hiddenCount = 0;
24886 Roo.TabPanel.superclass.constructor.call(this);
24889 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
24891 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
24893 tabPosition : "top",
24895 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
24897 currentTabWidth : 0,
24899 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
24903 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
24907 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
24909 preferredTabWidth : 175,
24911 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
24913 resizeTabs : false,
24915 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
24917 monitorResize : true,
24920 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
24921 * @param {String} id The id of the div to use <b>or create</b>
24922 * @param {String} text The text for the tab
24923 * @param {String} content (optional) Content to put in the TabPanelItem body
24924 * @param {Boolean} closable (optional) True to create a close icon on the tab
24925 * @return {Roo.TabPanelItem} The created TabPanelItem
24927 addTab : function(id, text, content, closable){
24928 var item = new Roo.TabPanelItem(this, id, text, closable);
24929 this.addTabItem(item);
24931 item.setContent(content);
24937 * Returns the {@link Roo.TabPanelItem} with the specified id/index
24938 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
24939 * @return {Roo.TabPanelItem}
24941 getTab : function(id){
24942 return this.items[id];
24946 * Hides the {@link Roo.TabPanelItem} with the specified id/index
24947 * @param {String/Number} id The id or index of the TabPanelItem to hide.
24949 hideTab : function(id){
24950 var t = this.items[id];
24953 this.hiddenCount++;
24954 this.autoSizeTabs();
24959 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
24960 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
24962 unhideTab : function(id){
24963 var t = this.items[id];
24965 t.setHidden(false);
24966 this.hiddenCount--;
24967 this.autoSizeTabs();
24972 * Adds an existing {@link Roo.TabPanelItem}.
24973 * @param {Roo.TabPanelItem} item The TabPanelItem to add
24975 addTabItem : function(item){
24976 this.items[item.id] = item;
24977 this.items.push(item);
24978 if(this.resizeTabs){
24979 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
24980 this.autoSizeTabs();
24987 * Removes a {@link Roo.TabPanelItem}.
24988 * @param {String/Number} id The id or index of the TabPanelItem to remove.
24990 removeTab : function(id){
24991 var items = this.items;
24992 var tab = items[id];
24994 var index = items.indexOf(tab);
24995 if(this.active == tab && items.length > 1){
24996 var newTab = this.getNextAvailable(index);
24997 if(newTab)newTab.activate();
24999 this.stripEl.dom.removeChild(tab.pnode.dom);
25000 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25001 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25003 items.splice(index, 1);
25004 delete this.items[tab.id];
25005 tab.fireEvent("close", tab);
25006 tab.purgeListeners();
25007 this.autoSizeTabs();
25010 getNextAvailable : function(start){
25011 var items = this.items;
25013 // look for a next tab that will slide over to
25014 // replace the one being removed
25015 while(index < items.length){
25016 var item = items[++index];
25017 if(item && !item.isHidden()){
25021 // if one isn't found select the previous tab (on the left)
25024 var item = items[--index];
25025 if(item && !item.isHidden()){
25033 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25034 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25036 disableTab : function(id){
25037 var tab = this.items[id];
25038 if(tab && this.active != tab){
25044 * Enables a {@link Roo.TabPanelItem} that is disabled.
25045 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25047 enableTab : function(id){
25048 var tab = this.items[id];
25053 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25054 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25055 * @return {Roo.TabPanelItem} The TabPanelItem.
25057 activate : function(id){
25058 var tab = this.items[id];
25062 if(tab == this.active || tab.disabled){
25066 this.fireEvent("beforetabchange", this, e, tab);
25067 if(e.cancel !== true && !tab.disabled){
25069 this.active.hide();
25071 this.active = this.items[id];
25072 this.active.show();
25073 this.fireEvent("tabchange", this, this.active);
25079 * Gets the active {@link Roo.TabPanelItem}.
25080 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25082 getActiveTab : function(){
25083 return this.active;
25087 * Updates the tab body element to fit the height of the container element
25088 * for overflow scrolling
25089 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25091 syncHeight : function(targetHeight){
25092 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25093 var bm = this.bodyEl.getMargins();
25094 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25095 this.bodyEl.setHeight(newHeight);
25099 onResize : function(){
25100 if(this.monitorResize){
25101 this.autoSizeTabs();
25106 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25108 beginUpdate : function(){
25109 this.updating = true;
25113 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25115 endUpdate : function(){
25116 this.updating = false;
25117 this.autoSizeTabs();
25121 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25123 autoSizeTabs : function(){
25124 var count = this.items.length;
25125 var vcount = count - this.hiddenCount;
25126 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25127 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25128 var availWidth = Math.floor(w / vcount);
25129 var b = this.stripBody;
25130 if(b.getWidth() > w){
25131 var tabs = this.items;
25132 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25133 if(availWidth < this.minTabWidth){
25134 /*if(!this.sleft){ // incomplete scrolling code
25135 this.createScrollButtons();
25138 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25141 if(this.currentTabWidth < this.preferredTabWidth){
25142 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25148 * Returns the number of tabs in this TabPanel.
25151 getCount : function(){
25152 return this.items.length;
25156 * Resizes all the tabs to the passed width
25157 * @param {Number} The new width
25159 setTabWidth : function(width){
25160 this.currentTabWidth = width;
25161 for(var i = 0, len = this.items.length; i < len; i++) {
25162 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25167 * Destroys this TabPanel
25168 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25170 destroy : function(removeEl){
25171 Roo.EventManager.removeResizeListener(this.onResize, this);
25172 for(var i = 0, len = this.items.length; i < len; i++){
25173 this.items[i].purgeListeners();
25175 if(removeEl === true){
25176 this.el.update("");
25183 * @class Roo.TabPanelItem
25184 * @extends Roo.util.Observable
25185 * Represents an individual item (tab plus body) in a TabPanel.
25186 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25187 * @param {String} id The id of this TabPanelItem
25188 * @param {String} text The text for the tab of this TabPanelItem
25189 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25191 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25193 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25194 * @type Roo.TabPanel
25196 this.tabPanel = tabPanel;
25198 * The id for this TabPanelItem
25203 this.disabled = false;
25207 this.loaded = false;
25208 this.closable = closable;
25211 * The body element for this TabPanelItem.
25212 * @type Roo.Element
25214 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25215 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25216 this.bodyEl.setStyle("display", "block");
25217 this.bodyEl.setStyle("zoom", "1");
25220 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25222 this.el = Roo.get(els.el, true);
25223 this.inner = Roo.get(els.inner, true);
25224 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25225 this.pnode = Roo.get(els.el.parentNode, true);
25226 this.el.on("mousedown", this.onTabMouseDown, this);
25227 this.el.on("click", this.onTabClick, this);
25230 var c = Roo.get(els.close, true);
25231 c.dom.title = this.closeText;
25232 c.addClassOnOver("close-over");
25233 c.on("click", this.closeClick, this);
25239 * Fires when this tab becomes the active tab.
25240 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25241 * @param {Roo.TabPanelItem} this
25245 * @event beforeclose
25246 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25247 * @param {Roo.TabPanelItem} this
25248 * @param {Object} e Set cancel to true on this object to cancel the close.
25250 "beforeclose": true,
25253 * Fires when this tab is closed.
25254 * @param {Roo.TabPanelItem} this
25258 * @event deactivate
25259 * Fires when this tab is no longer the active tab.
25260 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25261 * @param {Roo.TabPanelItem} this
25263 "deactivate" : true
25265 this.hidden = false;
25267 Roo.TabPanelItem.superclass.constructor.call(this);
25270 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25271 purgeListeners : function(){
25272 Roo.util.Observable.prototype.purgeListeners.call(this);
25273 this.el.removeAllListeners();
25276 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25279 this.pnode.addClass("on");
25282 this.tabPanel.stripWrap.repaint();
25284 this.fireEvent("activate", this.tabPanel, this);
25288 * Returns true if this tab is the active tab.
25289 * @return {Boolean}
25291 isActive : function(){
25292 return this.tabPanel.getActiveTab() == this;
25296 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25299 this.pnode.removeClass("on");
25301 this.fireEvent("deactivate", this.tabPanel, this);
25304 hideAction : function(){
25305 this.bodyEl.hide();
25306 this.bodyEl.setStyle("position", "absolute");
25307 this.bodyEl.setLeft("-20000px");
25308 this.bodyEl.setTop("-20000px");
25311 showAction : function(){
25312 this.bodyEl.setStyle("position", "relative");
25313 this.bodyEl.setTop("");
25314 this.bodyEl.setLeft("");
25315 this.bodyEl.show();
25319 * Set the tooltip for the tab.
25320 * @param {String} tooltip The tab's tooltip
25322 setTooltip : function(text){
25323 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25324 this.textEl.dom.qtip = text;
25325 this.textEl.dom.removeAttribute('title');
25327 this.textEl.dom.title = text;
25331 onTabClick : function(e){
25332 e.preventDefault();
25333 this.tabPanel.activate(this.id);
25336 onTabMouseDown : function(e){
25337 e.preventDefault();
25338 this.tabPanel.activate(this.id);
25341 getWidth : function(){
25342 return this.inner.getWidth();
25345 setWidth : function(width){
25346 var iwidth = width - this.pnode.getPadding("lr");
25347 this.inner.setWidth(iwidth);
25348 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25349 this.pnode.setWidth(width);
25353 * Show or hide the tab
25354 * @param {Boolean} hidden True to hide or false to show.
25356 setHidden : function(hidden){
25357 this.hidden = hidden;
25358 this.pnode.setStyle("display", hidden ? "none" : "");
25362 * Returns true if this tab is "hidden"
25363 * @return {Boolean}
25365 isHidden : function(){
25366 return this.hidden;
25370 * Returns the text for this tab
25373 getText : function(){
25377 autoSize : function(){
25378 //this.el.beginMeasure();
25379 this.textEl.setWidth(1);
25380 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25381 //this.el.endMeasure();
25385 * Sets the text for the tab (Note: this also sets the tooltip text)
25386 * @param {String} text The tab's text and tooltip
25388 setText : function(text){
25390 this.textEl.update(text);
25391 this.setTooltip(text);
25392 if(!this.tabPanel.resizeTabs){
25397 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25399 activate : function(){
25400 this.tabPanel.activate(this.id);
25404 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25406 disable : function(){
25407 if(this.tabPanel.active != this){
25408 this.disabled = true;
25409 this.pnode.addClass("disabled");
25414 * Enables this TabPanelItem if it was previously disabled.
25416 enable : function(){
25417 this.disabled = false;
25418 this.pnode.removeClass("disabled");
25422 * Sets the content for this TabPanelItem.
25423 * @param {String} content The content
25424 * @param {Boolean} loadScripts true to look for and load scripts
25426 setContent : function(content, loadScripts){
25427 this.bodyEl.update(content, loadScripts);
25431 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25432 * @return {Roo.UpdateManager} The UpdateManager
25434 getUpdateManager : function(){
25435 return this.bodyEl.getUpdateManager();
25439 * Set a URL to be used to load the content for this TabPanelItem.
25440 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25441 * @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)
25442 * @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)
25443 * @return {Roo.UpdateManager} The UpdateManager
25445 setUrl : function(url, params, loadOnce){
25446 if(this.refreshDelegate){
25447 this.un('activate', this.refreshDelegate);
25449 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25450 this.on("activate", this.refreshDelegate);
25451 return this.bodyEl.getUpdateManager();
25455 _handleRefresh : function(url, params, loadOnce){
25456 if(!loadOnce || !this.loaded){
25457 var updater = this.bodyEl.getUpdateManager();
25458 updater.update(url, params, this._setLoaded.createDelegate(this));
25463 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25464 * Will fail silently if the setUrl method has not been called.
25465 * This does not activate the panel, just updates its content.
25467 refresh : function(){
25468 if(this.refreshDelegate){
25469 this.loaded = false;
25470 this.refreshDelegate();
25475 _setLoaded : function(){
25476 this.loaded = true;
25480 closeClick : function(e){
25483 this.fireEvent("beforeclose", this, o);
25484 if(o.cancel !== true){
25485 this.tabPanel.removeTab(this.id);
25489 * The text displayed in the tooltip for the close icon.
25492 closeText : "Close this tab"
25496 Roo.TabPanel.prototype.createStrip = function(container){
25497 var strip = document.createElement("div");
25498 strip.className = "x-tabs-wrap";
25499 container.appendChild(strip);
25503 Roo.TabPanel.prototype.createStripList = function(strip){
25504 // div wrapper for retard IE
25505 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>';
25506 return strip.firstChild.firstChild.firstChild.firstChild;
25509 Roo.TabPanel.prototype.createBody = function(container){
25510 var body = document.createElement("div");
25511 Roo.id(body, "tab-body");
25512 Roo.fly(body).addClass("x-tabs-body");
25513 container.appendChild(body);
25517 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25518 var body = Roo.getDom(id);
25520 body = document.createElement("div");
25523 Roo.fly(body).addClass("x-tabs-item-body");
25524 bodyEl.insertBefore(body, bodyEl.firstChild);
25528 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25529 var td = document.createElement("td");
25530 stripEl.appendChild(td);
25532 td.className = "x-tabs-closable";
25533 if(!this.closeTpl){
25534 this.closeTpl = new Roo.Template(
25535 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25536 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25537 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25540 var el = this.closeTpl.overwrite(td, {"text": text});
25541 var close = el.getElementsByTagName("div")[0];
25542 var inner = el.getElementsByTagName("em")[0];
25543 return {"el": el, "close": close, "inner": inner};
25546 this.tabTpl = new Roo.Template(
25547 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25548 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25551 var el = this.tabTpl.overwrite(td, {"text": text});
25552 var inner = el.getElementsByTagName("em")[0];
25553 return {"el": el, "inner": inner};
25557 * Ext JS Library 1.1.1
25558 * Copyright(c) 2006-2007, Ext JS, LLC.
25560 * Originally Released Under LGPL - original licence link has changed is not relivant.
25563 * <script type="text/javascript">
25567 * @class Roo.Button
25568 * @extends Roo.util.Observable
25569 * Simple Button class
25570 * @cfg {String} text The button text
25571 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25572 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25573 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25574 * @cfg {Object} scope The scope of the handler
25575 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25576 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25577 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25578 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25579 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25580 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25581 applies if enableToggle = true)
25582 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25583 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25584 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25586 * Create a new button
25587 * @param {Object} config The config object
25589 Roo.Button = function(renderTo, config)
25593 renderTo = config.renderTo || false;
25596 Roo.apply(this, config);
25600 * Fires when this button is clicked
25601 * @param {Button} this
25602 * @param {EventObject} e The click event
25607 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25608 * @param {Button} this
25609 * @param {Boolean} pressed
25614 * Fires when the mouse hovers over the button
25615 * @param {Button} this
25616 * @param {Event} e The event object
25618 'mouseover' : true,
25621 * Fires when the mouse exits the button
25622 * @param {Button} this
25623 * @param {Event} e The event object
25628 * Fires when the button is rendered
25629 * @param {Button} this
25634 this.menu = Roo.menu.MenuMgr.get(this.menu);
25637 this.render(renderTo);
25640 Roo.util.Observable.call(this);
25643 Roo.extend(Roo.Button, Roo.util.Observable, {
25649 * Read-only. True if this button is hidden
25654 * Read-only. True if this button is disabled
25659 * Read-only. True if this button is pressed (only if enableToggle = true)
25665 * @cfg {Number} tabIndex
25666 * The DOM tabIndex for this button (defaults to undefined)
25668 tabIndex : undefined,
25671 * @cfg {Boolean} enableToggle
25672 * True to enable pressed/not pressed toggling (defaults to false)
25674 enableToggle: false,
25676 * @cfg {Mixed} menu
25677 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25681 * @cfg {String} menuAlign
25682 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25684 menuAlign : "tl-bl?",
25687 * @cfg {String} iconCls
25688 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25690 iconCls : undefined,
25692 * @cfg {String} type
25693 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25698 menuClassTarget: 'tr',
25701 * @cfg {String} clickEvent
25702 * The type of event to map to the button's event handler (defaults to 'click')
25704 clickEvent : 'click',
25707 * @cfg {Boolean} handleMouseEvents
25708 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25710 handleMouseEvents : true,
25713 * @cfg {String} tooltipType
25714 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
25716 tooltipType : 'qtip',
25719 * @cfg {String} cls
25720 * A CSS class to apply to the button's main element.
25724 * @cfg {Roo.Template} template (Optional)
25725 * An {@link Roo.Template} with which to create the Button's main element. This Template must
25726 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
25727 * require code modifications if required elements (e.g. a button) aren't present.
25731 render : function(renderTo){
25733 if(this.hideParent){
25734 this.parentEl = Roo.get(renderTo);
25736 if(!this.dhconfig){
25737 if(!this.template){
25738 if(!Roo.Button.buttonTemplate){
25739 // hideous table template
25740 Roo.Button.buttonTemplate = new Roo.Template(
25741 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
25742 '<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>',
25743 "</tr></tbody></table>");
25745 this.template = Roo.Button.buttonTemplate;
25747 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
25748 var btnEl = btn.child("button:first");
25749 btnEl.on('focus', this.onFocus, this);
25750 btnEl.on('blur', this.onBlur, this);
25752 btn.addClass(this.cls);
25755 btnEl.setStyle('background-image', 'url(' +this.icon +')');
25758 btnEl.addClass(this.iconCls);
25760 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
25763 if(this.tabIndex !== undefined){
25764 btnEl.dom.tabIndex = this.tabIndex;
25767 if(typeof this.tooltip == 'object'){
25768 Roo.QuickTips.tips(Roo.apply({
25772 btnEl.dom[this.tooltipType] = this.tooltip;
25776 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
25780 this.el.dom.id = this.el.id = this.id;
25783 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
25784 this.menu.on("show", this.onMenuShow, this);
25785 this.menu.on("hide", this.onMenuHide, this);
25787 btn.addClass("x-btn");
25788 if(Roo.isIE && !Roo.isIE7){
25789 this.autoWidth.defer(1, this);
25793 if(this.handleMouseEvents){
25794 btn.on("mouseover", this.onMouseOver, this);
25795 btn.on("mouseout", this.onMouseOut, this);
25796 btn.on("mousedown", this.onMouseDown, this);
25798 btn.on(this.clickEvent, this.onClick, this);
25799 //btn.on("mouseup", this.onMouseUp, this);
25806 Roo.ButtonToggleMgr.register(this);
25808 this.el.addClass("x-btn-pressed");
25811 var repeater = new Roo.util.ClickRepeater(btn,
25812 typeof this.repeat == "object" ? this.repeat : {}
25814 repeater.on("click", this.onClick, this);
25816 this.fireEvent('render', this);
25820 * Returns the button's underlying element
25821 * @return {Roo.Element} The element
25823 getEl : function(){
25828 * Destroys this Button and removes any listeners.
25830 destroy : function(){
25831 Roo.ButtonToggleMgr.unregister(this);
25832 this.el.removeAllListeners();
25833 this.purgeListeners();
25838 autoWidth : function(){
25840 this.el.setWidth("auto");
25841 if(Roo.isIE7 && Roo.isStrict){
25842 var ib = this.el.child('button');
25843 if(ib && ib.getWidth() > 20){
25845 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
25850 this.el.beginMeasure();
25852 if(this.el.getWidth() < this.minWidth){
25853 this.el.setWidth(this.minWidth);
25856 this.el.endMeasure();
25863 * Assigns this button's click handler
25864 * @param {Function} handler The function to call when the button is clicked
25865 * @param {Object} scope (optional) Scope for the function passed in
25867 setHandler : function(handler, scope){
25868 this.handler = handler;
25869 this.scope = scope;
25873 * Sets this button's text
25874 * @param {String} text The button text
25876 setText : function(text){
25879 this.el.child("td.x-btn-center button.x-btn-text").update(text);
25885 * Gets the text for this button
25886 * @return {String} The button text
25888 getText : function(){
25896 this.hidden = false;
25898 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
25906 this.hidden = true;
25908 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
25913 * Convenience function for boolean show/hide
25914 * @param {Boolean} visible True to show, false to hide
25916 setVisible: function(visible){
25925 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
25926 * @param {Boolean} state (optional) Force a particular state
25928 toggle : function(state){
25929 state = state === undefined ? !this.pressed : state;
25930 if(state != this.pressed){
25932 this.el.addClass("x-btn-pressed");
25933 this.pressed = true;
25934 this.fireEvent("toggle", this, true);
25936 this.el.removeClass("x-btn-pressed");
25937 this.pressed = false;
25938 this.fireEvent("toggle", this, false);
25940 if(this.toggleHandler){
25941 this.toggleHandler.call(this.scope || this, this, state);
25949 focus : function(){
25950 this.el.child('button:first').focus();
25954 * Disable this button
25956 disable : function(){
25958 this.el.addClass("x-btn-disabled");
25960 this.disabled = true;
25964 * Enable this button
25966 enable : function(){
25968 this.el.removeClass("x-btn-disabled");
25970 this.disabled = false;
25974 * Convenience function for boolean enable/disable
25975 * @param {Boolean} enabled True to enable, false to disable
25977 setDisabled : function(v){
25978 this[v !== true ? "enable" : "disable"]();
25982 onClick : function(e){
25984 e.preventDefault();
25989 if(!this.disabled){
25990 if(this.enableToggle){
25993 if(this.menu && !this.menu.isVisible()){
25994 this.menu.show(this.el, this.menuAlign);
25996 this.fireEvent("click", this, e);
25998 this.el.removeClass("x-btn-over");
25999 this.handler.call(this.scope || this, this, e);
26004 onMouseOver : function(e){
26005 if(!this.disabled){
26006 this.el.addClass("x-btn-over");
26007 this.fireEvent('mouseover', this, e);
26011 onMouseOut : function(e){
26012 if(!e.within(this.el, true)){
26013 this.el.removeClass("x-btn-over");
26014 this.fireEvent('mouseout', this, e);
26018 onFocus : function(e){
26019 if(!this.disabled){
26020 this.el.addClass("x-btn-focus");
26024 onBlur : function(e){
26025 this.el.removeClass("x-btn-focus");
26028 onMouseDown : function(e){
26029 if(!this.disabled && e.button == 0){
26030 this.el.addClass("x-btn-click");
26031 Roo.get(document).on('mouseup', this.onMouseUp, this);
26035 onMouseUp : function(e){
26037 this.el.removeClass("x-btn-click");
26038 Roo.get(document).un('mouseup', this.onMouseUp, this);
26042 onMenuShow : function(e){
26043 this.el.addClass("x-btn-menu-active");
26046 onMenuHide : function(e){
26047 this.el.removeClass("x-btn-menu-active");
26051 // Private utility class used by Button
26052 Roo.ButtonToggleMgr = function(){
26055 function toggleGroup(btn, state){
26057 var g = groups[btn.toggleGroup];
26058 for(var i = 0, l = g.length; i < l; i++){
26060 g[i].toggle(false);
26067 register : function(btn){
26068 if(!btn.toggleGroup){
26071 var g = groups[btn.toggleGroup];
26073 g = groups[btn.toggleGroup] = [];
26076 btn.on("toggle", toggleGroup);
26079 unregister : function(btn){
26080 if(!btn.toggleGroup){
26083 var g = groups[btn.toggleGroup];
26086 btn.un("toggle", toggleGroup);
26092 * Ext JS Library 1.1.1
26093 * Copyright(c) 2006-2007, Ext JS, LLC.
26095 * Originally Released Under LGPL - original licence link has changed is not relivant.
26098 * <script type="text/javascript">
26102 * @class Roo.SplitButton
26103 * @extends Roo.Button
26104 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26105 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26106 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26107 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26108 * @cfg {String} arrowTooltip The title attribute of the arrow
26110 * Create a new menu button
26111 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26112 * @param {Object} config The config object
26114 Roo.SplitButton = function(renderTo, config){
26115 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26117 * @event arrowclick
26118 * Fires when this button's arrow is clicked
26119 * @param {SplitButton} this
26120 * @param {EventObject} e The click event
26122 this.addEvents({"arrowclick":true});
26125 Roo.extend(Roo.SplitButton, Roo.Button, {
26126 render : function(renderTo){
26127 // this is one sweet looking template!
26128 var tpl = new Roo.Template(
26129 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26130 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26131 '<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>',
26132 "</tbody></table></td><td>",
26133 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26134 '<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>',
26135 "</tbody></table></td></tr></table>"
26137 var btn = tpl.append(renderTo, [this.text, this.type], true);
26138 var btnEl = btn.child("button");
26140 btn.addClass(this.cls);
26143 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26146 btnEl.addClass(this.iconCls);
26148 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26152 if(this.handleMouseEvents){
26153 btn.on("mouseover", this.onMouseOver, this);
26154 btn.on("mouseout", this.onMouseOut, this);
26155 btn.on("mousedown", this.onMouseDown, this);
26156 btn.on("mouseup", this.onMouseUp, this);
26158 btn.on(this.clickEvent, this.onClick, this);
26160 if(typeof this.tooltip == 'object'){
26161 Roo.QuickTips.tips(Roo.apply({
26165 btnEl.dom[this.tooltipType] = this.tooltip;
26168 if(this.arrowTooltip){
26169 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26178 this.el.addClass("x-btn-pressed");
26180 if(Roo.isIE && !Roo.isIE7){
26181 this.autoWidth.defer(1, this);
26186 this.menu.on("show", this.onMenuShow, this);
26187 this.menu.on("hide", this.onMenuHide, this);
26189 this.fireEvent('render', this);
26193 autoWidth : function(){
26195 var tbl = this.el.child("table:first");
26196 var tbl2 = this.el.child("table:last");
26197 this.el.setWidth("auto");
26198 tbl.setWidth("auto");
26199 if(Roo.isIE7 && Roo.isStrict){
26200 var ib = this.el.child('button:first');
26201 if(ib && ib.getWidth() > 20){
26203 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26208 this.el.beginMeasure();
26210 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26211 tbl.setWidth(this.minWidth-tbl2.getWidth());
26214 this.el.endMeasure();
26217 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26221 * Sets this button's click handler
26222 * @param {Function} handler The function to call when the button is clicked
26223 * @param {Object} scope (optional) Scope for the function passed above
26225 setHandler : function(handler, scope){
26226 this.handler = handler;
26227 this.scope = scope;
26231 * Sets this button's arrow click handler
26232 * @param {Function} handler The function to call when the arrow is clicked
26233 * @param {Object} scope (optional) Scope for the function passed above
26235 setArrowHandler : function(handler, scope){
26236 this.arrowHandler = handler;
26237 this.scope = scope;
26243 focus : function(){
26245 this.el.child("button:first").focus();
26250 onClick : function(e){
26251 e.preventDefault();
26252 if(!this.disabled){
26253 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26254 if(this.menu && !this.menu.isVisible()){
26255 this.menu.show(this.el, this.menuAlign);
26257 this.fireEvent("arrowclick", this, e);
26258 if(this.arrowHandler){
26259 this.arrowHandler.call(this.scope || this, this, e);
26262 this.fireEvent("click", this, e);
26264 this.handler.call(this.scope || this, this, e);
26270 onMouseDown : function(e){
26271 if(!this.disabled){
26272 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26276 onMouseUp : function(e){
26277 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26282 // backwards compat
26283 Roo.MenuButton = Roo.SplitButton;/*
26285 * Ext JS Library 1.1.1
26286 * Copyright(c) 2006-2007, Ext JS, LLC.
26288 * Originally Released Under LGPL - original licence link has changed is not relivant.
26291 * <script type="text/javascript">
26295 * @class Roo.Toolbar
26296 * Basic Toolbar class.
26298 * Creates a new Toolbar
26299 * @param {Object} config The config object
26301 Roo.Toolbar = function(container, buttons, config)
26303 /// old consturctor format still supported..
26304 if(container instanceof Array){ // omit the container for later rendering
26305 buttons = container;
26309 if (typeof(container) == 'object' && container.xtype) {
26310 config = container;
26311 container = config.container;
26312 buttons = config.buttons; // not really - use items!!
26315 if (config && config.items) {
26316 xitems = config.items;
26317 delete config.items;
26319 Roo.apply(this, config);
26320 this.buttons = buttons;
26323 this.render(container);
26325 Roo.each(xitems, function(b) {
26331 Roo.Toolbar.prototype = {
26333 * @cfg {Roo.data.Store} items
26334 * array of button configs or elements to add
26338 * @cfg {String/HTMLElement/Element} container
26339 * The id or element that will contain the toolbar
26342 render : function(ct){
26343 this.el = Roo.get(ct);
26345 this.el.addClass(this.cls);
26347 // using a table allows for vertical alignment
26348 // 100% width is needed by Safari...
26349 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26350 this.tr = this.el.child("tr", true);
26352 this.items = new Roo.util.MixedCollection(false, function(o){
26353 return o.id || ("item" + (++autoId));
26356 this.add.apply(this, this.buttons);
26357 delete this.buttons;
26362 * Adds element(s) to the toolbar -- this function takes a variable number of
26363 * arguments of mixed type and adds them to the toolbar.
26364 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26366 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26367 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26368 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26369 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26370 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26371 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26372 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26373 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26374 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26376 * @param {Mixed} arg2
26377 * @param {Mixed} etc.
26380 var a = arguments, l = a.length;
26381 for(var i = 0; i < l; i++){
26386 _add : function(el) {
26389 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26392 if (el.applyTo){ // some kind of form field
26393 return this.addField(el);
26395 if (el.render){ // some kind of Toolbar.Item
26396 return this.addItem(el);
26398 if (typeof el == "string"){ // string
26399 if(el == "separator" || el == "-"){
26400 return this.addSeparator();
26403 return this.addSpacer();
26406 return this.addFill();
26408 return this.addText(el);
26411 if(el.tagName){ // element
26412 return this.addElement(el);
26414 if(typeof el == "object"){ // must be button config?
26415 return this.addButton(el);
26417 // and now what?!?!
26423 * Add an Xtype element
26424 * @param {Object} xtype Xtype Object
26425 * @return {Object} created Object
26427 addxtype : function(e){
26428 return this.add(e);
26432 * Returns the Element for this toolbar.
26433 * @return {Roo.Element}
26435 getEl : function(){
26441 * @return {Roo.Toolbar.Item} The separator item
26443 addSeparator : function(){
26444 return this.addItem(new Roo.Toolbar.Separator());
26448 * Adds a spacer element
26449 * @return {Roo.Toolbar.Spacer} The spacer item
26451 addSpacer : function(){
26452 return this.addItem(new Roo.Toolbar.Spacer());
26456 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26457 * @return {Roo.Toolbar.Fill} The fill item
26459 addFill : function(){
26460 return this.addItem(new Roo.Toolbar.Fill());
26464 * Adds any standard HTML element to the toolbar
26465 * @param {String/HTMLElement/Element} el The element or id of the element to add
26466 * @return {Roo.Toolbar.Item} The element's item
26468 addElement : function(el){
26469 return this.addItem(new Roo.Toolbar.Item(el));
26472 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26473 * @type Roo.util.MixedCollection
26478 * Adds any Toolbar.Item or subclass
26479 * @param {Roo.Toolbar.Item} item
26480 * @return {Roo.Toolbar.Item} The item
26482 addItem : function(item){
26483 var td = this.nextBlock();
26485 this.items.add(item);
26490 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26491 * @param {Object/Array} config A button config or array of configs
26492 * @return {Roo.Toolbar.Button/Array}
26494 addButton : function(config){
26495 if(config instanceof Array){
26497 for(var i = 0, len = config.length; i < len; i++) {
26498 buttons.push(this.addButton(config[i]));
26503 if(!(config instanceof Roo.Toolbar.Button)){
26505 new Roo.Toolbar.SplitButton(config) :
26506 new Roo.Toolbar.Button(config);
26508 var td = this.nextBlock();
26515 * Adds text to the toolbar
26516 * @param {String} text The text to add
26517 * @return {Roo.Toolbar.Item} The element's item
26519 addText : function(text){
26520 return this.addItem(new Roo.Toolbar.TextItem(text));
26524 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26525 * @param {Number} index The index where the item is to be inserted
26526 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26527 * @return {Roo.Toolbar.Button/Item}
26529 insertButton : function(index, item){
26530 if(item instanceof Array){
26532 for(var i = 0, len = item.length; i < len; i++) {
26533 buttons.push(this.insertButton(index + i, item[i]));
26537 if (!(item instanceof Roo.Toolbar.Button)){
26538 item = new Roo.Toolbar.Button(item);
26540 var td = document.createElement("td");
26541 this.tr.insertBefore(td, this.tr.childNodes[index]);
26543 this.items.insert(index, item);
26548 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26549 * @param {Object} config
26550 * @return {Roo.Toolbar.Item} The element's item
26552 addDom : function(config, returnEl){
26553 var td = this.nextBlock();
26554 Roo.DomHelper.overwrite(td, config);
26555 var ti = new Roo.Toolbar.Item(td.firstChild);
26557 this.items.add(ti);
26562 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26563 * @type Roo.util.MixedCollection
26568 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26569 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26570 * @param {Roo.form.Field} field
26571 * @return {Roo.ToolbarItem}
26575 addField : function(field) {
26576 if (!this.fields) {
26578 this.fields = new Roo.util.MixedCollection(false, function(o){
26579 return o.id || ("item" + (++autoId));
26584 var td = this.nextBlock();
26586 var ti = new Roo.Toolbar.Item(td.firstChild);
26588 this.items.add(ti);
26589 this.fields.add(field);
26600 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26601 this.el.child('div').hide();
26609 this.el.child('div').show();
26613 nextBlock : function(){
26614 var td = document.createElement("td");
26615 this.tr.appendChild(td);
26620 destroy : function(){
26621 if(this.items){ // rendered?
26622 Roo.destroy.apply(Roo, this.items.items);
26624 if(this.fields){ // rendered?
26625 Roo.destroy.apply(Roo, this.fields.items);
26627 Roo.Element.uncache(this.el, this.tr);
26632 * @class Roo.Toolbar.Item
26633 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26635 * Creates a new Item
26636 * @param {HTMLElement} el
26638 Roo.Toolbar.Item = function(el){
26639 this.el = Roo.getDom(el);
26640 this.id = Roo.id(this.el);
26641 this.hidden = false;
26644 Roo.Toolbar.Item.prototype = {
26647 * Get this item's HTML Element
26648 * @return {HTMLElement}
26650 getEl : function(){
26655 render : function(td){
26657 td.appendChild(this.el);
26661 * Removes and destroys this item.
26663 destroy : function(){
26664 this.td.parentNode.removeChild(this.td);
26671 this.hidden = false;
26672 this.td.style.display = "";
26679 this.hidden = true;
26680 this.td.style.display = "none";
26684 * Convenience function for boolean show/hide.
26685 * @param {Boolean} visible true to show/false to hide
26687 setVisible: function(visible){
26696 * Try to focus this item.
26698 focus : function(){
26699 Roo.fly(this.el).focus();
26703 * Disables this item.
26705 disable : function(){
26706 Roo.fly(this.td).addClass("x-item-disabled");
26707 this.disabled = true;
26708 this.el.disabled = true;
26712 * Enables this item.
26714 enable : function(){
26715 Roo.fly(this.td).removeClass("x-item-disabled");
26716 this.disabled = false;
26717 this.el.disabled = false;
26723 * @class Roo.Toolbar.Separator
26724 * @extends Roo.Toolbar.Item
26725 * A simple toolbar separator class
26727 * Creates a new Separator
26729 Roo.Toolbar.Separator = function(){
26730 var s = document.createElement("span");
26731 s.className = "ytb-sep";
26732 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
26734 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
26735 enable:Roo.emptyFn,
26736 disable:Roo.emptyFn,
26741 * @class Roo.Toolbar.Spacer
26742 * @extends Roo.Toolbar.Item
26743 * A simple element that adds extra horizontal space to a toolbar.
26745 * Creates a new Spacer
26747 Roo.Toolbar.Spacer = function(){
26748 var s = document.createElement("div");
26749 s.className = "ytb-spacer";
26750 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
26752 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
26753 enable:Roo.emptyFn,
26754 disable:Roo.emptyFn,
26759 * @class Roo.Toolbar.Fill
26760 * @extends Roo.Toolbar.Spacer
26761 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
26763 * Creates a new Spacer
26765 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
26767 render : function(td){
26768 td.style.width = '100%';
26769 Roo.Toolbar.Fill.superclass.render.call(this, td);
26774 * @class Roo.Toolbar.TextItem
26775 * @extends Roo.Toolbar.Item
26776 * A simple class that renders text directly into a toolbar.
26778 * Creates a new TextItem
26779 * @param {String} text
26781 Roo.Toolbar.TextItem = function(text){
26782 if (typeof(text) == 'object') {
26785 var s = document.createElement("span");
26786 s.className = "ytb-text";
26787 s.innerHTML = text;
26788 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
26790 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
26791 enable:Roo.emptyFn,
26792 disable:Roo.emptyFn,
26797 * @class Roo.Toolbar.Button
26798 * @extends Roo.Button
26799 * A button that renders into a toolbar.
26801 * Creates a new Button
26802 * @param {Object} config A standard {@link Roo.Button} config object
26804 Roo.Toolbar.Button = function(config){
26805 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
26807 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
26808 render : function(td){
26810 Roo.Toolbar.Button.superclass.render.call(this, td);
26814 * Removes and destroys this button
26816 destroy : function(){
26817 Roo.Toolbar.Button.superclass.destroy.call(this);
26818 this.td.parentNode.removeChild(this.td);
26822 * Shows this button
26825 this.hidden = false;
26826 this.td.style.display = "";
26830 * Hides this button
26833 this.hidden = true;
26834 this.td.style.display = "none";
26838 * Disables this item
26840 disable : function(){
26841 Roo.fly(this.td).addClass("x-item-disabled");
26842 this.disabled = true;
26846 * Enables this item
26848 enable : function(){
26849 Roo.fly(this.td).removeClass("x-item-disabled");
26850 this.disabled = false;
26853 // backwards compat
26854 Roo.ToolbarButton = Roo.Toolbar.Button;
26857 * @class Roo.Toolbar.SplitButton
26858 * @extends Roo.SplitButton
26859 * A menu button that renders into a toolbar.
26861 * Creates a new SplitButton
26862 * @param {Object} config A standard {@link Roo.SplitButton} config object
26864 Roo.Toolbar.SplitButton = function(config){
26865 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
26867 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
26868 render : function(td){
26870 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
26874 * Removes and destroys this button
26876 destroy : function(){
26877 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
26878 this.td.parentNode.removeChild(this.td);
26882 * Shows this button
26885 this.hidden = false;
26886 this.td.style.display = "";
26890 * Hides this button
26893 this.hidden = true;
26894 this.td.style.display = "none";
26898 // backwards compat
26899 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
26901 * Ext JS Library 1.1.1
26902 * Copyright(c) 2006-2007, Ext JS, LLC.
26904 * Originally Released Under LGPL - original licence link has changed is not relivant.
26907 * <script type="text/javascript">
26911 * @class Roo.PagingToolbar
26912 * @extends Roo.Toolbar
26913 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26915 * Create a new PagingToolbar
26916 * @param {Object} config The config object
26918 Roo.PagingToolbar = function(el, ds, config)
26920 // old args format still supported... - xtype is prefered..
26921 if (typeof(el) == 'object' && el.xtype) {
26922 // created from xtype...
26924 ds = el.dataSource;
26925 el = config.container;
26929 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
26932 this.renderButtons(this.el);
26936 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
26938 * @cfg {Roo.data.Store} dataSource
26939 * The underlying data store providing the paged data
26942 * @cfg {String/HTMLElement/Element} container
26943 * container The id or element that will contain the toolbar
26946 * @cfg {Boolean} displayInfo
26947 * True to display the displayMsg (defaults to false)
26950 * @cfg {Number} pageSize
26951 * The number of records to display per page (defaults to 20)
26955 * @cfg {String} displayMsg
26956 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26958 displayMsg : 'Displaying {0} - {1} of {2}',
26960 * @cfg {String} emptyMsg
26961 * The message to display when no records are found (defaults to "No data to display")
26963 emptyMsg : 'No data to display',
26965 * Customizable piece of the default paging text (defaults to "Page")
26968 beforePageText : "Page",
26970 * Customizable piece of the default paging text (defaults to "of %0")
26973 afterPageText : "of {0}",
26975 * Customizable piece of the default paging text (defaults to "First Page")
26978 firstText : "First Page",
26980 * Customizable piece of the default paging text (defaults to "Previous Page")
26983 prevText : "Previous Page",
26985 * Customizable piece of the default paging text (defaults to "Next Page")
26988 nextText : "Next Page",
26990 * Customizable piece of the default paging text (defaults to "Last Page")
26993 lastText : "Last Page",
26995 * Customizable piece of the default paging text (defaults to "Refresh")
26998 refreshText : "Refresh",
27001 renderButtons : function(el){
27002 Roo.PagingToolbar.superclass.render.call(this, el);
27003 this.first = this.addButton({
27004 tooltip: this.firstText,
27005 cls: "x-btn-icon x-grid-page-first",
27007 handler: this.onClick.createDelegate(this, ["first"])
27009 this.prev = this.addButton({
27010 tooltip: this.prevText,
27011 cls: "x-btn-icon x-grid-page-prev",
27013 handler: this.onClick.createDelegate(this, ["prev"])
27015 this.addSeparator();
27016 this.add(this.beforePageText);
27017 this.field = Roo.get(this.addDom({
27022 cls: "x-grid-page-number"
27024 this.field.on("keydown", this.onPagingKeydown, this);
27025 this.field.on("focus", function(){this.dom.select();});
27026 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27027 this.field.setHeight(18);
27028 this.addSeparator();
27029 this.next = this.addButton({
27030 tooltip: this.nextText,
27031 cls: "x-btn-icon x-grid-page-next",
27033 handler: this.onClick.createDelegate(this, ["next"])
27035 this.last = this.addButton({
27036 tooltip: this.lastText,
27037 cls: "x-btn-icon x-grid-page-last",
27039 handler: this.onClick.createDelegate(this, ["last"])
27041 this.addSeparator();
27042 this.loading = this.addButton({
27043 tooltip: this.refreshText,
27044 cls: "x-btn-icon x-grid-loading",
27045 handler: this.onClick.createDelegate(this, ["refresh"])
27048 if(this.displayInfo){
27049 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27054 updateInfo : function(){
27055 if(this.displayEl){
27056 var count = this.ds.getCount();
27057 var msg = count == 0 ?
27061 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27063 this.displayEl.update(msg);
27068 onLoad : function(ds, r, o){
27069 this.cursor = o.params ? o.params.start : 0;
27070 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27072 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27073 this.field.dom.value = ap;
27074 this.first.setDisabled(ap == 1);
27075 this.prev.setDisabled(ap == 1);
27076 this.next.setDisabled(ap == ps);
27077 this.last.setDisabled(ap == ps);
27078 this.loading.enable();
27083 getPageData : function(){
27084 var total = this.ds.getTotalCount();
27087 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27088 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27093 onLoadError : function(){
27094 this.loading.enable();
27098 onPagingKeydown : function(e){
27099 var k = e.getKey();
27100 var d = this.getPageData();
27102 var v = this.field.dom.value, pageNum;
27103 if(!v || isNaN(pageNum = parseInt(v, 10))){
27104 this.field.dom.value = d.activePage;
27107 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27108 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27111 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))
27113 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27114 this.field.dom.value = pageNum;
27115 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27118 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27120 var v = this.field.dom.value, pageNum;
27121 var increment = (e.shiftKey) ? 10 : 1;
27122 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27124 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27125 this.field.dom.value = d.activePage;
27128 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27130 this.field.dom.value = parseInt(v, 10) + increment;
27131 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27132 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27139 beforeLoad : function(){
27141 this.loading.disable();
27146 onClick : function(which){
27150 ds.load({params:{start: 0, limit: this.pageSize}});
27153 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27156 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27159 var total = ds.getTotalCount();
27160 var extra = total % this.pageSize;
27161 var lastStart = extra ? (total - extra) : total-this.pageSize;
27162 ds.load({params:{start: lastStart, limit: this.pageSize}});
27165 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27171 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27172 * @param {Roo.data.Store} store The data store to unbind
27174 unbind : function(ds){
27175 ds.un("beforeload", this.beforeLoad, this);
27176 ds.un("load", this.onLoad, this);
27177 ds.un("loadexception", this.onLoadError, this);
27178 ds.un("remove", this.updateInfo, this);
27179 ds.un("add", this.updateInfo, this);
27180 this.ds = undefined;
27184 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27185 * @param {Roo.data.Store} store The data store to bind
27187 bind : function(ds){
27188 ds.on("beforeload", this.beforeLoad, this);
27189 ds.on("load", this.onLoad, this);
27190 ds.on("loadexception", this.onLoadError, this);
27191 ds.on("remove", this.updateInfo, this);
27192 ds.on("add", this.updateInfo, this);
27197 * Ext JS Library 1.1.1
27198 * Copyright(c) 2006-2007, Ext JS, LLC.
27200 * Originally Released Under LGPL - original licence link has changed is not relivant.
27203 * <script type="text/javascript">
27207 * @class Roo.Resizable
27208 * @extends Roo.util.Observable
27209 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27210 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27211 * the textarea in a div and set "resizeChild" to true (or to the id of the element), <b>or</b> set wrap:true in your config and
27212 * the element will be wrapped for you automatically.</p>
27213 * <p>Here is the list of valid resize handles:</p>
27216 ------ -------------------
27227 * <p>Here's an example showing the creation of a typical Resizable:</p>
27229 var resizer = new Roo.Resizable("element-id", {
27237 resizer.on("resize", myHandler);
27239 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27240 * resizer.east.setDisplayed(false);</p>
27241 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27242 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27243 * resize operation's new size (defaults to [0, 0])
27244 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27245 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27246 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27247 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27248 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27249 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27250 * @cfg {Number} width The width of the element in pixels (defaults to null)
27251 * @cfg {Number} height The height of the element in pixels (defaults to null)
27252 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27253 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27254 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27255 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27256 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27257 * in favor of the handles config option (defaults to false)
27258 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27259 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27260 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27261 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27262 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27263 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27264 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27265 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27266 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27267 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27268 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27270 * Create a new resizable component
27271 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27272 * @param {Object} config configuration options
27274 Roo.Resizable = function(el, config){
27275 this.el = Roo.get(el);
27277 if(config && config.wrap){
27278 config.resizeChild = this.el;
27279 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27280 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27281 this.el.setStyle("overflow", "hidden");
27282 this.el.setPositioning(config.resizeChild.getPositioning());
27283 config.resizeChild.clearPositioning();
27284 if(!config.width || !config.height){
27285 var csize = config.resizeChild.getSize();
27286 this.el.setSize(csize.width, csize.height);
27288 if(config.pinned && !config.adjustments){
27289 config.adjustments = "auto";
27293 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27294 this.proxy.unselectable();
27295 this.proxy.enableDisplayMode('block');
27297 Roo.apply(this, config);
27300 this.disableTrackOver = true;
27301 this.el.addClass("x-resizable-pinned");
27303 // if the element isn't positioned, make it relative
27304 var position = this.el.getStyle("position");
27305 if(position != "absolute" && position != "fixed"){
27306 this.el.setStyle("position", "relative");
27308 if(!this.handles){ // no handles passed, must be legacy style
27309 this.handles = 's,e,se';
27310 if(this.multiDirectional){
27311 this.handles += ',n,w';
27314 if(this.handles == "all"){
27315 this.handles = "n s e w ne nw se sw";
27317 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27318 var ps = Roo.Resizable.positions;
27319 for(var i = 0, len = hs.length; i < len; i++){
27320 if(hs[i] && ps[hs[i]]){
27321 var pos = ps[hs[i]];
27322 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27326 this.corner = this.southeast;
27328 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1){
27329 this.updateBox = true;
27332 this.activeHandle = null;
27334 if(this.resizeChild){
27335 if(typeof this.resizeChild == "boolean"){
27336 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27338 this.resizeChild = Roo.get(this.resizeChild, true);
27342 if(this.adjustments == "auto"){
27343 var rc = this.resizeChild;
27344 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27345 if(rc && (hw || hn)){
27346 rc.position("relative");
27347 rc.setLeft(hw ? hw.el.getWidth() : 0);
27348 rc.setTop(hn ? hn.el.getHeight() : 0);
27350 this.adjustments = [
27351 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27352 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27356 if(this.draggable){
27357 this.dd = this.dynamic ?
27358 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27359 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27365 * @event beforeresize
27366 * Fired before resize is allowed. Set enabled to false to cancel resize.
27367 * @param {Roo.Resizable} this
27368 * @param {Roo.EventObject} e The mousedown event
27370 "beforeresize" : true,
27373 * Fired after a resize.
27374 * @param {Roo.Resizable} this
27375 * @param {Number} width The new width
27376 * @param {Number} height The new height
27377 * @param {Roo.EventObject} e The mouseup event
27382 if(this.width !== null && this.height !== null){
27383 this.resizeTo(this.width, this.height);
27385 this.updateChildSize();
27388 this.el.dom.style.zoom = 1;
27390 Roo.Resizable.superclass.constructor.call(this);
27393 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27394 resizeChild : false,
27395 adjustments : [0, 0],
27405 multiDirectional : false,
27406 disableTrackOver : false,
27407 easing : 'easeOutStrong',
27408 widthIncrement : 0,
27409 heightIncrement : 0,
27413 preserveRatio : false,
27414 transparent: false,
27420 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27422 constrainTo: undefined,
27424 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27426 resizeRegion: undefined,
27430 * Perform a manual resize
27431 * @param {Number} width
27432 * @param {Number} height
27434 resizeTo : function(width, height){
27435 this.el.setSize(width, height);
27436 this.updateChildSize();
27437 this.fireEvent("resize", this, width, height, null);
27441 startSizing : function(e, handle){
27442 this.fireEvent("beforeresize", this, e);
27443 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27446 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27447 this.overlay.unselectable();
27448 this.overlay.enableDisplayMode("block");
27449 this.overlay.on("mousemove", this.onMouseMove, this);
27450 this.overlay.on("mouseup", this.onMouseUp, this);
27452 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27454 this.resizing = true;
27455 this.startBox = this.el.getBox();
27456 this.startPoint = e.getXY();
27457 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27458 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27460 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27461 this.overlay.show();
27463 if(this.constrainTo) {
27464 var ct = Roo.get(this.constrainTo);
27465 this.resizeRegion = ct.getRegion().adjust(
27466 ct.getFrameWidth('t'),
27467 ct.getFrameWidth('l'),
27468 -ct.getFrameWidth('b'),
27469 -ct.getFrameWidth('r')
27473 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27475 this.proxy.setBox(this.startBox);
27477 this.proxy.setStyle('visibility', 'visible');
27483 onMouseDown : function(handle, e){
27486 this.activeHandle = handle;
27487 this.startSizing(e, handle);
27492 onMouseUp : function(e){
27493 var size = this.resizeElement();
27494 this.resizing = false;
27496 this.overlay.hide();
27498 this.fireEvent("resize", this, size.width, size.height, e);
27502 updateChildSize : function(){
27503 if(this.resizeChild){
27505 var child = this.resizeChild;
27506 var adj = this.adjustments;
27507 if(el.dom.offsetWidth){
27508 var b = el.getSize(true);
27509 child.setSize(b.width+adj[0], b.height+adj[1]);
27511 // Second call here for IE
27512 // The first call enables instant resizing and
27513 // the second call corrects scroll bars if they
27516 setTimeout(function(){
27517 if(el.dom.offsetWidth){
27518 var b = el.getSize(true);
27519 child.setSize(b.width+adj[0], b.height+adj[1]);
27527 snap : function(value, inc, min){
27528 if(!inc || !value) return value;
27529 var newValue = value;
27530 var m = value % inc;
27533 newValue = value + (inc-m);
27535 newValue = value - m;
27538 return Math.max(min, newValue);
27542 resizeElement : function(){
27543 var box = this.proxy.getBox();
27544 if(this.updateBox){
27545 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27547 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27549 this.updateChildSize();
27557 constrain : function(v, diff, m, mx){
27560 }else if(v - diff > mx){
27567 onMouseMove : function(e){
27569 try{// try catch so if something goes wrong the user doesn't get hung
27571 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27575 //var curXY = this.startPoint;
27576 var curSize = this.curSize || this.startBox;
27577 var x = this.startBox.x, y = this.startBox.y;
27578 var ox = x, oy = y;
27579 var w = curSize.width, h = curSize.height;
27580 var ow = w, oh = h;
27581 var mw = this.minWidth, mh = this.minHeight;
27582 var mxw = this.maxWidth, mxh = this.maxHeight;
27583 var wi = this.widthIncrement;
27584 var hi = this.heightIncrement;
27586 var eventXY = e.getXY();
27587 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27588 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27590 var pos = this.activeHandle.position;
27595 w = Math.min(Math.max(mw, w), mxw);
27599 h = Math.min(Math.max(mh, h), mxh);
27604 w = Math.min(Math.max(mw, w), mxw);
27605 h = Math.min(Math.max(mh, h), mxh);
27608 diffY = this.constrain(h, diffY, mh, mxh);
27613 diffX = this.constrain(w, diffX, mw, mxw);
27619 w = Math.min(Math.max(mw, w), mxw);
27620 diffY = this.constrain(h, diffY, mh, mxh);
27625 diffX = this.constrain(w, diffX, mw, mxw);
27626 diffY = this.constrain(h, diffY, mh, mxh);
27633 diffX = this.constrain(w, diffX, mw, mxw);
27635 h = Math.min(Math.max(mh, h), mxh);
27641 var sw = this.snap(w, wi, mw);
27642 var sh = this.snap(h, hi, mh);
27643 if(sw != w || sh != h){
27666 if(this.preserveRatio){
27671 h = Math.min(Math.max(mh, h), mxh);
27676 w = Math.min(Math.max(mw, w), mxw);
27681 w = Math.min(Math.max(mw, w), mxw);
27687 w = Math.min(Math.max(mw, w), mxw);
27693 h = Math.min(Math.max(mh, h), mxh);
27701 h = Math.min(Math.max(mh, h), mxh);
27711 h = Math.min(Math.max(mh, h), mxh);
27719 this.proxy.setBounds(x, y, w, h);
27721 this.resizeElement();
27728 handleOver : function(){
27730 this.el.addClass("x-resizable-over");
27735 handleOut : function(){
27736 if(!this.resizing){
27737 this.el.removeClass("x-resizable-over");
27742 * Returns the element this component is bound to.
27743 * @return {Roo.Element}
27745 getEl : function(){
27750 * Returns the resizeChild element (or null).
27751 * @return {Roo.Element}
27753 getResizeChild : function(){
27754 return this.resizeChild;
27758 * Destroys this resizable. If the element was wrapped and
27759 * removeEl is not true then the element remains.
27760 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
27762 destroy : function(removeEl){
27763 this.proxy.remove();
27765 this.overlay.removeAllListeners();
27766 this.overlay.remove();
27768 var ps = Roo.Resizable.positions;
27770 if(typeof ps[k] != "function" && this[ps[k]]){
27771 var h = this[ps[k]];
27772 h.el.removeAllListeners();
27777 this.el.update("");
27784 // hash to map config positions to true positions
27785 Roo.Resizable.positions = {
27786 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast"
27790 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
27792 // only initialize the template if resizable is used
27793 var tpl = Roo.DomHelper.createTemplate(
27794 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
27797 Roo.Resizable.Handle.prototype.tpl = tpl;
27799 this.position = pos;
27801 this.el = this.tpl.append(rz.el.dom, [this.position], true);
27802 this.el.unselectable();
27804 this.el.setOpacity(0);
27806 this.el.on("mousedown", this.onMouseDown, this);
27807 if(!disableTrackOver){
27808 this.el.on("mouseover", this.onMouseOver, this);
27809 this.el.on("mouseout", this.onMouseOut, this);
27814 Roo.Resizable.Handle.prototype = {
27815 afterResize : function(rz){
27819 onMouseDown : function(e){
27820 this.rz.onMouseDown(this, e);
27823 onMouseOver : function(e){
27824 this.rz.handleOver(this, e);
27827 onMouseOut : function(e){
27828 this.rz.handleOut(this, e);
27832 * Ext JS Library 1.1.1
27833 * Copyright(c) 2006-2007, Ext JS, LLC.
27835 * Originally Released Under LGPL - original licence link has changed is not relivant.
27838 * <script type="text/javascript">
27842 * @class Roo.Editor
27843 * @extends Roo.Component
27844 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
27846 * Create a new Editor
27847 * @param {Roo.form.Field} field The Field object (or descendant)
27848 * @param {Object} config The config object
27850 Roo.Editor = function(field, config){
27851 Roo.Editor.superclass.constructor.call(this, config);
27852 this.field = field;
27855 * @event beforestartedit
27856 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
27857 * false from the handler of this event.
27858 * @param {Editor} this
27859 * @param {Roo.Element} boundEl The underlying element bound to this editor
27860 * @param {Mixed} value The field value being set
27862 "beforestartedit" : true,
27865 * Fires when this editor is displayed
27866 * @param {Roo.Element} boundEl The underlying element bound to this editor
27867 * @param {Mixed} value The starting field value
27869 "startedit" : true,
27871 * @event beforecomplete
27872 * Fires after a change has been made to the field, but before the change is reflected in the underlying
27873 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
27874 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
27875 * event will not fire since no edit actually occurred.
27876 * @param {Editor} this
27877 * @param {Mixed} value The current field value
27878 * @param {Mixed} startValue The original field value
27880 "beforecomplete" : true,
27883 * Fires after editing is complete and any changed value has been written to the underlying field.
27884 * @param {Editor} this
27885 * @param {Mixed} value The current field value
27886 * @param {Mixed} startValue The original field value
27890 * @event specialkey
27891 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
27892 * {@link Roo.EventObject#getKey} to determine which key was pressed.
27893 * @param {Roo.form.Field} this
27894 * @param {Roo.EventObject} e The event object
27896 "specialkey" : true
27900 Roo.extend(Roo.Editor, Roo.Component, {
27902 * @cfg {Boolean/String} autosize
27903 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
27904 * or "height" to adopt the height only (defaults to false)
27907 * @cfg {Boolean} revertInvalid
27908 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
27909 * validation fails (defaults to true)
27912 * @cfg {Boolean} ignoreNoChange
27913 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
27914 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
27915 * will never be ignored.
27918 * @cfg {Boolean} hideEl
27919 * False to keep the bound element visible while the editor is displayed (defaults to true)
27922 * @cfg {Mixed} value
27923 * The data value of the underlying field (defaults to "")
27927 * @cfg {String} alignment
27928 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
27932 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
27933 * for bottom-right shadow (defaults to "frame")
27937 * @cfg {Boolean} constrain True to constrain the editor to the viewport
27941 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
27943 completeOnEnter : false,
27945 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
27947 cancelOnEsc : false,
27949 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
27954 onRender : function(ct, position){
27955 this.el = new Roo.Layer({
27956 shadow: this.shadow,
27962 constrain: this.constrain
27964 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
27965 if(this.field.msgTarget != 'title'){
27966 this.field.msgTarget = 'qtip';
27968 this.field.render(this.el);
27970 this.field.el.dom.setAttribute('autocomplete', 'off');
27972 this.field.on("specialkey", this.onSpecialKey, this);
27973 if(this.swallowKeys){
27974 this.field.el.swallowEvent(['keydown','keypress']);
27977 this.field.on("blur", this.onBlur, this);
27978 if(this.field.grow){
27979 this.field.on("autosize", this.el.sync, this.el, {delay:1});
27983 onSpecialKey : function(field, e){
27984 if(this.completeOnEnter && e.getKey() == e.ENTER){
27986 this.completeEdit();
27987 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
27990 this.fireEvent('specialkey', field, e);
27995 * Starts the editing process and shows the editor.
27996 * @param {String/HTMLElement/Element} el The element to edit
27997 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
27998 * to the innerHTML of el.
28000 startEdit : function(el, value){
28002 this.completeEdit();
28004 this.boundEl = Roo.get(el);
28005 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28006 if(!this.rendered){
28007 this.render(this.parentEl || document.body);
28009 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28012 this.startValue = v;
28013 this.field.setValue(v);
28015 var sz = this.boundEl.getSize();
28016 switch(this.autoSize){
28018 this.setSize(sz.width, "");
28021 this.setSize("", sz.height);
28024 this.setSize(sz.width, sz.height);
28027 this.el.alignTo(this.boundEl, this.alignment);
28028 this.editing = true;
28030 Roo.QuickTips.disable();
28036 * Sets the height and width of this editor.
28037 * @param {Number} width The new width
28038 * @param {Number} height The new height
28040 setSize : function(w, h){
28041 this.field.setSize(w, h);
28048 * Realigns the editor to the bound field based on the current alignment config value.
28050 realign : function(){
28051 this.el.alignTo(this.boundEl, this.alignment);
28055 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28056 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28058 completeEdit : function(remainVisible){
28062 var v = this.getValue();
28063 if(this.revertInvalid !== false && !this.field.isValid()){
28064 v = this.startValue;
28065 this.cancelEdit(true);
28067 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28068 this.editing = false;
28072 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28073 this.editing = false;
28074 if(this.updateEl && this.boundEl){
28075 this.boundEl.update(v);
28077 if(remainVisible !== true){
28080 this.fireEvent("complete", this, v, this.startValue);
28085 onShow : function(){
28087 if(this.hideEl !== false){
28088 this.boundEl.hide();
28091 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28092 this.fixIEFocus = true;
28093 this.deferredFocus.defer(50, this);
28095 this.field.focus();
28097 this.fireEvent("startedit", this.boundEl, this.startValue);
28100 deferredFocus : function(){
28102 this.field.focus();
28107 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28108 * reverted to the original starting value.
28109 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28110 * cancel (defaults to false)
28112 cancelEdit : function(remainVisible){
28114 this.setValue(this.startValue);
28115 if(remainVisible !== true){
28122 onBlur : function(){
28123 if(this.allowBlur !== true && this.editing){
28124 this.completeEdit();
28129 onHide : function(){
28131 this.completeEdit();
28135 if(this.field.collapse){
28136 this.field.collapse();
28139 if(this.hideEl !== false){
28140 this.boundEl.show();
28143 Roo.QuickTips.enable();
28148 * Sets the data value of the editor
28149 * @param {Mixed} value Any valid value supported by the underlying field
28151 setValue : function(v){
28152 this.field.setValue(v);
28156 * Gets the data value of the editor
28157 * @return {Mixed} The data value
28159 getValue : function(){
28160 return this.field.getValue();
28164 * Ext JS Library 1.1.1
28165 * Copyright(c) 2006-2007, Ext JS, LLC.
28167 * Originally Released Under LGPL - original licence link has changed is not relivant.
28170 * <script type="text/javascript">
28174 * @class Roo.BasicDialog
28175 * @extends Roo.util.Observable
28176 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28178 var dlg = new Roo.BasicDialog("my-dlg", {
28187 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28188 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28189 dlg.addButton('Cancel', dlg.hide, dlg);
28192 <b>A Dialog should always be a direct child of the body element.</b>
28193 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28194 * @cfg {String} title Default text to display in the title bar (defaults to null)
28195 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28196 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28197 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28198 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28199 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28200 * (defaults to null with no animation)
28201 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28202 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28203 * property for valid values (defaults to 'all')
28204 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28205 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28206 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28207 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28208 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28209 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28210 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28211 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28212 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28213 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28214 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28215 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28216 * draggable = true (defaults to false)
28217 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28218 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28219 * shadow (defaults to false)
28220 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28221 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28222 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28223 * @cfg {Array} buttons Array of buttons
28224 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28226 * Create a new BasicDialog.
28227 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28228 * @param {Object} config Configuration options
28230 Roo.BasicDialog = function(el, config){
28231 this.el = Roo.get(el);
28232 var dh = Roo.DomHelper;
28233 if(!this.el && config && config.autoCreate){
28234 if(typeof config.autoCreate == "object"){
28235 if(!config.autoCreate.id){
28236 config.autoCreate.id = el;
28238 this.el = dh.append(document.body,
28239 config.autoCreate, true);
28241 this.el = dh.append(document.body,
28242 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28246 el.setDisplayed(true);
28247 el.hide = this.hideAction;
28249 el.addClass("x-dlg");
28251 Roo.apply(this, config);
28253 this.proxy = el.createProxy("x-dlg-proxy");
28254 this.proxy.hide = this.hideAction;
28255 this.proxy.setOpacity(.5);
28259 el.setWidth(config.width);
28262 el.setHeight(config.height);
28264 this.size = el.getSize();
28265 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28266 this.xy = [config.x,config.y];
28268 this.xy = el.getCenterXY(true);
28270 /** The header element @type Roo.Element */
28271 this.header = el.child("> .x-dlg-hd");
28272 /** The body element @type Roo.Element */
28273 this.body = el.child("> .x-dlg-bd");
28274 /** The footer element @type Roo.Element */
28275 this.footer = el.child("> .x-dlg-ft");
28278 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28281 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28284 this.header.unselectable();
28286 this.header.update(this.title);
28288 // this element allows the dialog to be focused for keyboard event
28289 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28290 this.focusEl.swallowEvent("click", true);
28292 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28294 // wrap the body and footer for special rendering
28295 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28297 this.bwrap.dom.appendChild(this.footer.dom);
28300 this.bg = this.el.createChild({
28301 tag: "div", cls:"x-dlg-bg",
28302 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28304 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28307 if(this.autoScroll !== false && !this.autoTabs){
28308 this.body.setStyle("overflow", "auto");
28311 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28313 if(this.closable !== false){
28314 this.el.addClass("x-dlg-closable");
28315 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28316 this.close.on("click", this.closeClick, this);
28317 this.close.addClassOnOver("x-dlg-close-over");
28319 if(this.collapsible !== false){
28320 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28321 this.collapseBtn.on("click", this.collapseClick, this);
28322 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28323 this.header.on("dblclick", this.collapseClick, this);
28325 if(this.resizable !== false){
28326 this.el.addClass("x-dlg-resizable");
28327 this.resizer = new Roo.Resizable(el, {
28328 minWidth: this.minWidth || 80,
28329 minHeight:this.minHeight || 80,
28330 handles: this.resizeHandles || "all",
28333 this.resizer.on("beforeresize", this.beforeResize, this);
28334 this.resizer.on("resize", this.onResize, this);
28336 if(this.draggable !== false){
28337 el.addClass("x-dlg-draggable");
28338 if (!this.proxyDrag) {
28339 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28342 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28344 dd.setHandleElId(this.header.id);
28345 dd.endDrag = this.endMove.createDelegate(this);
28346 dd.startDrag = this.startMove.createDelegate(this);
28347 dd.onDrag = this.onDrag.createDelegate(this);
28352 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28353 this.mask.enableDisplayMode("block");
28355 this.el.addClass("x-dlg-modal");
28358 this.shadow = new Roo.Shadow({
28359 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28360 offset : this.shadowOffset
28363 this.shadowOffset = 0;
28365 if(Roo.useShims && this.shim !== false){
28366 this.shim = this.el.createShim();
28367 this.shim.hide = this.hideAction;
28375 if (this.buttons) {
28376 var bts= this.buttons;
28378 Roo.each(bts, function(b) {
28387 * Fires when a key is pressed
28388 * @param {Roo.BasicDialog} this
28389 * @param {Roo.EventObject} e
28394 * Fires when this dialog is moved by the user.
28395 * @param {Roo.BasicDialog} this
28396 * @param {Number} x The new page X
28397 * @param {Number} y The new page Y
28402 * Fires when this dialog is resized by the user.
28403 * @param {Roo.BasicDialog} this
28404 * @param {Number} width The new width
28405 * @param {Number} height The new height
28409 * @event beforehide
28410 * Fires before this dialog is hidden.
28411 * @param {Roo.BasicDialog} this
28413 "beforehide" : true,
28416 * Fires when this dialog is hidden.
28417 * @param {Roo.BasicDialog} this
28421 * @event beforeshow
28422 * Fires before this dialog is shown.
28423 * @param {Roo.BasicDialog} this
28425 "beforeshow" : true,
28428 * Fires when this dialog is shown.
28429 * @param {Roo.BasicDialog} this
28433 el.on("keydown", this.onKeyDown, this);
28434 el.on("mousedown", this.toFront, this);
28435 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28437 Roo.DialogManager.register(this);
28438 Roo.BasicDialog.superclass.constructor.call(this);
28441 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28442 shadowOffset: Roo.isIE ? 6 : 5,
28445 minButtonWidth: 75,
28446 defaultButton: null,
28447 buttonAlign: "right",
28452 * Sets the dialog title text
28453 * @param {String} text The title text to display
28454 * @return {Roo.BasicDialog} this
28456 setTitle : function(text){
28457 this.header.update(text);
28462 closeClick : function(){
28467 collapseClick : function(){
28468 this[this.collapsed ? "expand" : "collapse"]();
28472 * Collapses the dialog to its minimized state (only the title bar is visible).
28473 * Equivalent to the user clicking the collapse dialog button.
28475 collapse : function(){
28476 if(!this.collapsed){
28477 this.collapsed = true;
28478 this.el.addClass("x-dlg-collapsed");
28479 this.restoreHeight = this.el.getHeight();
28480 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28485 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28486 * clicking the expand dialog button.
28488 expand : function(){
28489 if(this.collapsed){
28490 this.collapsed = false;
28491 this.el.removeClass("x-dlg-collapsed");
28492 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28497 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28498 * @return {Roo.TabPanel} The tabs component
28500 initTabs : function(){
28501 var tabs = this.getTabs();
28502 while(tabs.getTab(0)){
28505 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28507 tabs.addTab(Roo.id(dom), dom.title);
28515 beforeResize : function(){
28516 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28520 onResize : function(){
28521 this.refreshSize();
28522 this.syncBodyHeight();
28523 this.adjustAssets();
28525 this.fireEvent("resize", this, this.size.width, this.size.height);
28529 onKeyDown : function(e){
28530 if(this.isVisible()){
28531 this.fireEvent("keydown", this, e);
28536 * Resizes the dialog.
28537 * @param {Number} width
28538 * @param {Number} height
28539 * @return {Roo.BasicDialog} this
28541 resizeTo : function(width, height){
28542 this.el.setSize(width, height);
28543 this.size = {width: width, height: height};
28544 this.syncBodyHeight();
28545 if(this.fixedcenter){
28548 if(this.isVisible()){
28549 this.constrainXY();
28550 this.adjustAssets();
28552 this.fireEvent("resize", this, width, height);
28558 * Resizes the dialog to fit the specified content size.
28559 * @param {Number} width
28560 * @param {Number} height
28561 * @return {Roo.BasicDialog} this
28563 setContentSize : function(w, h){
28564 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28565 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28566 //if(!this.el.isBorderBox()){
28567 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28568 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28571 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28572 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28574 this.resizeTo(w, h);
28579 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28580 * executed in response to a particular key being pressed while the dialog is active.
28581 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28582 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28583 * @param {Function} fn The function to call
28584 * @param {Object} scope (optional) The scope of the function
28585 * @return {Roo.BasicDialog} this
28587 addKeyListener : function(key, fn, scope){
28588 var keyCode, shift, ctrl, alt;
28589 if(typeof key == "object" && !(key instanceof Array)){
28590 keyCode = key["key"];
28591 shift = key["shift"];
28592 ctrl = key["ctrl"];
28597 var handler = function(dlg, e){
28598 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28599 var k = e.getKey();
28600 if(keyCode instanceof Array){
28601 for(var i = 0, len = keyCode.length; i < len; i++){
28602 if(keyCode[i] == k){
28603 fn.call(scope || window, dlg, k, e);
28609 fn.call(scope || window, dlg, k, e);
28614 this.on("keydown", handler);
28619 * Returns the TabPanel component (creates it if it doesn't exist).
28620 * Note: If you wish to simply check for the existence of tabs without creating them,
28621 * check for a null 'tabs' property.
28622 * @return {Roo.TabPanel} The tabs component
28624 getTabs : function(){
28626 this.el.addClass("x-dlg-auto-tabs");
28627 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28628 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28634 * Adds a button to the footer section of the dialog.
28635 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28636 * object or a valid Roo.DomHelper element config
28637 * @param {Function} handler The function called when the button is clicked
28638 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28639 * @return {Roo.Button} The new button
28641 addButton : function(config, handler, scope){
28642 var dh = Roo.DomHelper;
28644 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28646 if(!this.btnContainer){
28647 var tb = this.footer.createChild({
28649 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28650 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28652 this.btnContainer = tb.firstChild.firstChild.firstChild;
28657 minWidth: this.minButtonWidth,
28660 if(typeof config == "string"){
28661 bconfig.text = config;
28664 bconfig.dhconfig = config;
28666 Roo.apply(bconfig, config);
28670 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
28671 bconfig.position = Math.max(0, bconfig.position);
28672 fc = this.btnContainer.childNodes[bconfig.position];
28675 var btn = new Roo.Button(
28677 this.btnContainer.insertBefore(document.createElement("td"),fc)
28678 : this.btnContainer.appendChild(document.createElement("td")),
28679 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
28682 this.syncBodyHeight();
28685 * Array of all the buttons that have been added to this dialog via addButton
28690 this.buttons.push(btn);
28695 * Sets the default button to be focused when the dialog is displayed.
28696 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
28697 * @return {Roo.BasicDialog} this
28699 setDefaultButton : function(btn){
28700 this.defaultButton = btn;
28705 getHeaderFooterHeight : function(safe){
28708 height += this.header.getHeight();
28711 var fm = this.footer.getMargins();
28712 height += (this.footer.getHeight()+fm.top+fm.bottom);
28714 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
28715 height += this.centerBg.getPadding("tb");
28720 syncBodyHeight : function(){
28721 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
28722 var height = this.size.height - this.getHeaderFooterHeight(false);
28723 bd.setHeight(height-bd.getMargins("tb"));
28724 var hh = this.header.getHeight();
28725 var h = this.size.height-hh;
28727 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
28728 bw.setHeight(h-cb.getPadding("tb"));
28729 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
28730 bd.setWidth(bw.getWidth(true));
28732 this.tabs.syncHeight();
28734 this.tabs.el.repaint();
28740 * Restores the previous state of the dialog if Roo.state is configured.
28741 * @return {Roo.BasicDialog} this
28743 restoreState : function(){
28744 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
28745 if(box && box.width){
28746 this.xy = [box.x, box.y];
28747 this.resizeTo(box.width, box.height);
28753 beforeShow : function(){
28755 if(this.fixedcenter){
28756 this.xy = this.el.getCenterXY(true);
28759 Roo.get(document.body).addClass("x-body-masked");
28760 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28763 this.constrainXY();
28767 animShow : function(){
28768 var b = Roo.get(this.animateTarget, true).getBox();
28769 this.proxy.setSize(b.width, b.height);
28770 this.proxy.setLocation(b.x, b.y);
28772 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
28773 true, .35, this.showEl.createDelegate(this));
28777 * Shows the dialog.
28778 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
28779 * @return {Roo.BasicDialog} this
28781 show : function(animateTarget){
28782 if (this.fireEvent("beforeshow", this) === false){
28785 if(this.syncHeightBeforeShow){
28786 this.syncBodyHeight();
28787 }else if(this.firstShow){
28788 this.firstShow = false;
28789 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
28791 this.animateTarget = animateTarget || this.animateTarget;
28792 if(!this.el.isVisible()){
28794 if(this.animateTarget){
28804 showEl : function(){
28806 this.el.setXY(this.xy);
28808 this.adjustAssets(true);
28811 // IE peekaboo bug - fix found by Dave Fenwick
28815 this.fireEvent("show", this);
28819 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
28820 * dialog itself will receive focus.
28822 focus : function(){
28823 if(this.defaultButton){
28824 this.defaultButton.focus();
28826 this.focusEl.focus();
28831 constrainXY : function(){
28832 if(this.constraintoviewport !== false){
28833 if(!this.viewSize){
28834 if(this.container){
28835 var s = this.container.getSize();
28836 this.viewSize = [s.width, s.height];
28838 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
28841 var s = Roo.get(this.container||document).getScroll();
28843 var x = this.xy[0], y = this.xy[1];
28844 var w = this.size.width, h = this.size.height;
28845 var vw = this.viewSize[0], vh = this.viewSize[1];
28846 // only move it if it needs it
28848 // first validate right/bottom
28849 if(x + w > vw+s.left){
28853 if(y + h > vh+s.top){
28857 // then make sure top/left isn't negative
28869 if(this.isVisible()){
28870 this.el.setLocation(x, y);
28871 this.adjustAssets();
28878 onDrag : function(){
28879 if(!this.proxyDrag){
28880 this.xy = this.el.getXY();
28881 this.adjustAssets();
28886 adjustAssets : function(doShow){
28887 var x = this.xy[0], y = this.xy[1];
28888 var w = this.size.width, h = this.size.height;
28889 if(doShow === true){
28891 this.shadow.show(this.el);
28897 if(this.shadow && this.shadow.isVisible()){
28898 this.shadow.show(this.el);
28900 if(this.shim && this.shim.isVisible()){
28901 this.shim.setBounds(x, y, w, h);
28906 adjustViewport : function(w, h){
28908 w = Roo.lib.Dom.getViewWidth();
28909 h = Roo.lib.Dom.getViewHeight();
28912 this.viewSize = [w, h];
28913 if(this.modal && this.mask.isVisible()){
28914 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
28915 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28917 if(this.isVisible()){
28918 this.constrainXY();
28923 * Destroys this dialog and all its supporting elements (including any tabs, shim,
28924 * shadow, proxy, mask, etc.) Also removes all event listeners.
28925 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28927 destroy : function(removeEl){
28928 if(this.isVisible()){
28929 this.animateTarget = null;
28932 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
28934 this.tabs.destroy(removeEl);
28947 for(var i = 0, len = this.buttons.length; i < len; i++){
28948 this.buttons[i].destroy();
28951 this.el.removeAllListeners();
28952 if(removeEl === true){
28953 this.el.update("");
28956 Roo.DialogManager.unregister(this);
28960 startMove : function(){
28961 if(this.proxyDrag){
28964 if(this.constraintoviewport !== false){
28965 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
28970 endMove : function(){
28971 if(!this.proxyDrag){
28972 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
28974 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
28977 this.refreshSize();
28978 this.adjustAssets();
28980 this.fireEvent("move", this, this.xy[0], this.xy[1]);
28984 * Brings this dialog to the front of any other visible dialogs
28985 * @return {Roo.BasicDialog} this
28987 toFront : function(){
28988 Roo.DialogManager.bringToFront(this);
28993 * Sends this dialog to the back (under) of any other visible dialogs
28994 * @return {Roo.BasicDialog} this
28996 toBack : function(){
28997 Roo.DialogManager.sendToBack(this);
29002 * Centers this dialog in the viewport
29003 * @return {Roo.BasicDialog} this
29005 center : function(){
29006 var xy = this.el.getCenterXY(true);
29007 this.moveTo(xy[0], xy[1]);
29012 * Moves the dialog's top-left corner to the specified point
29013 * @param {Number} x
29014 * @param {Number} y
29015 * @return {Roo.BasicDialog} this
29017 moveTo : function(x, y){
29019 if(this.isVisible()){
29020 this.el.setXY(this.xy);
29021 this.adjustAssets();
29027 * Aligns the dialog to the specified element
29028 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29029 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29030 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29031 * @return {Roo.BasicDialog} this
29033 alignTo : function(element, position, offsets){
29034 this.xy = this.el.getAlignToXY(element, position, offsets);
29035 if(this.isVisible()){
29036 this.el.setXY(this.xy);
29037 this.adjustAssets();
29043 * Anchors an element to another element and realigns it when the window is resized.
29044 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29045 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29046 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29047 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29048 * is a number, it is used as the buffer delay (defaults to 50ms).
29049 * @return {Roo.BasicDialog} this
29051 anchorTo : function(el, alignment, offsets, monitorScroll){
29052 var action = function(){
29053 this.alignTo(el, alignment, offsets);
29055 Roo.EventManager.onWindowResize(action, this);
29056 var tm = typeof monitorScroll;
29057 if(tm != 'undefined'){
29058 Roo.EventManager.on(window, 'scroll', action, this,
29059 {buffer: tm == 'number' ? monitorScroll : 50});
29066 * Returns true if the dialog is visible
29067 * @return {Boolean}
29069 isVisible : function(){
29070 return this.el.isVisible();
29074 animHide : function(callback){
29075 var b = Roo.get(this.animateTarget).getBox();
29077 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29079 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29080 this.hideEl.createDelegate(this, [callback]));
29084 * Hides the dialog.
29085 * @param {Function} callback (optional) Function to call when the dialog is hidden
29086 * @return {Roo.BasicDialog} this
29088 hide : function(callback){
29089 if (this.fireEvent("beforehide", this) === false){
29093 this.shadow.hide();
29098 if(this.animateTarget){
29099 this.animHide(callback);
29102 this.hideEl(callback);
29108 hideEl : function(callback){
29112 Roo.get(document.body).removeClass("x-body-masked");
29114 this.fireEvent("hide", this);
29115 if(typeof callback == "function"){
29121 hideAction : function(){
29122 this.setLeft("-10000px");
29123 this.setTop("-10000px");
29124 this.setStyle("visibility", "hidden");
29128 refreshSize : function(){
29129 this.size = this.el.getSize();
29130 this.xy = this.el.getXY();
29131 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29135 // z-index is managed by the DialogManager and may be overwritten at any time
29136 setZIndex : function(index){
29138 this.mask.setStyle("z-index", index);
29141 this.shim.setStyle("z-index", ++index);
29144 this.shadow.setZIndex(++index);
29146 this.el.setStyle("z-index", ++index);
29148 this.proxy.setStyle("z-index", ++index);
29151 this.resizer.proxy.setStyle("z-index", ++index);
29154 this.lastZIndex = index;
29158 * Returns the element for this dialog
29159 * @return {Roo.Element} The underlying dialog Element
29161 getEl : function(){
29167 * @class Roo.DialogManager
29168 * Provides global access to BasicDialogs that have been created and
29169 * support for z-indexing (layering) multiple open dialogs.
29171 Roo.DialogManager = function(){
29173 var accessList = [];
29177 var sortDialogs = function(d1, d2){
29178 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29182 var orderDialogs = function(){
29183 accessList.sort(sortDialogs);
29184 var seed = Roo.DialogManager.zseed;
29185 for(var i = 0, len = accessList.length; i < len; i++){
29186 var dlg = accessList[i];
29188 dlg.setZIndex(seed + (i*10));
29195 * The starting z-index for BasicDialogs (defaults to 9000)
29196 * @type Number The z-index value
29201 register : function(dlg){
29202 list[dlg.id] = dlg;
29203 accessList.push(dlg);
29207 unregister : function(dlg){
29208 delete list[dlg.id];
29211 if(!accessList.indexOf){
29212 for( i = 0, len = accessList.length; i < len; i++){
29213 if(accessList[i] == dlg){
29214 accessList.splice(i, 1);
29219 i = accessList.indexOf(dlg);
29221 accessList.splice(i, 1);
29227 * Gets a registered dialog by id
29228 * @param {String/Object} id The id of the dialog or a dialog
29229 * @return {Roo.BasicDialog} this
29231 get : function(id){
29232 return typeof id == "object" ? id : list[id];
29236 * Brings the specified dialog to the front
29237 * @param {String/Object} dlg The id of the dialog or a dialog
29238 * @return {Roo.BasicDialog} this
29240 bringToFront : function(dlg){
29241 dlg = this.get(dlg);
29244 dlg._lastAccess = new Date().getTime();
29251 * Sends the specified dialog to the back
29252 * @param {String/Object} dlg The id of the dialog or a dialog
29253 * @return {Roo.BasicDialog} this
29255 sendToBack : function(dlg){
29256 dlg = this.get(dlg);
29257 dlg._lastAccess = -(new Date().getTime());
29263 * Hides all dialogs
29265 hideAll : function(){
29266 for(var id in list){
29267 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29276 * @class Roo.LayoutDialog
29277 * @extends Roo.BasicDialog
29278 * Dialog which provides adjustments for working with a layout in a Dialog.
29279 * Add your necessary layout config options to the dialog's config.<br>
29280 * Example usage (including a nested layout):
29283 dialog = new Roo.LayoutDialog("download-dlg", {
29292 // layout config merges with the dialog config
29294 tabPosition: "top",
29295 alwaysShowTabs: true
29298 dialog.addKeyListener(27, dialog.hide, dialog);
29299 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29300 dialog.addButton("Build It!", this.getDownload, this);
29302 // we can even add nested layouts
29303 var innerLayout = new Roo.BorderLayout("dl-inner", {
29313 innerLayout.beginUpdate();
29314 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29315 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29316 innerLayout.endUpdate(true);
29318 var layout = dialog.getLayout();
29319 layout.beginUpdate();
29320 layout.add("center", new Roo.ContentPanel("standard-panel",
29321 {title: "Download the Source", fitToFrame:true}));
29322 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29323 {title: "Build your own roo.js"}));
29324 layout.getRegion("center").showPanel(sp);
29325 layout.endUpdate();
29329 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29330 * @param {Object} config configuration options
29332 Roo.LayoutDialog = function(el, cfg){
29335 if (typeof(cfg) == 'undefined') {
29336 config = Roo.apply({}, el);
29337 el = Roo.get( document.documentElement || document.body).createChild();
29338 //config.autoCreate = true;
29342 config.autoTabs = false;
29343 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29344 this.body.setStyle({overflow:"hidden", position:"relative"});
29345 this.layout = new Roo.BorderLayout(this.body.dom, config);
29346 this.layout.monitorWindowResize = false;
29347 this.el.addClass("x-dlg-auto-layout");
29348 // fix case when center region overwrites center function
29349 this.center = Roo.BasicDialog.prototype.center;
29350 this.on("show", this.layout.layout, this.layout, true);
29351 if (config.items) {
29352 var xitems = config.items;
29353 delete config.items;
29354 Roo.each(xitems, this.addxtype, this);
29359 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29361 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29364 endUpdate : function(){
29365 this.layout.endUpdate();
29369 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29372 beginUpdate : function(){
29373 this.layout.beginUpdate();
29377 * Get the BorderLayout for this dialog
29378 * @return {Roo.BorderLayout}
29380 getLayout : function(){
29381 return this.layout;
29384 showEl : function(){
29385 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29387 this.layout.layout();
29392 // Use the syncHeightBeforeShow config option to control this automatically
29393 syncBodyHeight : function(){
29394 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29395 if(this.layout){this.layout.layout();}
29399 * Add an xtype element (actually adds to the layout.)
29400 * @return {Object} xdata xtype object data.
29403 addxtype : function(c) {
29404 return this.layout.addxtype(c);
29408 * Ext JS Library 1.1.1
29409 * Copyright(c) 2006-2007, Ext JS, LLC.
29411 * Originally Released Under LGPL - original licence link has changed is not relivant.
29414 * <script type="text/javascript">
29418 * @class Roo.MessageBox
29419 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29423 Roo.Msg.alert('Status', 'Changes saved successfully.');
29425 // Prompt for user data:
29426 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29428 // process text value...
29432 // Show a dialog using config options:
29434 title:'Save Changes?',
29435 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29436 buttons: Roo.Msg.YESNOCANCEL,
29443 Roo.MessageBox = function(){
29444 var dlg, opt, mask, waitTimer;
29445 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29446 var buttons, activeTextEl, bwidth;
29449 var handleButton = function(button){
29451 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29455 var handleHide = function(){
29456 if(opt && opt.cls){
29457 dlg.el.removeClass(opt.cls);
29460 Roo.TaskMgr.stop(waitTimer);
29466 var updateButtons = function(b){
29469 buttons["ok"].hide();
29470 buttons["cancel"].hide();
29471 buttons["yes"].hide();
29472 buttons["no"].hide();
29473 dlg.footer.dom.style.display = 'none';
29476 dlg.footer.dom.style.display = '';
29477 for(var k in buttons){
29478 if(typeof buttons[k] != "function"){
29481 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29482 width += buttons[k].el.getWidth()+15;
29492 var handleEsc = function(d, k, e){
29493 if(opt && opt.closable !== false){
29503 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29504 * @return {Roo.BasicDialog} The BasicDialog element
29506 getDialog : function(){
29508 dlg = new Roo.BasicDialog("x-msg-box", {
29513 constraintoviewport:false,
29515 collapsible : false,
29518 width:400, height:100,
29519 buttonAlign:"center",
29520 closeClick : function(){
29521 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29522 handleButton("no");
29524 handleButton("cancel");
29528 dlg.on("hide", handleHide);
29530 dlg.addKeyListener(27, handleEsc);
29532 var bt = this.buttonText;
29533 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29534 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29535 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29536 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29537 bodyEl = dlg.body.createChild({
29539 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" /><textarea class="roo-mb-textarea"></textarea><div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
29541 msgEl = bodyEl.dom.firstChild;
29542 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29543 textboxEl.enableDisplayMode();
29544 textboxEl.addKeyListener([10,13], function(){
29545 if(dlg.isVisible() && opt && opt.buttons){
29546 if(opt.buttons.ok){
29547 handleButton("ok");
29548 }else if(opt.buttons.yes){
29549 handleButton("yes");
29553 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29554 textareaEl.enableDisplayMode();
29555 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29556 progressEl.enableDisplayMode();
29557 var pf = progressEl.dom.firstChild;
29559 pp = Roo.get(pf.firstChild);
29560 pp.setHeight(pf.offsetHeight);
29568 * Updates the message box body text
29569 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29570 * the XHTML-compliant non-breaking space character '&#160;')
29571 * @return {Roo.MessageBox} This message box
29573 updateText : function(text){
29574 if(!dlg.isVisible() && !opt.width){
29575 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29577 msgEl.innerHTML = text || ' ';
29578 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29579 Math.max(opt.minWidth || this.minWidth, bwidth));
29581 activeTextEl.setWidth(w);
29583 if(dlg.isVisible()){
29584 dlg.fixedcenter = false;
29586 dlg.setContentSize(w, bodyEl.getHeight());
29587 if(dlg.isVisible()){
29588 dlg.fixedcenter = true;
29594 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29595 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29596 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29597 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29598 * @return {Roo.MessageBox} This message box
29600 updateProgress : function(value, text){
29602 this.updateText(text);
29604 if (pp) { // weird bug on my firefox - for some reason this is not defined
29605 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29611 * Returns true if the message box is currently displayed
29612 * @return {Boolean} True if the message box is visible, else false
29614 isVisible : function(){
29615 return dlg && dlg.isVisible();
29619 * Hides the message box if it is displayed
29622 if(this.isVisible()){
29628 * Displays a new message box, or reinitializes an existing message box, based on the config options
29629 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29630 * The following config object properties are supported:
29632 Property Type Description
29633 ---------- --------------- ------------------------------------------------------------------------------------
29634 animEl String/Element An id or Element from which the message box should animate as it opens and
29635 closes (defaults to undefined)
29636 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29637 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29638 closable Boolean False to hide the top-right close button (defaults to true). Note that
29639 progress and wait dialogs will ignore this property and always hide the
29640 close button as they can only be closed programmatically.
29641 cls String A custom CSS class to apply to the message box element
29642 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29643 displayed (defaults to 75)
29644 fn Function A callback function to execute after closing the dialog. The arguments to the
29645 function will be btn (the name of the button that was clicked, if applicable,
29646 e.g. "ok"), and text (the value of the active text field, if applicable).
29647 Progress and wait dialogs will ignore this option since they do not respond to
29648 user actions and can only be closed programmatically, so any required function
29649 should be called by the same code after it closes the dialog.
29650 icon String A CSS class that provides a background image to be used as an icon for
29651 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29652 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29653 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29654 modal Boolean False to allow user interaction with the page while the message box is
29655 displayed (defaults to true)
29656 msg String A string that will replace the existing message box body text (defaults
29657 to the XHTML-compliant non-breaking space character ' ')
29658 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
29659 progress Boolean True to display a progress bar (defaults to false)
29660 progressText String The text to display inside the progress bar if progress = true (defaults to '')
29661 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
29662 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
29663 title String The title text
29664 value String The string value to set into the active textbox element if displayed
29665 wait Boolean True to display a progress bar (defaults to false)
29666 width Number The width of the dialog in pixels
29673 msg: 'Please enter your address:',
29675 buttons: Roo.MessageBox.OKCANCEL,
29678 animEl: 'addAddressBtn'
29681 * @param {Object} config Configuration options
29682 * @return {Roo.MessageBox} This message box
29684 show : function(options){
29685 if(this.isVisible()){
29688 var d = this.getDialog();
29690 d.setTitle(opt.title || " ");
29691 d.close.setDisplayed(opt.closable !== false);
29692 activeTextEl = textboxEl;
29693 opt.prompt = opt.prompt || (opt.multiline ? true : false);
29698 textareaEl.setHeight(typeof opt.multiline == "number" ?
29699 opt.multiline : this.defaultTextHeight);
29700 activeTextEl = textareaEl;
29709 progressEl.setDisplayed(opt.progress === true);
29710 this.updateProgress(0);
29711 activeTextEl.dom.value = opt.value || "";
29713 dlg.setDefaultButton(activeTextEl);
29715 var bs = opt.buttons;
29718 db = buttons["ok"];
29719 }else if(bs && bs.yes){
29720 db = buttons["yes"];
29722 dlg.setDefaultButton(db);
29724 bwidth = updateButtons(opt.buttons);
29725 this.updateText(opt.msg);
29727 d.el.addClass(opt.cls);
29729 d.proxyDrag = opt.proxyDrag === true;
29730 d.modal = opt.modal !== false;
29731 d.mask = opt.modal !== false ? mask : false;
29732 if(!d.isVisible()){
29733 // force it to the end of the z-index stack so it gets a cursor in FF
29734 document.body.appendChild(dlg.el.dom);
29735 d.animateTarget = null;
29736 d.show(options.animEl);
29742 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
29743 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
29744 * and closing the message box when the process is complete.
29745 * @param {String} title The title bar text
29746 * @param {String} msg The message box body text
29747 * @return {Roo.MessageBox} This message box
29749 progress : function(title, msg){
29756 minWidth: this.minProgressWidth,
29763 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
29764 * If a callback function is passed it will be called after the user clicks the button, and the
29765 * id of the button that was clicked will be passed as the only parameter to the callback
29766 * (could also be the top-right close button).
29767 * @param {String} title The title bar text
29768 * @param {String} msg The message box body text
29769 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29770 * @param {Object} scope (optional) The scope of the callback function
29771 * @return {Roo.MessageBox} This message box
29773 alert : function(title, msg, fn, scope){
29786 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
29787 * interaction while waiting for a long-running process to complete that does not have defined intervals.
29788 * You are responsible for closing the message box when the process is complete.
29789 * @param {String} msg The message box body text
29790 * @param {String} title (optional) The title bar text
29791 * @return {Roo.MessageBox} This message box
29793 wait : function(msg, title){
29804 waitTimer = Roo.TaskMgr.start({
29806 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
29814 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
29815 * If a callback function is passed it will be called after the user clicks either button, and the id of the
29816 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
29817 * @param {String} title The title bar text
29818 * @param {String} msg The message box body text
29819 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29820 * @param {Object} scope (optional) The scope of the callback function
29821 * @return {Roo.MessageBox} This message box
29823 confirm : function(title, msg, fn, scope){
29827 buttons: this.YESNO,
29836 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
29837 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
29838 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
29839 * (could also be the top-right close button) and the text that was entered will be passed as the two
29840 * parameters to the callback.
29841 * @param {String} title The title bar text
29842 * @param {String} msg The message box body text
29843 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29844 * @param {Object} scope (optional) The scope of the callback function
29845 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
29846 * property, or the height in pixels to create the textbox (defaults to false / single-line)
29847 * @return {Roo.MessageBox} This message box
29849 prompt : function(title, msg, fn, scope, multiline){
29853 buttons: this.OKCANCEL,
29858 multiline: multiline,
29865 * Button config that displays a single OK button
29870 * Button config that displays Yes and No buttons
29873 YESNO : {yes:true, no:true},
29875 * Button config that displays OK and Cancel buttons
29878 OKCANCEL : {ok:true, cancel:true},
29880 * Button config that displays Yes, No and Cancel buttons
29883 YESNOCANCEL : {yes:true, no:true, cancel:true},
29886 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
29889 defaultTextHeight : 75,
29891 * The maximum width in pixels of the message box (defaults to 600)
29896 * The minimum width in pixels of the message box (defaults to 100)
29901 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
29902 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
29905 minProgressWidth : 250,
29907 * An object containing the default button text strings that can be overriden for localized language support.
29908 * Supported properties are: ok, cancel, yes and no.
29909 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
29922 * Shorthand for {@link Roo.MessageBox}
29924 Roo.Msg = Roo.MessageBox;/*
29926 * Ext JS Library 1.1.1
29927 * Copyright(c) 2006-2007, Ext JS, LLC.
29929 * Originally Released Under LGPL - original licence link has changed is not relivant.
29932 * <script type="text/javascript">
29935 * @class Roo.QuickTips
29936 * Provides attractive and customizable tooltips for any element.
29939 Roo.QuickTips = function(){
29940 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
29941 var ce, bd, xy, dd;
29942 var visible = false, disabled = true, inited = false;
29943 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
29945 var onOver = function(e){
29949 var t = e.getTarget();
29950 if(!t || t.nodeType !== 1 || t == document || t == document.body){
29953 if(ce && t == ce.el){
29954 clearTimeout(hideProc);
29957 if(t && tagEls[t.id]){
29958 tagEls[t.id].el = t;
29959 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
29962 var ttp, et = Roo.fly(t);
29963 var ns = cfg.namespace;
29964 if(tm.interceptTitles && t.title){
29967 t.removeAttribute("title");
29968 e.preventDefault();
29970 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
29973 showProc = show.defer(tm.showDelay, tm, [{
29976 width: et.getAttributeNS(ns, cfg.width),
29977 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
29978 title: et.getAttributeNS(ns, cfg.title),
29979 cls: et.getAttributeNS(ns, cfg.cls)
29984 var onOut = function(e){
29985 clearTimeout(showProc);
29986 var t = e.getTarget();
29987 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
29988 hideProc = setTimeout(hide, tm.hideDelay);
29992 var onMove = function(e){
29998 if(tm.trackMouse && ce){
30003 var onDown = function(e){
30004 clearTimeout(showProc);
30005 clearTimeout(hideProc);
30007 if(tm.hideOnClick){
30010 tm.enable.defer(100, tm);
30015 var getPad = function(){
30016 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30019 var show = function(o){
30023 clearTimeout(dismissProc);
30025 if(removeCls){ // in case manually hidden
30026 el.removeClass(removeCls);
30030 el.addClass(ce.cls);
30031 removeCls = ce.cls;
30034 tipTitle.update(ce.title);
30037 tipTitle.update('');
30040 el.dom.style.width = tm.maxWidth+'px';
30041 //tipBody.dom.style.width = '';
30042 tipBodyText.update(o.text);
30043 var p = getPad(), w = ce.width;
30045 var td = tipBodyText.dom;
30046 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30047 if(aw > tm.maxWidth){
30049 }else if(aw < tm.minWidth){
30055 //tipBody.setWidth(w);
30056 el.setWidth(parseInt(w, 10) + p);
30057 if(ce.autoHide === false){
30058 close.setDisplayed(true);
30063 close.setDisplayed(false);
30069 el.avoidY = xy[1]-18;
30074 el.setStyle("visibility", "visible");
30075 el.fadeIn({callback: afterShow});
30081 var afterShow = function(){
30085 if(tm.autoDismiss && ce.autoHide !== false){
30086 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30091 var hide = function(noanim){
30092 clearTimeout(dismissProc);
30093 clearTimeout(hideProc);
30095 if(el.isVisible()){
30097 if(noanim !== true && tm.animate){
30098 el.fadeOut({callback: afterHide});
30105 var afterHide = function(){
30108 el.removeClass(removeCls);
30115 * @cfg {Number} minWidth
30116 * The minimum width of the quick tip (defaults to 40)
30120 * @cfg {Number} maxWidth
30121 * The maximum width of the quick tip (defaults to 300)
30125 * @cfg {Boolean} interceptTitles
30126 * True to automatically use the element's DOM title value if available (defaults to false)
30128 interceptTitles : false,
30130 * @cfg {Boolean} trackMouse
30131 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30133 trackMouse : false,
30135 * @cfg {Boolean} hideOnClick
30136 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30138 hideOnClick : true,
30140 * @cfg {Number} showDelay
30141 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30145 * @cfg {Number} hideDelay
30146 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30150 * @cfg {Boolean} autoHide
30151 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30152 * Used in conjunction with hideDelay.
30157 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30158 * (defaults to true). Used in conjunction with autoDismissDelay.
30160 autoDismiss : true,
30163 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30165 autoDismissDelay : 5000,
30167 * @cfg {Boolean} animate
30168 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30173 * @cfg {String} title
30174 * Title text to display (defaults to ''). This can be any valid HTML markup.
30178 * @cfg {String} text
30179 * Body text to display (defaults to ''). This can be any valid HTML markup.
30183 * @cfg {String} cls
30184 * A CSS class to apply to the base quick tip element (defaults to '').
30188 * @cfg {Number} width
30189 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30190 * minWidth or maxWidth.
30195 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30196 * or display QuickTips in a page.
30199 tm = Roo.QuickTips;
30200 cfg = tm.tagConfig;
30202 if(!Roo.isReady){ // allow calling of init() before onReady
30203 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30206 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30207 el.fxDefaults = {stopFx: true};
30208 // maximum custom styling
30209 //el.update('<div class="x-tip-top-left"><div class="x-tip-top-right"><div class="x-tip-top"></div></div></div><div class="x-tip-bd-left"><div class="x-tip-bd-right"><div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div></div></div><div class="x-tip-ft-left"><div class="x-tip-ft-right"><div class="x-tip-ft"></div></div></div>');
30210 el.update('<div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div>');
30211 tipTitle = el.child('h3');
30212 tipTitle.enableDisplayMode("block");
30213 tipBody = el.child('div.x-tip-bd');
30214 tipBodyText = el.child('div.x-tip-bd-inner');
30215 //bdLeft = el.child('div.x-tip-bd-left');
30216 //bdRight = el.child('div.x-tip-bd-right');
30217 close = el.child('div.x-tip-close');
30218 close.enableDisplayMode("block");
30219 close.on("click", hide);
30220 var d = Roo.get(document);
30221 d.on("mousedown", onDown);
30222 d.on("mouseover", onOver);
30223 d.on("mouseout", onOut);
30224 d.on("mousemove", onMove);
30225 esc = d.addKeyListener(27, hide);
30228 dd = el.initDD("default", null, {
30229 onDrag : function(){
30233 dd.setHandleElId(tipTitle.id);
30242 * Configures a new quick tip instance and assigns it to a target element. The following config options
30245 Property Type Description
30246 ---------- --------------------- ------------------------------------------------------------------------
30247 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30249 * @param {Object} config The config object
30251 register : function(config){
30252 var cs = config instanceof Array ? config : arguments;
30253 for(var i = 0, len = cs.length; i < len; i++) {
30255 var target = c.target;
30257 if(target instanceof Array){
30258 for(var j = 0, jlen = target.length; j < jlen; j++){
30259 tagEls[target[j]] = c;
30262 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30269 * Removes this quick tip from its element and destroys it.
30270 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30272 unregister : function(el){
30273 delete tagEls[Roo.id(el)];
30277 * Enable this quick tip.
30279 enable : function(){
30280 if(inited && disabled){
30282 if(locks.length < 1){
30289 * Disable this quick tip.
30291 disable : function(){
30293 clearTimeout(showProc);
30294 clearTimeout(hideProc);
30295 clearTimeout(dismissProc);
30303 * Returns true if the quick tip is enabled, else false.
30305 isEnabled : function(){
30312 attribute : "qtip",
30322 // backwards compat
30323 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30325 * Ext JS Library 1.1.1
30326 * Copyright(c) 2006-2007, Ext JS, LLC.
30328 * Originally Released Under LGPL - original licence link has changed is not relivant.
30331 * <script type="text/javascript">
30336 * @class Roo.tree.TreePanel
30337 * @extends Roo.data.Tree
30339 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30340 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30341 * @cfg {Boolean} enableDD true to enable drag and drop
30342 * @cfg {Boolean} enableDrag true to enable just drag
30343 * @cfg {Boolean} enableDrop true to enable just drop
30344 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30345 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30346 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30347 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30348 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30349 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30350 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30351 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30352 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30353 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30354 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30355 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30356 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30357 * @cfg {Function} renderer Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
30358 * @cfg {Function} rendererTip Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
30361 * @param {String/HTMLElement/Element} el The container element
30362 * @param {Object} config
30364 Roo.tree.TreePanel = function(el, config){
30366 var loader = false;
30368 root = config.root;
30369 delete config.root;
30371 if (config.loader) {
30372 loader = config.loader;
30373 delete config.loader;
30376 Roo.apply(this, config);
30377 Roo.tree.TreePanel.superclass.constructor.call(this);
30378 this.el = Roo.get(el);
30379 this.el.addClass('x-tree');
30380 //console.log(root);
30382 this.setRootNode( Roo.factory(root, Roo.tree));
30385 this.loader = Roo.factory(loader, Roo.tree);
30388 * Read-only. The id of the container element becomes this TreePanel's id.
30390 this.id = this.el.id;
30393 * @event beforeload
30394 * Fires before a node is loaded, return false to cancel
30395 * @param {Node} node The node being loaded
30397 "beforeload" : true,
30400 * Fires when a node is loaded
30401 * @param {Node} node The node that was loaded
30405 * @event textchange
30406 * Fires when the text for a node is changed
30407 * @param {Node} node The node
30408 * @param {String} text The new text
30409 * @param {String} oldText The old text
30411 "textchange" : true,
30413 * @event beforeexpand
30414 * Fires before a node is expanded, return false to cancel.
30415 * @param {Node} node The node
30416 * @param {Boolean} deep
30417 * @param {Boolean} anim
30419 "beforeexpand" : true,
30421 * @event beforecollapse
30422 * Fires before a node is collapsed, return false to cancel.
30423 * @param {Node} node The node
30424 * @param {Boolean} deep
30425 * @param {Boolean} anim
30427 "beforecollapse" : true,
30430 * Fires when a node is expanded
30431 * @param {Node} node The node
30435 * @event disabledchange
30436 * Fires when the disabled status of a node changes
30437 * @param {Node} node The node
30438 * @param {Boolean} disabled
30440 "disabledchange" : true,
30443 * Fires when a node is collapsed
30444 * @param {Node} node The node
30448 * @event beforeclick
30449 * Fires before click processing on a node. Return false to cancel the default action.
30450 * @param {Node} node The node
30451 * @param {Roo.EventObject} e The event object
30453 "beforeclick":true,
30455 * @event checkchange
30456 * Fires when a node with a checkbox's checked property changes
30457 * @param {Node} this This node
30458 * @param {Boolean} checked
30460 "checkchange":true,
30463 * Fires when a node is clicked
30464 * @param {Node} node The node
30465 * @param {Roo.EventObject} e The event object
30470 * Fires when a node is double clicked
30471 * @param {Node} node The node
30472 * @param {Roo.EventObject} e The event object
30476 * @event contextmenu
30477 * Fires when a node is right clicked
30478 * @param {Node} node The node
30479 * @param {Roo.EventObject} e The event object
30481 "contextmenu":true,
30483 * @event beforechildrenrendered
30484 * Fires right before the child nodes for a node are rendered
30485 * @param {Node} node The node
30487 "beforechildrenrendered":true,
30490 * Fires when a node starts being dragged
30491 * @param {Roo.tree.TreePanel} this
30492 * @param {Roo.tree.TreeNode} node
30493 * @param {event} e The raw browser event
30495 "startdrag" : true,
30498 * Fires when a drag operation is complete
30499 * @param {Roo.tree.TreePanel} this
30500 * @param {Roo.tree.TreeNode} node
30501 * @param {event} e The raw browser event
30506 * Fires when a dragged node is dropped on a valid DD target
30507 * @param {Roo.tree.TreePanel} this
30508 * @param {Roo.tree.TreeNode} node
30509 * @param {DD} dd The dd it was dropped on
30510 * @param {event} e The raw browser event
30514 * @event beforenodedrop
30515 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30516 * passed to handlers has the following properties:<br />
30517 * <ul style="padding:5px;padding-left:16px;">
30518 * <li>tree - The TreePanel</li>
30519 * <li>target - The node being targeted for the drop</li>
30520 * <li>data - The drag data from the drag source</li>
30521 * <li>point - The point of the drop - append, above or below</li>
30522 * <li>source - The drag source</li>
30523 * <li>rawEvent - Raw mouse event</li>
30524 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30525 * to be inserted by setting them on this object.</li>
30526 * <li>cancel - Set this to true to cancel the drop.</li>
30528 * @param {Object} dropEvent
30530 "beforenodedrop" : true,
30533 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30534 * passed to handlers has the following properties:<br />
30535 * <ul style="padding:5px;padding-left:16px;">
30536 * <li>tree - The TreePanel</li>
30537 * <li>target - The node being targeted for the drop</li>
30538 * <li>data - The drag data from the drag source</li>
30539 * <li>point - The point of the drop - append, above or below</li>
30540 * <li>source - The drag source</li>
30541 * <li>rawEvent - Raw mouse event</li>
30542 * <li>dropNode - Dropped node(s).</li>
30544 * @param {Object} dropEvent
30548 * @event nodedragover
30549 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30550 * passed to handlers has the following properties:<br />
30551 * <ul style="padding:5px;padding-left:16px;">
30552 * <li>tree - The TreePanel</li>
30553 * <li>target - The node being targeted for the drop</li>
30554 * <li>data - The drag data from the drag source</li>
30555 * <li>point - The point of the drop - append, above or below</li>
30556 * <li>source - The drag source</li>
30557 * <li>rawEvent - Raw mouse event</li>
30558 * <li>dropNode - Drop node(s) provided by the source.</li>
30559 * <li>cancel - Set this to true to signal drop not allowed.</li>
30561 * @param {Object} dragOverEvent
30563 "nodedragover" : true
30566 if(this.singleExpand){
30567 this.on("beforeexpand", this.restrictExpand, this);
30570 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30571 rootVisible : true,
30572 animate: Roo.enableFx,
30575 hlDrop : Roo.enableFx,
30579 rendererTip: false,
30581 restrictExpand : function(node){
30582 var p = node.parentNode;
30584 if(p.expandedChild && p.expandedChild.parentNode == p){
30585 p.expandedChild.collapse();
30587 p.expandedChild = node;
30591 // private override
30592 setRootNode : function(node){
30593 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30594 if(!this.rootVisible){
30595 node.ui = new Roo.tree.RootTreeNodeUI(node);
30601 * Returns the container element for this TreePanel
30603 getEl : function(){
30608 * Returns the default TreeLoader for this TreePanel
30610 getLoader : function(){
30611 return this.loader;
30617 expandAll : function(){
30618 this.root.expand(true);
30622 * Collapse all nodes
30624 collapseAll : function(){
30625 this.root.collapse(true);
30629 * Returns the selection model used by this TreePanel
30631 getSelectionModel : function(){
30632 if(!this.selModel){
30633 this.selModel = new Roo.tree.DefaultSelectionModel();
30635 return this.selModel;
30639 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30640 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30641 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30644 getChecked : function(a, startNode){
30645 startNode = startNode || this.root;
30647 var f = function(){
30648 if(this.attributes.checked){
30649 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30652 startNode.cascade(f);
30657 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30658 * @param {String} path
30659 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30660 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
30661 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
30663 expandPath : function(path, attr, callback){
30664 attr = attr || "id";
30665 var keys = path.split(this.pathSeparator);
30666 var curNode = this.root;
30667 if(curNode.attributes[attr] != keys[1]){ // invalid root
30669 callback(false, null);
30674 var f = function(){
30675 if(++index == keys.length){
30677 callback(true, curNode);
30681 var c = curNode.findChild(attr, keys[index]);
30684 callback(false, curNode);
30689 c.expand(false, false, f);
30691 curNode.expand(false, false, f);
30695 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30696 * @param {String} path
30697 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30698 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
30699 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
30701 selectPath : function(path, attr, callback){
30702 attr = attr || "id";
30703 var keys = path.split(this.pathSeparator);
30704 var v = keys.pop();
30705 if(keys.length > 0){
30706 var f = function(success, node){
30707 if(success && node){
30708 var n = node.findChild(attr, v);
30714 }else if(callback){
30715 callback(false, n);
30719 callback(false, n);
30723 this.expandPath(keys.join(this.pathSeparator), attr, f);
30725 this.root.select();
30727 callback(true, this.root);
30732 getTreeEl : function(){
30737 * Trigger rendering of this TreePanel
30739 render : function(){
30740 if (this.innerCt) {
30741 return this; // stop it rendering more than once!!
30744 this.innerCt = this.el.createChild({tag:"ul",
30745 cls:"x-tree-root-ct " +
30746 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
30748 if(this.containerScroll){
30749 Roo.dd.ScrollManager.register(this.el);
30751 if((this.enableDD || this.enableDrop) && !this.dropZone){
30753 * The dropZone used by this tree if drop is enabled
30754 * @type Roo.tree.TreeDropZone
30756 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
30757 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
30760 if((this.enableDD || this.enableDrag) && !this.dragZone){
30762 * The dragZone used by this tree if drag is enabled
30763 * @type Roo.tree.TreeDragZone
30765 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
30766 ddGroup: this.ddGroup || "TreeDD",
30767 scroll: this.ddScroll
30770 this.getSelectionModel().init(this);
30772 console.log("ROOT not set in tree");
30775 this.root.render();
30776 if(!this.rootVisible){
30777 this.root.renderChildren();
30783 * Ext JS Library 1.1.1
30784 * Copyright(c) 2006-2007, Ext JS, LLC.
30786 * Originally Released Under LGPL - original licence link has changed is not relivant.
30789 * <script type="text/javascript">
30794 * @class Roo.tree.DefaultSelectionModel
30795 * @extends Roo.util.Observable
30796 * The default single selection for a TreePanel.
30798 Roo.tree.DefaultSelectionModel = function(){
30799 this.selNode = null;
30803 * @event selectionchange
30804 * Fires when the selected node changes
30805 * @param {DefaultSelectionModel} this
30806 * @param {TreeNode} node the new selection
30808 "selectionchange" : true,
30811 * @event beforeselect
30812 * Fires before the selected node changes, return false to cancel the change
30813 * @param {DefaultSelectionModel} this
30814 * @param {TreeNode} node the new selection
30815 * @param {TreeNode} node the old selection
30817 "beforeselect" : true
30821 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
30822 init : function(tree){
30824 tree.getTreeEl().on("keydown", this.onKeyDown, this);
30825 tree.on("click", this.onNodeClick, this);
30828 onNodeClick : function(node, e){
30829 if (e.ctrlKey && this.selNode == node) {
30830 this.unselect(node);
30838 * @param {TreeNode} node The node to select
30839 * @return {TreeNode} The selected node
30841 select : function(node){
30842 var last = this.selNode;
30843 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
30845 last.ui.onSelectedChange(false);
30847 this.selNode = node;
30848 node.ui.onSelectedChange(true);
30849 this.fireEvent("selectionchange", this, node, last);
30856 * @param {TreeNode} node The node to unselect
30858 unselect : function(node){
30859 if(this.selNode == node){
30860 this.clearSelections();
30865 * Clear all selections
30867 clearSelections : function(){
30868 var n = this.selNode;
30870 n.ui.onSelectedChange(false);
30871 this.selNode = null;
30872 this.fireEvent("selectionchange", this, null);
30878 * Get the selected node
30879 * @return {TreeNode} The selected node
30881 getSelectedNode : function(){
30882 return this.selNode;
30886 * Returns true if the node is selected
30887 * @param {TreeNode} node The node to check
30888 * @return {Boolean}
30890 isSelected : function(node){
30891 return this.selNode == node;
30895 * Selects the node above the selected node in the tree, intelligently walking the nodes
30896 * @return TreeNode The new selection
30898 selectPrevious : function(){
30899 var s = this.selNode || this.lastSelNode;
30903 var ps = s.previousSibling;
30905 if(!ps.isExpanded() || ps.childNodes.length < 1){
30906 return this.select(ps);
30908 var lc = ps.lastChild;
30909 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
30912 return this.select(lc);
30914 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
30915 return this.select(s.parentNode);
30921 * Selects the node above the selected node in the tree, intelligently walking the nodes
30922 * @return TreeNode The new selection
30924 selectNext : function(){
30925 var s = this.selNode || this.lastSelNode;
30929 if(s.firstChild && s.isExpanded()){
30930 return this.select(s.firstChild);
30931 }else if(s.nextSibling){
30932 return this.select(s.nextSibling);
30933 }else if(s.parentNode){
30935 s.parentNode.bubble(function(){
30936 if(this.nextSibling){
30937 newS = this.getOwnerTree().selModel.select(this.nextSibling);
30946 onKeyDown : function(e){
30947 var s = this.selNode || this.lastSelNode;
30948 // undesirable, but required
30953 var k = e.getKey();
30961 this.selectPrevious();
30964 e.preventDefault();
30965 if(s.hasChildNodes()){
30966 if(!s.isExpanded()){
30968 }else if(s.firstChild){
30969 this.select(s.firstChild, e);
30974 e.preventDefault();
30975 if(s.hasChildNodes() && s.isExpanded()){
30977 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
30978 this.select(s.parentNode, e);
30986 * @class Roo.tree.MultiSelectionModel
30987 * @extends Roo.util.Observable
30988 * Multi selection for a TreePanel.
30990 Roo.tree.MultiSelectionModel = function(){
30991 this.selNodes = [];
30995 * @event selectionchange
30996 * Fires when the selected nodes change
30997 * @param {MultiSelectionModel} this
30998 * @param {Array} nodes Array of the selected nodes
31000 "selectionchange" : true
31004 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31005 init : function(tree){
31007 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31008 tree.on("click", this.onNodeClick, this);
31011 onNodeClick : function(node, e){
31012 this.select(node, e, e.ctrlKey);
31017 * @param {TreeNode} node The node to select
31018 * @param {EventObject} e (optional) An event associated with the selection
31019 * @param {Boolean} keepExisting True to retain existing selections
31020 * @return {TreeNode} The selected node
31022 select : function(node, e, keepExisting){
31023 if(keepExisting !== true){
31024 this.clearSelections(true);
31026 if(this.isSelected(node)){
31027 this.lastSelNode = node;
31030 this.selNodes.push(node);
31031 this.selMap[node.id] = node;
31032 this.lastSelNode = node;
31033 node.ui.onSelectedChange(true);
31034 this.fireEvent("selectionchange", this, this.selNodes);
31040 * @param {TreeNode} node The node to unselect
31042 unselect : function(node){
31043 if(this.selMap[node.id]){
31044 node.ui.onSelectedChange(false);
31045 var sn = this.selNodes;
31048 index = sn.indexOf(node);
31050 for(var i = 0, len = sn.length; i < len; i++){
31058 this.selNodes.splice(index, 1);
31060 delete this.selMap[node.id];
31061 this.fireEvent("selectionchange", this, this.selNodes);
31066 * Clear all selections
31068 clearSelections : function(suppressEvent){
31069 var sn = this.selNodes;
31071 for(var i = 0, len = sn.length; i < len; i++){
31072 sn[i].ui.onSelectedChange(false);
31074 this.selNodes = [];
31076 if(suppressEvent !== true){
31077 this.fireEvent("selectionchange", this, this.selNodes);
31083 * Returns true if the node is selected
31084 * @param {TreeNode} node The node to check
31085 * @return {Boolean}
31087 isSelected : function(node){
31088 return this.selMap[node.id] ? true : false;
31092 * Returns an array of the selected nodes
31095 getSelectedNodes : function(){
31096 return this.selNodes;
31099 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31101 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31103 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31106 * Ext JS Library 1.1.1
31107 * Copyright(c) 2006-2007, Ext JS, LLC.
31109 * Originally Released Under LGPL - original licence link has changed is not relivant.
31112 * <script type="text/javascript">
31116 * @class Roo.tree.TreeNode
31117 * @extends Roo.data.Node
31118 * @cfg {String} text The text for this node
31119 * @cfg {Boolean} expanded true to start the node expanded
31120 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31121 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31122 * @cfg {Boolean} disabled true to start the node disabled
31123 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31124 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31125 * @cfg {String} cls A css class to be added to the node
31126 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31127 * @cfg {String} href URL of the link used for the node (defaults to #)
31128 * @cfg {String} hrefTarget target frame for the link
31129 * @cfg {String} qtip An Ext QuickTip for the node
31130 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31131 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31132 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31133 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31134 * (defaults to undefined with no checkbox rendered)
31136 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31138 Roo.tree.TreeNode = function(attributes){
31139 attributes = attributes || {};
31140 if(typeof attributes == "string"){
31141 attributes = {text: attributes};
31143 this.childrenRendered = false;
31144 this.rendered = false;
31145 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31146 this.expanded = attributes.expanded === true;
31147 this.isTarget = attributes.isTarget !== false;
31148 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31149 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31152 * Read-only. The text for this node. To change it use setText().
31155 this.text = attributes.text;
31157 * True if this node is disabled.
31160 this.disabled = attributes.disabled === true;
31164 * @event textchange
31165 * Fires when the text for this node is changed
31166 * @param {Node} this This node
31167 * @param {String} text The new text
31168 * @param {String} oldText The old text
31170 "textchange" : true,
31172 * @event beforeexpand
31173 * Fires before this node is expanded, return false to cancel.
31174 * @param {Node} this This node
31175 * @param {Boolean} deep
31176 * @param {Boolean} anim
31178 "beforeexpand" : true,
31180 * @event beforecollapse
31181 * Fires before this node is collapsed, return false to cancel.
31182 * @param {Node} this This node
31183 * @param {Boolean} deep
31184 * @param {Boolean} anim
31186 "beforecollapse" : true,
31189 * Fires when this node is expanded
31190 * @param {Node} this This node
31194 * @event disabledchange
31195 * Fires when the disabled status of this node changes
31196 * @param {Node} this This node
31197 * @param {Boolean} disabled
31199 "disabledchange" : true,
31202 * Fires when this node is collapsed
31203 * @param {Node} this This node
31207 * @event beforeclick
31208 * Fires before click processing. Return false to cancel the default action.
31209 * @param {Node} this This node
31210 * @param {Roo.EventObject} e The event object
31212 "beforeclick":true,
31214 * @event checkchange
31215 * Fires when a node with a checkbox's checked property changes
31216 * @param {Node} this This node
31217 * @param {Boolean} checked
31219 "checkchange":true,
31222 * Fires when this node is clicked
31223 * @param {Node} this This node
31224 * @param {Roo.EventObject} e The event object
31229 * Fires when this node is double clicked
31230 * @param {Node} this This node
31231 * @param {Roo.EventObject} e The event object
31235 * @event contextmenu
31236 * Fires when this node is right clicked
31237 * @param {Node} this This node
31238 * @param {Roo.EventObject} e The event object
31240 "contextmenu":true,
31242 * @event beforechildrenrendered
31243 * Fires right before the child nodes for this node are rendered
31244 * @param {Node} this This node
31246 "beforechildrenrendered":true
31249 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31252 * Read-only. The UI for this node
31255 this.ui = new uiClass(this);
31257 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31258 preventHScroll: true,
31260 * Returns true if this node is expanded
31261 * @return {Boolean}
31263 isExpanded : function(){
31264 return this.expanded;
31268 * Returns the UI object for this node
31269 * @return {TreeNodeUI}
31271 getUI : function(){
31275 // private override
31276 setFirstChild : function(node){
31277 var of = this.firstChild;
31278 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31279 if(this.childrenRendered && of && node != of){
31280 of.renderIndent(true, true);
31283 this.renderIndent(true, true);
31287 // private override
31288 setLastChild : function(node){
31289 var ol = this.lastChild;
31290 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31291 if(this.childrenRendered && ol && node != ol){
31292 ol.renderIndent(true, true);
31295 this.renderIndent(true, true);
31299 // these methods are overridden to provide lazy rendering support
31300 // private override
31301 appendChild : function(){
31302 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31303 if(node && this.childrenRendered){
31306 this.ui.updateExpandIcon();
31310 // private override
31311 removeChild : function(node){
31312 this.ownerTree.getSelectionModel().unselect(node);
31313 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31314 // if it's been rendered remove dom node
31315 if(this.childrenRendered){
31318 if(this.childNodes.length < 1){
31319 this.collapse(false, false);
31321 this.ui.updateExpandIcon();
31323 if(!this.firstChild) {
31324 this.childrenRendered = false;
31329 // private override
31330 insertBefore : function(node, refNode){
31331 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31332 if(newNode && refNode && this.childrenRendered){
31335 this.ui.updateExpandIcon();
31340 * Sets the text for this node
31341 * @param {String} text
31343 setText : function(text){
31344 var oldText = this.text;
31346 this.attributes.text = text;
31347 if(this.rendered){ // event without subscribing
31348 this.ui.onTextChange(this, text, oldText);
31350 this.fireEvent("textchange", this, text, oldText);
31354 * Triggers selection of this node
31356 select : function(){
31357 this.getOwnerTree().getSelectionModel().select(this);
31361 * Triggers deselection of this node
31363 unselect : function(){
31364 this.getOwnerTree().getSelectionModel().unselect(this);
31368 * Returns true if this node is selected
31369 * @return {Boolean}
31371 isSelected : function(){
31372 return this.getOwnerTree().getSelectionModel().isSelected(this);
31376 * Expand this node.
31377 * @param {Boolean} deep (optional) True to expand all children as well
31378 * @param {Boolean} anim (optional) false to cancel the default animation
31379 * @param {Function} callback (optional) A callback to be called when
31380 * expanding this node completes (does not wait for deep expand to complete).
31381 * Called with 1 parameter, this node.
31383 expand : function(deep, anim, callback){
31384 if(!this.expanded){
31385 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31388 if(!this.childrenRendered){
31389 this.renderChildren();
31391 this.expanded = true;
31392 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31393 this.ui.animExpand(function(){
31394 this.fireEvent("expand", this);
31395 if(typeof callback == "function"){
31399 this.expandChildNodes(true);
31401 }.createDelegate(this));
31405 this.fireEvent("expand", this);
31406 if(typeof callback == "function"){
31411 if(typeof callback == "function"){
31416 this.expandChildNodes(true);
31420 isHiddenRoot : function(){
31421 return this.isRoot && !this.getOwnerTree().rootVisible;
31425 * Collapse this node.
31426 * @param {Boolean} deep (optional) True to collapse all children as well
31427 * @param {Boolean} anim (optional) false to cancel the default animation
31429 collapse : function(deep, anim){
31430 if(this.expanded && !this.isHiddenRoot()){
31431 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31434 this.expanded = false;
31435 if((this.getOwnerTree().animate && anim !== false) || anim){
31436 this.ui.animCollapse(function(){
31437 this.fireEvent("collapse", this);
31439 this.collapseChildNodes(true);
31441 }.createDelegate(this));
31444 this.ui.collapse();
31445 this.fireEvent("collapse", this);
31449 var cs = this.childNodes;
31450 for(var i = 0, len = cs.length; i < len; i++) {
31451 cs[i].collapse(true, false);
31457 delayedExpand : function(delay){
31458 if(!this.expandProcId){
31459 this.expandProcId = this.expand.defer(delay, this);
31464 cancelExpand : function(){
31465 if(this.expandProcId){
31466 clearTimeout(this.expandProcId);
31468 this.expandProcId = false;
31472 * Toggles expanded/collapsed state of the node
31474 toggle : function(){
31483 * Ensures all parent nodes are expanded
31485 ensureVisible : function(callback){
31486 var tree = this.getOwnerTree();
31487 tree.expandPath(this.parentNode.getPath(), false, function(){
31488 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31489 Roo.callback(callback);
31490 }.createDelegate(this));
31494 * Expand all child nodes
31495 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31497 expandChildNodes : function(deep){
31498 var cs = this.childNodes;
31499 for(var i = 0, len = cs.length; i < len; i++) {
31500 cs[i].expand(deep);
31505 * Collapse all child nodes
31506 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31508 collapseChildNodes : function(deep){
31509 var cs = this.childNodes;
31510 for(var i = 0, len = cs.length; i < len; i++) {
31511 cs[i].collapse(deep);
31516 * Disables this node
31518 disable : function(){
31519 this.disabled = true;
31521 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31522 this.ui.onDisableChange(this, true);
31524 this.fireEvent("disabledchange", this, true);
31528 * Enables this node
31530 enable : function(){
31531 this.disabled = false;
31532 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31533 this.ui.onDisableChange(this, false);
31535 this.fireEvent("disabledchange", this, false);
31539 renderChildren : function(suppressEvent){
31540 if(suppressEvent !== false){
31541 this.fireEvent("beforechildrenrendered", this);
31543 var cs = this.childNodes;
31544 for(var i = 0, len = cs.length; i < len; i++){
31545 cs[i].render(true);
31547 this.childrenRendered = true;
31551 sort : function(fn, scope){
31552 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31553 if(this.childrenRendered){
31554 var cs = this.childNodes;
31555 for(var i = 0, len = cs.length; i < len; i++){
31556 cs[i].render(true);
31562 render : function(bulkRender){
31563 this.ui.render(bulkRender);
31564 if(!this.rendered){
31565 this.rendered = true;
31567 this.expanded = false;
31568 this.expand(false, false);
31574 renderIndent : function(deep, refresh){
31576 this.ui.childIndent = null;
31578 this.ui.renderIndent();
31579 if(deep === true && this.childrenRendered){
31580 var cs = this.childNodes;
31581 for(var i = 0, len = cs.length; i < len; i++){
31582 cs[i].renderIndent(true, refresh);
31588 * Ext JS Library 1.1.1
31589 * Copyright(c) 2006-2007, Ext JS, LLC.
31591 * Originally Released Under LGPL - original licence link has changed is not relivant.
31594 * <script type="text/javascript">
31598 * @class Roo.tree.AsyncTreeNode
31599 * @extends Roo.tree.TreeNode
31600 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31602 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31604 Roo.tree.AsyncTreeNode = function(config){
31605 this.loaded = false;
31606 this.loading = false;
31607 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31609 * @event beforeload
31610 * Fires before this node is loaded, return false to cancel
31611 * @param {Node} this This node
31613 this.addEvents({'beforeload':true, 'load': true});
31616 * Fires when this node is loaded
31617 * @param {Node} this This node
31620 * The loader used by this node (defaults to using the tree's defined loader)
31625 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31626 expand : function(deep, anim, callback){
31627 if(this.loading){ // if an async load is already running, waiting til it's done
31629 var f = function(){
31630 if(!this.loading){ // done loading
31631 clearInterval(timer);
31632 this.expand(deep, anim, callback);
31634 }.createDelegate(this);
31635 timer = setInterval(f, 200);
31639 if(this.fireEvent("beforeload", this) === false){
31642 this.loading = true;
31643 this.ui.beforeLoad(this);
31644 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31646 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31650 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31654 * Returns true if this node is currently loading
31655 * @return {Boolean}
31657 isLoading : function(){
31658 return this.loading;
31661 loadComplete : function(deep, anim, callback){
31662 this.loading = false;
31663 this.loaded = true;
31664 this.ui.afterLoad(this);
31665 this.fireEvent("load", this);
31666 this.expand(deep, anim, callback);
31670 * Returns true if this node has been loaded
31671 * @return {Boolean}
31673 isLoaded : function(){
31674 return this.loaded;
31677 hasChildNodes : function(){
31678 if(!this.isLeaf() && !this.loaded){
31681 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
31686 * Trigger a reload for this node
31687 * @param {Function} callback
31689 reload : function(callback){
31690 this.collapse(false, false);
31691 while(this.firstChild){
31692 this.removeChild(this.firstChild);
31694 this.childrenRendered = false;
31695 this.loaded = false;
31696 if(this.isHiddenRoot()){
31697 this.expanded = false;
31699 this.expand(false, false, callback);
31703 * Ext JS Library 1.1.1
31704 * Copyright(c) 2006-2007, Ext JS, LLC.
31706 * Originally Released Under LGPL - original licence link has changed is not relivant.
31709 * <script type="text/javascript">
31713 * @class Roo.tree.TreeNodeUI
31715 * @param {Object} node The node to render
31716 * The TreeNode UI implementation is separate from the
31717 * tree implementation. Unless you are customizing the tree UI,
31718 * you should never have to use this directly.
31720 Roo.tree.TreeNodeUI = function(node){
31722 this.rendered = false;
31723 this.animating = false;
31724 this.emptyIcon = Roo.BLANK_IMAGE_URL;
31727 Roo.tree.TreeNodeUI.prototype = {
31728 removeChild : function(node){
31730 this.ctNode.removeChild(node.ui.getEl());
31734 beforeLoad : function(){
31735 this.addClass("x-tree-node-loading");
31738 afterLoad : function(){
31739 this.removeClass("x-tree-node-loading");
31742 onTextChange : function(node, text, oldText){
31744 this.textNode.innerHTML = text;
31748 onDisableChange : function(node, state){
31749 this.disabled = state;
31751 this.addClass("x-tree-node-disabled");
31753 this.removeClass("x-tree-node-disabled");
31757 onSelectedChange : function(state){
31760 this.addClass("x-tree-selected");
31763 this.removeClass("x-tree-selected");
31767 onMove : function(tree, node, oldParent, newParent, index, refNode){
31768 this.childIndent = null;
31770 var targetNode = newParent.ui.getContainer();
31771 if(!targetNode){//target not rendered
31772 this.holder = document.createElement("div");
31773 this.holder.appendChild(this.wrap);
31776 var insertBefore = refNode ? refNode.ui.getEl() : null;
31778 targetNode.insertBefore(this.wrap, insertBefore);
31780 targetNode.appendChild(this.wrap);
31782 this.node.renderIndent(true);
31786 addClass : function(cls){
31788 Roo.fly(this.elNode).addClass(cls);
31792 removeClass : function(cls){
31794 Roo.fly(this.elNode).removeClass(cls);
31798 remove : function(){
31800 this.holder = document.createElement("div");
31801 this.holder.appendChild(this.wrap);
31805 fireEvent : function(){
31806 return this.node.fireEvent.apply(this.node, arguments);
31809 initEvents : function(){
31810 this.node.on("move", this.onMove, this);
31811 var E = Roo.EventManager;
31812 var a = this.anchor;
31814 var el = Roo.fly(a, '_treeui');
31816 if(Roo.isOpera){ // opera render bug ignores the CSS
31817 el.setStyle("text-decoration", "none");
31820 el.on("click", this.onClick, this);
31821 el.on("dblclick", this.onDblClick, this);
31824 Roo.EventManager.on(this.checkbox,
31825 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
31828 el.on("contextmenu", this.onContextMenu, this);
31830 var icon = Roo.fly(this.iconNode);
31831 icon.on("click", this.onClick, this);
31832 icon.on("dblclick", this.onDblClick, this);
31833 icon.on("contextmenu", this.onContextMenu, this);
31834 E.on(this.ecNode, "click", this.ecClick, this, true);
31836 if(this.node.disabled){
31837 this.addClass("x-tree-node-disabled");
31839 if(this.node.hidden){
31840 this.addClass("x-tree-node-disabled");
31842 var ot = this.node.getOwnerTree();
31843 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
31844 if(dd && (!this.node.isRoot || ot.rootVisible)){
31845 Roo.dd.Registry.register(this.elNode, {
31847 handles: this.getDDHandles(),
31853 getDDHandles : function(){
31854 return [this.iconNode, this.textNode];
31859 this.wrap.style.display = "none";
31865 this.wrap.style.display = "";
31869 onContextMenu : function(e){
31870 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
31871 e.preventDefault();
31873 this.fireEvent("contextmenu", this.node, e);
31877 onClick : function(e){
31882 if(this.fireEvent("beforeclick", this.node, e) !== false){
31883 if(!this.disabled && this.node.attributes.href){
31884 this.fireEvent("click", this.node, e);
31887 e.preventDefault();
31892 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
31893 this.node.toggle();
31896 this.fireEvent("click", this.node, e);
31902 onDblClick : function(e){
31903 e.preventDefault();
31908 this.toggleCheck();
31910 if(!this.animating && this.node.hasChildNodes()){
31911 this.node.toggle();
31913 this.fireEvent("dblclick", this.node, e);
31916 onCheckChange : function(){
31917 var checked = this.checkbox.checked;
31918 this.node.attributes.checked = checked;
31919 this.fireEvent('checkchange', this.node, checked);
31922 ecClick : function(e){
31923 if(!this.animating && this.node.hasChildNodes()){
31924 this.node.toggle();
31928 startDrop : function(){
31929 this.dropping = true;
31932 // delayed drop so the click event doesn't get fired on a drop
31933 endDrop : function(){
31934 setTimeout(function(){
31935 this.dropping = false;
31936 }.createDelegate(this), 50);
31939 expand : function(){
31940 this.updateExpandIcon();
31941 this.ctNode.style.display = "";
31944 focus : function(){
31945 if(!this.node.preventHScroll){
31946 try{this.anchor.focus();
31948 }else if(!Roo.isIE){
31950 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
31951 var l = noscroll.scrollLeft;
31952 this.anchor.focus();
31953 noscroll.scrollLeft = l;
31958 toggleCheck : function(value){
31959 var cb = this.checkbox;
31961 cb.checked = (value === undefined ? !cb.checked : value);
31967 this.anchor.blur();
31971 animExpand : function(callback){
31972 var ct = Roo.get(this.ctNode);
31974 if(!this.node.hasChildNodes()){
31975 this.updateExpandIcon();
31976 this.ctNode.style.display = "";
31977 Roo.callback(callback);
31980 this.animating = true;
31981 this.updateExpandIcon();
31984 callback : function(){
31985 this.animating = false;
31986 Roo.callback(callback);
31989 duration: this.node.ownerTree.duration || .25
31993 highlight : function(){
31994 var tree = this.node.getOwnerTree();
31995 Roo.fly(this.wrap).highlight(
31996 tree.hlColor || "C3DAF9",
31997 {endColor: tree.hlBaseColor}
32001 collapse : function(){
32002 this.updateExpandIcon();
32003 this.ctNode.style.display = "none";
32006 animCollapse : function(callback){
32007 var ct = Roo.get(this.ctNode);
32008 ct.enableDisplayMode('block');
32011 this.animating = true;
32012 this.updateExpandIcon();
32015 callback : function(){
32016 this.animating = false;
32017 Roo.callback(callback);
32020 duration: this.node.ownerTree.duration || .25
32024 getContainer : function(){
32025 return this.ctNode;
32028 getEl : function(){
32032 appendDDGhost : function(ghostNode){
32033 ghostNode.appendChild(this.elNode.cloneNode(true));
32036 getDDRepairXY : function(){
32037 return Roo.lib.Dom.getXY(this.iconNode);
32040 onRender : function(){
32044 render : function(bulkRender){
32045 var n = this.node, a = n.attributes;
32046 var targetNode = n.parentNode ?
32047 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32049 if(!this.rendered){
32050 this.rendered = true;
32052 this.renderElements(n, a, targetNode, bulkRender);
32055 if(this.textNode.setAttributeNS){
32056 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32058 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32061 this.textNode.setAttribute("ext:qtip", a.qtip);
32063 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32066 }else if(a.qtipCfg){
32067 a.qtipCfg.target = Roo.id(this.textNode);
32068 Roo.QuickTips.register(a.qtipCfg);
32071 if(!this.node.expanded){
32072 this.updateExpandIcon();
32075 if(bulkRender === true) {
32076 targetNode.appendChild(this.wrap);
32081 renderElements : function(n, a, targetNode, bulkRender){
32082 // add some indent caching, this helps performance when rendering a large tree
32083 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32084 var t = n.getOwnerTree();
32085 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32086 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32087 var cb = typeof a.checked == 'boolean';
32088 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32089 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32090 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32091 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32092 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32093 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32094 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32095 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32096 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32097 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32100 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32101 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32102 n.nextSibling.ui.getEl(), buf.join(""));
32104 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32107 this.elNode = this.wrap.childNodes[0];
32108 this.ctNode = this.wrap.childNodes[1];
32109 var cs = this.elNode.childNodes;
32110 this.indentNode = cs[0];
32111 this.ecNode = cs[1];
32112 this.iconNode = cs[2];
32115 this.checkbox = cs[3];
32118 this.anchor = cs[index];
32119 this.textNode = cs[index].firstChild;
32122 getAnchor : function(){
32123 return this.anchor;
32126 getTextEl : function(){
32127 return this.textNode;
32130 getIconEl : function(){
32131 return this.iconNode;
32134 isChecked : function(){
32135 return this.checkbox ? this.checkbox.checked : false;
32138 updateExpandIcon : function(){
32140 var n = this.node, c1, c2;
32141 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32142 var hasChild = n.hasChildNodes();
32146 c1 = "x-tree-node-collapsed";
32147 c2 = "x-tree-node-expanded";
32150 c1 = "x-tree-node-expanded";
32151 c2 = "x-tree-node-collapsed";
32154 this.removeClass("x-tree-node-leaf");
32155 this.wasLeaf = false;
32157 if(this.c1 != c1 || this.c2 != c2){
32158 Roo.fly(this.elNode).replaceClass(c1, c2);
32159 this.c1 = c1; this.c2 = c2;
32163 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32166 this.wasLeaf = true;
32169 var ecc = "x-tree-ec-icon "+cls;
32170 if(this.ecc != ecc){
32171 this.ecNode.className = ecc;
32177 getChildIndent : function(){
32178 if(!this.childIndent){
32182 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32184 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32186 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32191 this.childIndent = buf.join("");
32193 return this.childIndent;
32196 renderIndent : function(){
32199 var p = this.node.parentNode;
32201 indent = p.ui.getChildIndent();
32203 if(this.indentMarkup != indent){ // don't rerender if not required
32204 this.indentNode.innerHTML = indent;
32205 this.indentMarkup = indent;
32207 this.updateExpandIcon();
32212 Roo.tree.RootTreeNodeUI = function(){
32213 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32215 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32216 render : function(){
32217 if(!this.rendered){
32218 var targetNode = this.node.ownerTree.innerCt.dom;
32219 this.node.expanded = true;
32220 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32221 this.wrap = this.ctNode = targetNode.firstChild;
32224 collapse : function(){
32226 expand : function(){
32230 * Ext JS Library 1.1.1
32231 * Copyright(c) 2006-2007, Ext JS, LLC.
32233 * Originally Released Under LGPL - original licence link has changed is not relivant.
32236 * <script type="text/javascript">
32239 * @class Roo.tree.TreeLoader
32240 * @extends Roo.util.Observable
32241 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32242 * nodes from a specified URL. The response must be a javascript Array definition
32243 * who's elements are node definition objects. eg:
32245 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32246 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32249 * A server request is sent, and child nodes are loaded only when a node is expanded.
32250 * The loading node's id is passed to the server under the parameter name "node" to
32251 * enable the server to produce the correct child nodes.
32253 * To pass extra parameters, an event handler may be attached to the "beforeload"
32254 * event, and the parameters specified in the TreeLoader's baseParams property:
32256 myTreeLoader.on("beforeload", function(treeLoader, node) {
32257 this.baseParams.category = node.attributes.category;
32260 * This would pass an HTTP parameter called "category" to the server containing
32261 * the value of the Node's "category" attribute.
32263 * Creates a new Treeloader.
32264 * @param {Object} config A config object containing config properties.
32266 Roo.tree.TreeLoader = function(config){
32267 this.baseParams = {};
32268 this.requestMethod = "POST";
32269 Roo.apply(this, config);
32274 * @event beforeload
32275 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32276 * @param {Object} This TreeLoader object.
32277 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32278 * @param {Object} callback The callback function specified in the {@link #load} call.
32283 * Fires when the node has been successfuly loaded.
32284 * @param {Object} This TreeLoader object.
32285 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32286 * @param {Object} response The response object containing the data from the server.
32290 * @event loadexception
32291 * Fires if the network request failed.
32292 * @param {Object} This TreeLoader object.
32293 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32294 * @param {Object} response The response object containing the data from the server.
32296 loadexception : true,
32299 * Fires before a node is created, enabling you to return custom Node types
32300 * @param {Object} This TreeLoader object.
32301 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32306 Roo.tree.TreeLoader.superclass.constructor.call(this);
32309 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32311 * @cfg {String} dataUrl The URL from which to request a Json string which
32312 * specifies an array of node definition object representing the child nodes
32316 * @cfg {Object} baseParams (optional) An object containing properties which
32317 * specify HTTP parameters to be passed to each request for child nodes.
32320 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32321 * created by this loader. If the attributes sent by the server have an attribute in this object,
32322 * they take priority.
32325 * @cfg {Object} uiProviders (optional) An object containing properties which
32327 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32328 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32329 * <i>uiProvider</i> attribute of a returned child node is a string rather
32330 * than a reference to a TreeNodeUI implementation, this that string value
32331 * is used as a property name in the uiProviders object. You can define the provider named
32332 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32337 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32338 * child nodes before loading.
32340 clearOnLoad : true,
32343 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32344 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32345 * Grid query { data : [ .....] }
32350 * @cfg {String} queryParam (optional)
32351 * Name of the query as it will be passed on the querystring (defaults to 'node')
32352 * eg. the request will be ?node=[id]
32359 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32360 * This is called automatically when a node is expanded, but may be used to reload
32361 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32362 * @param {Roo.tree.TreeNode} node
32363 * @param {Function} callback
32365 load : function(node, callback){
32366 if(this.clearOnLoad){
32367 while(node.firstChild){
32368 node.removeChild(node.firstChild);
32371 if(node.attributes.children){ // preloaded json children
32372 var cs = node.attributes.children;
32373 for(var i = 0, len = cs.length; i < len; i++){
32374 node.appendChild(this.createNode(cs[i]));
32376 if(typeof callback == "function"){
32379 }else if(this.dataUrl){
32380 this.requestData(node, callback);
32384 getParams: function(node){
32385 var buf = [], bp = this.baseParams;
32386 for(var key in bp){
32387 if(typeof bp[key] != "function"){
32388 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32391 var n = this.queryParam === false ? 'node' : this.queryParam;
32392 buf.push(n + "=", encodeURIComponent(node.id));
32393 return buf.join("");
32396 requestData : function(node, callback){
32397 if(this.fireEvent("beforeload", this, node, callback) !== false){
32398 this.transId = Roo.Ajax.request({
32399 method:this.requestMethod,
32400 url: this.dataUrl||this.url,
32401 success: this.handleResponse,
32402 failure: this.handleFailure,
32404 argument: {callback: callback, node: node},
32405 params: this.getParams(node)
32408 // if the load is cancelled, make sure we notify
32409 // the node that we are done
32410 if(typeof callback == "function"){
32416 isLoading : function(){
32417 return this.transId ? true : false;
32420 abort : function(){
32421 if(this.isLoading()){
32422 Roo.Ajax.abort(this.transId);
32427 createNode : function(attr){
32428 // apply baseAttrs, nice idea Corey!
32429 if(this.baseAttrs){
32430 Roo.applyIf(attr, this.baseAttrs);
32432 if(this.applyLoader !== false){
32433 attr.loader = this;
32435 // uiProvider = depreciated..
32437 if(typeof(attr.uiProvider) == 'string'){
32438 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32439 /** eval:var:attr */ eval(attr.uiProvider);
32441 if(typeof(this.uiProviders['default']) != 'undefined') {
32442 attr.uiProvider = this.uiProviders['default'];
32445 this.fireEvent('create', this, attr);
32447 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32449 new Roo.tree.TreeNode(attr) :
32450 new Roo.tree.AsyncTreeNode(attr));
32453 processResponse : function(response, node, callback){
32454 var json = response.responseText;
32457 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32458 if (this.root !== false) {
32462 for(var i = 0, len = o.length; i < len; i++){
32463 var n = this.createNode(o[i]);
32465 node.appendChild(n);
32468 if(typeof callback == "function"){
32469 callback(this, node);
32472 this.handleFailure(response);
32476 handleResponse : function(response){
32477 this.transId = false;
32478 var a = response.argument;
32479 this.processResponse(response, a.node, a.callback);
32480 this.fireEvent("load", this, a.node, response);
32483 handleFailure : function(response){
32484 this.transId = false;
32485 var a = response.argument;
32486 this.fireEvent("loadexception", this, a.node, response);
32487 if(typeof a.callback == "function"){
32488 a.callback(this, a.node);
32493 * Ext JS Library 1.1.1
32494 * Copyright(c) 2006-2007, Ext JS, LLC.
32496 * Originally Released Under LGPL - original licence link has changed is not relivant.
32499 * <script type="text/javascript">
32503 * @class Roo.tree.TreeFilter
32504 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32505 * @param {TreePanel} tree
32506 * @param {Object} config (optional)
32508 Roo.tree.TreeFilter = function(tree, config){
32510 this.filtered = {};
32511 Roo.apply(this, config);
32514 Roo.tree.TreeFilter.prototype = {
32521 * Filter the data by a specific attribute.
32522 * @param {String/RegExp} value Either string that the attribute value
32523 * should start with or a RegExp to test against the attribute
32524 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32525 * @param {TreeNode} startNode (optional) The node to start the filter at.
32527 filter : function(value, attr, startNode){
32528 attr = attr || "text";
32530 if(typeof value == "string"){
32531 var vlen = value.length;
32532 // auto clear empty filter
32533 if(vlen == 0 && this.clearBlank){
32537 value = value.toLowerCase();
32539 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32541 }else if(value.exec){ // regex?
32543 return value.test(n.attributes[attr]);
32546 throw 'Illegal filter type, must be string or regex';
32548 this.filterBy(f, null, startNode);
32552 * Filter by a function. The passed function will be called with each
32553 * node in the tree (or from the startNode). If the function returns true, the node is kept
32554 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32555 * @param {Function} fn The filter function
32556 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32558 filterBy : function(fn, scope, startNode){
32559 startNode = startNode || this.tree.root;
32560 if(this.autoClear){
32563 var af = this.filtered, rv = this.reverse;
32564 var f = function(n){
32565 if(n == startNode){
32571 var m = fn.call(scope || n, n);
32579 startNode.cascade(f);
32582 if(typeof id != "function"){
32584 if(n && n.parentNode){
32585 n.parentNode.removeChild(n);
32593 * Clears the current filter. Note: with the "remove" option
32594 * set a filter cannot be cleared.
32596 clear : function(){
32598 var af = this.filtered;
32600 if(typeof id != "function"){
32607 this.filtered = {};
32612 * Ext JS Library 1.1.1
32613 * Copyright(c) 2006-2007, Ext JS, LLC.
32615 * Originally Released Under LGPL - original licence link has changed is not relivant.
32618 * <script type="text/javascript">
32623 * @class Roo.tree.TreeSorter
32624 * Provides sorting of nodes in a TreePanel
32626 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32627 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32628 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32629 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32630 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32631 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32633 * @param {TreePanel} tree
32634 * @param {Object} config
32636 Roo.tree.TreeSorter = function(tree, config){
32637 Roo.apply(this, config);
32638 tree.on("beforechildrenrendered", this.doSort, this);
32639 tree.on("append", this.updateSort, this);
32640 tree.on("insert", this.updateSort, this);
32642 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32643 var p = this.property || "text";
32644 var sortType = this.sortType;
32645 var fs = this.folderSort;
32646 var cs = this.caseSensitive === true;
32647 var leafAttr = this.leafAttr || 'leaf';
32649 this.sortFn = function(n1, n2){
32651 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32654 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
32658 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
32659 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
32661 return dsc ? +1 : -1;
32663 return dsc ? -1 : +1;
32670 Roo.tree.TreeSorter.prototype = {
32671 doSort : function(node){
32672 node.sort(this.sortFn);
32675 compareNodes : function(n1, n2){
32676 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
32679 updateSort : function(tree, node){
32680 if(node.childrenRendered){
32681 this.doSort.defer(1, this, [node]);
32686 * Ext JS Library 1.1.1
32687 * Copyright(c) 2006-2007, Ext JS, LLC.
32689 * Originally Released Under LGPL - original licence link has changed is not relivant.
32692 * <script type="text/javascript">
32695 if(Roo.dd.DropZone){
32697 Roo.tree.TreeDropZone = function(tree, config){
32698 this.allowParentInsert = false;
32699 this.allowContainerDrop = false;
32700 this.appendOnly = false;
32701 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
32703 this.lastInsertClass = "x-tree-no-status";
32704 this.dragOverData = {};
32707 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
32708 ddGroup : "TreeDD",
32710 expandDelay : 1000,
32712 expandNode : function(node){
32713 if(node.hasChildNodes() && !node.isExpanded()){
32714 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
32718 queueExpand : function(node){
32719 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
32722 cancelExpand : function(){
32723 if(this.expandProcId){
32724 clearTimeout(this.expandProcId);
32725 this.expandProcId = false;
32729 isValidDropPoint : function(n, pt, dd, e, data){
32730 if(!n || !data){ return false; }
32731 var targetNode = n.node;
32732 var dropNode = data.node;
32733 // default drop rules
32734 if(!(targetNode && targetNode.isTarget && pt)){
32737 if(pt == "append" && targetNode.allowChildren === false){
32740 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
32743 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
32746 // reuse the object
32747 var overEvent = this.dragOverData;
32748 overEvent.tree = this.tree;
32749 overEvent.target = targetNode;
32750 overEvent.data = data;
32751 overEvent.point = pt;
32752 overEvent.source = dd;
32753 overEvent.rawEvent = e;
32754 overEvent.dropNode = dropNode;
32755 overEvent.cancel = false;
32756 var result = this.tree.fireEvent("nodedragover", overEvent);
32757 return overEvent.cancel === false && result !== false;
32760 getDropPoint : function(e, n, dd){
32763 return tn.allowChildren !== false ? "append" : false; // always append for root
32765 var dragEl = n.ddel;
32766 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
32767 var y = Roo.lib.Event.getPageY(e);
32768 var noAppend = tn.allowChildren === false || tn.isLeaf();
32769 if(this.appendOnly || tn.parentNode.allowChildren === false){
32770 return noAppend ? false : "append";
32772 var noBelow = false;
32773 if(!this.allowParentInsert){
32774 noBelow = tn.hasChildNodes() && tn.isExpanded();
32776 var q = (b - t) / (noAppend ? 2 : 3);
32777 if(y >= t && y < (t + q)){
32779 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
32786 onNodeEnter : function(n, dd, e, data){
32787 this.cancelExpand();
32790 onNodeOver : function(n, dd, e, data){
32791 var pt = this.getDropPoint(e, n, dd);
32794 // auto node expand check
32795 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
32796 this.queueExpand(node);
32797 }else if(pt != "append"){
32798 this.cancelExpand();
32801 // set the insert point style on the target node
32802 var returnCls = this.dropNotAllowed;
32803 if(this.isValidDropPoint(n, pt, dd, e, data)){
32808 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
32809 cls = "x-tree-drag-insert-above";
32810 }else if(pt == "below"){
32811 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
32812 cls = "x-tree-drag-insert-below";
32814 returnCls = "x-tree-drop-ok-append";
32815 cls = "x-tree-drag-append";
32817 if(this.lastInsertClass != cls){
32818 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
32819 this.lastInsertClass = cls;
32826 onNodeOut : function(n, dd, e, data){
32827 this.cancelExpand();
32828 this.removeDropIndicators(n);
32831 onNodeDrop : function(n, dd, e, data){
32832 var point = this.getDropPoint(e, n, dd);
32833 var targetNode = n.node;
32834 targetNode.ui.startDrop();
32835 if(!this.isValidDropPoint(n, point, dd, e, data)){
32836 targetNode.ui.endDrop();
32839 // first try to find the drop node
32840 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
32843 target: targetNode,
32848 dropNode: dropNode,
32851 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
32852 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
32853 targetNode.ui.endDrop();
32856 // allow target changing
32857 targetNode = dropEvent.target;
32858 if(point == "append" && !targetNode.isExpanded()){
32859 targetNode.expand(false, null, function(){
32860 this.completeDrop(dropEvent);
32861 }.createDelegate(this));
32863 this.completeDrop(dropEvent);
32868 completeDrop : function(de){
32869 var ns = de.dropNode, p = de.point, t = de.target;
32870 if(!(ns instanceof Array)){
32874 for(var i = 0, len = ns.length; i < len; i++){
32877 t.parentNode.insertBefore(n, t);
32878 }else if(p == "below"){
32879 t.parentNode.insertBefore(n, t.nextSibling);
32885 if(this.tree.hlDrop){
32889 this.tree.fireEvent("nodedrop", de);
32892 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
32893 if(this.tree.hlDrop){
32894 dropNode.ui.focus();
32895 dropNode.ui.highlight();
32897 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
32900 getTree : function(){
32904 removeDropIndicators : function(n){
32907 Roo.fly(el).removeClass([
32908 "x-tree-drag-insert-above",
32909 "x-tree-drag-insert-below",
32910 "x-tree-drag-append"]);
32911 this.lastInsertClass = "_noclass";
32915 beforeDragDrop : function(target, e, id){
32916 this.cancelExpand();
32920 afterRepair : function(data){
32921 if(data && Roo.enableFx){
32922 data.node.ui.highlight();
32930 * Ext JS Library 1.1.1
32931 * Copyright(c) 2006-2007, Ext JS, LLC.
32933 * Originally Released Under LGPL - original licence link has changed is not relivant.
32936 * <script type="text/javascript">
32940 if(Roo.dd.DragZone){
32941 Roo.tree.TreeDragZone = function(tree, config){
32942 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
32946 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
32947 ddGroup : "TreeDD",
32949 onBeforeDrag : function(data, e){
32951 return n && n.draggable && !n.disabled;
32954 onInitDrag : function(e){
32955 var data = this.dragData;
32956 this.tree.getSelectionModel().select(data.node);
32957 this.proxy.update("");
32958 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
32959 this.tree.fireEvent("startdrag", this.tree, data.node, e);
32962 getRepairXY : function(e, data){
32963 return data.node.ui.getDDRepairXY();
32966 onEndDrag : function(data, e){
32967 this.tree.fireEvent("enddrag", this.tree, data.node, e);
32970 onValidDrop : function(dd, e, id){
32971 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
32975 beforeInvalidDrop : function(e, id){
32976 // this scrolls the original position back into view
32977 var sm = this.tree.getSelectionModel();
32978 sm.clearSelections();
32979 sm.select(this.dragData.node);
32984 * Ext JS Library 1.1.1
32985 * Copyright(c) 2006-2007, Ext JS, LLC.
32987 * Originally Released Under LGPL - original licence link has changed is not relivant.
32990 * <script type="text/javascript">
32993 * @class Roo.tree.TreeEditor
32994 * @extends Roo.Editor
32995 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
32996 * as the editor field.
32998 * @param {TreePanel} tree
32999 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33001 Roo.tree.TreeEditor = function(tree, config){
33002 config = config || {};
33003 var field = config.events ? config : new Roo.form.TextField(config);
33004 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33008 tree.on('beforeclick', this.beforeNodeClick, this);
33009 tree.getTreeEl().on('mousedown', this.hide, this);
33010 this.on('complete', this.updateNode, this);
33011 this.on('beforestartedit', this.fitToTree, this);
33012 this.on('startedit', this.bindScroll, this, {delay:10});
33013 this.on('specialkey', this.onSpecialKey, this);
33016 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33018 * @cfg {String} alignment
33019 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33025 * @cfg {Boolean} hideEl
33026 * True to hide the bound element while the editor is displayed (defaults to false)
33030 * @cfg {String} cls
33031 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33033 cls: "x-small-editor x-tree-editor",
33035 * @cfg {Boolean} shim
33036 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33042 * @cfg {Number} maxWidth
33043 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33044 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33045 * scroll and client offsets into account prior to each edit.
33052 fitToTree : function(ed, el){
33053 var td = this.tree.getTreeEl().dom, nd = el.dom;
33054 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33055 td.scrollLeft = nd.offsetLeft;
33059 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33060 this.setSize(w, '');
33064 triggerEdit : function(node){
33065 this.completeEdit();
33066 this.editNode = node;
33067 this.startEdit(node.ui.textNode, node.text);
33071 bindScroll : function(){
33072 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33076 beforeNodeClick : function(node, e){
33077 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33078 this.lastClick = new Date();
33079 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33081 this.triggerEdit(node);
33087 updateNode : function(ed, value){
33088 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33089 this.editNode.setText(value);
33093 onHide : function(){
33094 Roo.tree.TreeEditor.superclass.onHide.call(this);
33096 this.editNode.ui.focus();
33101 onSpecialKey : function(field, e){
33102 var k = e.getKey();
33106 }else if(k == e.ENTER && !e.hasModifier()){
33108 this.completeEdit();
33111 });//<Script type="text/javascript">
33114 * Ext JS Library 1.1.1
33115 * Copyright(c) 2006-2007, Ext JS, LLC.
33117 * Originally Released Under LGPL - original licence link has changed is not relivant.
33120 * <script type="text/javascript">
33124 * Not documented??? - probably should be...
33127 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33128 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33130 renderElements : function(n, a, targetNode, bulkRender){
33131 //consel.log("renderElements?");
33132 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33134 var t = n.getOwnerTree();
33135 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33137 var cols = t.columns;
33138 var bw = t.borderWidth;
33140 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33141 var cb = typeof a.checked == "boolean";
33142 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33143 var colcls = 'x-t-' + tid + '-c0';
33145 '<li class="x-tree-node">',
33148 '<div class="x-tree-node-el ', a.cls,'">',
33150 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33153 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33154 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33155 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33156 (a.icon ? ' x-tree-node-inline-icon' : ''),
33157 (a.iconCls ? ' '+a.iconCls : ''),
33158 '" unselectable="on" />',
33159 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33160 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33162 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33163 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33164 '<span unselectable="on" qtip="' + tx + '">',
33168 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33169 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33172 for(var i = 1, len = cols.length; i < len; i++){
33174 colcls = 'x-t-' + tid + '-c' +i;
33175 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33176 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33177 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33183 '<div class="x-clear"></div></div>',
33184 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33187 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33188 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33189 n.nextSibling.ui.getEl(), buf.join(""));
33191 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33193 var el = this.wrap.firstChild;
33195 this.elNode = el.firstChild;
33196 this.ranchor = el.childNodes[1];
33197 this.ctNode = this.wrap.childNodes[1];
33198 var cs = el.firstChild.childNodes;
33199 this.indentNode = cs[0];
33200 this.ecNode = cs[1];
33201 this.iconNode = cs[2];
33204 this.checkbox = cs[3];
33207 this.anchor = cs[index];
33209 this.textNode = cs[index].firstChild;
33211 //el.on("click", this.onClick, this);
33212 //el.on("dblclick", this.onDblClick, this);
33215 // console.log(this);
33217 initEvents : function(){
33218 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33221 var a = this.ranchor;
33223 var el = Roo.get(a);
33225 if(Roo.isOpera){ // opera render bug ignores the CSS
33226 el.setStyle("text-decoration", "none");
33229 el.on("click", this.onClick, this);
33230 el.on("dblclick", this.onDblClick, this);
33231 el.on("contextmenu", this.onContextMenu, this);
33235 /*onSelectedChange : function(state){
33238 this.addClass("x-tree-selected");
33241 this.removeClass("x-tree-selected");
33244 addClass : function(cls){
33246 Roo.fly(this.elRow).addClass(cls);
33252 removeClass : function(cls){
33254 Roo.fly(this.elRow).removeClass(cls);
33260 });//<Script type="text/javascript">
33264 * Ext JS Library 1.1.1
33265 * Copyright(c) 2006-2007, Ext JS, LLC.
33267 * Originally Released Under LGPL - original licence link has changed is not relivant.
33270 * <script type="text/javascript">
33275 * @class Roo.tree.ColumnTree
33276 * @extends Roo.data.TreePanel
33277 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33278 * @cfg {int} borderWidth compined right/left border allowance
33280 * @param {String/HTMLElement/Element} el The container element
33281 * @param {Object} config
33283 Roo.tree.ColumnTree = function(el, config)
33285 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33289 * Fire this event on a container when it resizes
33290 * @param {int} w Width
33291 * @param {int} h Height
33295 this.on('resize', this.onResize, this);
33298 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33302 borderWidth: Roo.isBorderBox ? 0 : 2,
33305 render : function(){
33306 // add the header.....
33308 Roo.tree.ColumnTree.superclass.render.apply(this);
33310 this.el.addClass('x-column-tree');
33312 this.headers = this.el.createChild(
33313 {cls:'x-tree-headers'},this.innerCt.dom);
33315 var cols = this.columns, c;
33316 var totalWidth = 0;
33318 var len = cols.length;
33319 for(var i = 0; i < len; i++){
33321 totalWidth += c.width;
33322 this.headEls.push(this.headers.createChild({
33323 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33325 cls:'x-tree-hd-text',
33328 style:'width:'+(c.width-this.borderWidth)+'px;'
33331 this.headers.createChild({cls:'x-clear'});
33332 // prevent floats from wrapping when clipped
33333 this.headers.setWidth(totalWidth);
33334 //this.innerCt.setWidth(totalWidth);
33335 this.innerCt.setStyle({ overflow: 'auto' });
33336 this.onResize(this.width, this.height);
33340 onResize : function(w,h)
33345 this.innerCt.setWidth(this.width);
33346 this.innerCt.setHeight(this.height-20);
33349 var cols = this.columns, c;
33350 var totalWidth = 0;
33352 var len = cols.length;
33353 for(var i = 0; i < len; i++){
33355 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33356 // it's the expander..
33357 expEl = this.headEls[i];
33360 totalWidth += c.width;
33364 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33366 this.headers.setWidth(w-20);
33375 * Ext JS Library 1.1.1
33376 * Copyright(c) 2006-2007, Ext JS, LLC.
33378 * Originally Released Under LGPL - original licence link has changed is not relivant.
33381 * <script type="text/javascript">
33385 * @class Roo.menu.Menu
33386 * @extends Roo.util.Observable
33387 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33388 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33390 * Creates a new Menu
33391 * @param {Object} config Configuration options
33393 Roo.menu.Menu = function(config){
33394 Roo.apply(this, config);
33395 this.id = this.id || Roo.id();
33398 * @event beforeshow
33399 * Fires before this menu is displayed
33400 * @param {Roo.menu.Menu} this
33404 * @event beforehide
33405 * Fires before this menu is hidden
33406 * @param {Roo.menu.Menu} this
33411 * Fires after this menu is displayed
33412 * @param {Roo.menu.Menu} this
33417 * Fires after this menu is hidden
33418 * @param {Roo.menu.Menu} this
33423 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33424 * @param {Roo.menu.Menu} this
33425 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33426 * @param {Roo.EventObject} e
33431 * Fires when the mouse is hovering over this menu
33432 * @param {Roo.menu.Menu} this
33433 * @param {Roo.EventObject} e
33434 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33439 * Fires when the mouse exits this menu
33440 * @param {Roo.menu.Menu} this
33441 * @param {Roo.EventObject} e
33442 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33447 * Fires when a menu item contained in this menu is clicked
33448 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33449 * @param {Roo.EventObject} e
33453 if (this.registerMenu) {
33454 Roo.menu.MenuMgr.register(this);
33457 var mis = this.items;
33458 this.items = new Roo.util.MixedCollection();
33460 this.add.apply(this, mis);
33464 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33466 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33470 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33471 * for bottom-right shadow (defaults to "sides")
33475 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33476 * this menu (defaults to "tl-tr?")
33478 subMenuAlign : "tl-tr?",
33480 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33481 * relative to its element of origin (defaults to "tl-bl?")
33483 defaultAlign : "tl-bl?",
33485 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33487 allowOtherMenus : false,
33489 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33491 registerMenu : true,
33496 render : function(){
33500 var el = this.el = new Roo.Layer({
33502 shadow:this.shadow,
33504 parentEl: this.parentEl || document.body,
33508 this.keyNav = new Roo.menu.MenuNav(this);
33511 el.addClass("x-menu-plain");
33514 el.addClass(this.cls);
33516 // generic focus element
33517 this.focusEl = el.createChild({
33518 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33520 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33521 ul.on("click", this.onClick, this);
33522 ul.on("mouseover", this.onMouseOver, this);
33523 ul.on("mouseout", this.onMouseOut, this);
33524 this.items.each(function(item){
33525 var li = document.createElement("li");
33526 li.className = "x-menu-list-item";
33527 ul.dom.appendChild(li);
33528 item.render(li, this);
33535 autoWidth : function(){
33536 var el = this.el, ul = this.ul;
33540 var w = this.width;
33543 }else if(Roo.isIE){
33544 el.setWidth(this.minWidth);
33545 var t = el.dom.offsetWidth; // force recalc
33546 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33551 delayAutoWidth : function(){
33554 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33556 this.awTask.delay(20);
33561 findTargetItem : function(e){
33562 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33563 if(t && t.menuItemId){
33564 return this.items.get(t.menuItemId);
33569 onClick : function(e){
33571 if(t = this.findTargetItem(e)){
33573 this.fireEvent("click", this, t, e);
33578 setActiveItem : function(item, autoExpand){
33579 if(item != this.activeItem){
33580 if(this.activeItem){
33581 this.activeItem.deactivate();
33583 this.activeItem = item;
33584 item.activate(autoExpand);
33585 }else if(autoExpand){
33591 tryActivate : function(start, step){
33592 var items = this.items;
33593 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33594 var item = items.get(i);
33595 if(!item.disabled && item.canActivate){
33596 this.setActiveItem(item, false);
33604 onMouseOver : function(e){
33606 if(t = this.findTargetItem(e)){
33607 if(t.canActivate && !t.disabled){
33608 this.setActiveItem(t, true);
33611 this.fireEvent("mouseover", this, e, t);
33615 onMouseOut : function(e){
33617 if(t = this.findTargetItem(e)){
33618 if(t == this.activeItem && t.shouldDeactivate(e)){
33619 this.activeItem.deactivate();
33620 delete this.activeItem;
33623 this.fireEvent("mouseout", this, e, t);
33627 * Read-only. Returns true if the menu is currently displayed, else false.
33630 isVisible : function(){
33631 return this.el && !this.hidden;
33635 * Displays this menu relative to another element
33636 * @param {String/HTMLElement/Roo.Element} element The element to align to
33637 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33638 * the element (defaults to this.defaultAlign)
33639 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33641 show : function(el, pos, parentMenu){
33642 this.parentMenu = parentMenu;
33646 this.fireEvent("beforeshow", this);
33647 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33651 * Displays this menu at a specific xy position
33652 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
33653 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33655 showAt : function(xy, parentMenu, /* private: */_e){
33656 this.parentMenu = parentMenu;
33661 this.fireEvent("beforeshow", this);
33662 xy = this.el.adjustForConstraints(xy);
33666 this.hidden = false;
33668 this.fireEvent("show", this);
33671 focus : function(){
33673 this.doFocus.defer(50, this);
33677 doFocus : function(){
33679 this.focusEl.focus();
33684 * Hides this menu and optionally all parent menus
33685 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
33687 hide : function(deep){
33688 if(this.el && this.isVisible()){
33689 this.fireEvent("beforehide", this);
33690 if(this.activeItem){
33691 this.activeItem.deactivate();
33692 this.activeItem = null;
33695 this.hidden = true;
33696 this.fireEvent("hide", this);
33698 if(deep === true && this.parentMenu){
33699 this.parentMenu.hide(true);
33704 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
33705 * Any of the following are valid:
33707 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
33708 * <li>An HTMLElement object which will be converted to a menu item</li>
33709 * <li>A menu item config object that will be created as a new menu item</li>
33710 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
33711 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
33716 var menu = new Roo.menu.Menu();
33718 // Create a menu item to add by reference
33719 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
33721 // Add a bunch of items at once using different methods.
33722 // Only the last item added will be returned.
33723 var item = menu.add(
33724 menuItem, // add existing item by ref
33725 'Dynamic Item', // new TextItem
33726 '-', // new separator
33727 { text: 'Config Item' } // new item by config
33730 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
33731 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
33734 var a = arguments, l = a.length, item;
33735 for(var i = 0; i < l; i++){
33737 if(el.render){ // some kind of Item
33738 item = this.addItem(el);
33739 }else if(typeof el == "string"){ // string
33740 if(el == "separator" || el == "-"){
33741 item = this.addSeparator();
33743 item = this.addText(el);
33745 }else if(el.tagName || el.el){ // element
33746 item = this.addElement(el);
33747 }else if(typeof el == "object"){ // must be menu item config?
33748 item = this.addMenuItem(el);
33755 * Returns this menu's underlying {@link Roo.Element} object
33756 * @return {Roo.Element} The element
33758 getEl : function(){
33766 * Adds a separator bar to the menu
33767 * @return {Roo.menu.Item} The menu item that was added
33769 addSeparator : function(){
33770 return this.addItem(new Roo.menu.Separator());
33774 * Adds an {@link Roo.Element} object to the menu
33775 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
33776 * @return {Roo.menu.Item} The menu item that was added
33778 addElement : function(el){
33779 return this.addItem(new Roo.menu.BaseItem(el));
33783 * Adds an existing object based on {@link Roo.menu.Item} to the menu
33784 * @param {Roo.menu.Item} item The menu item to add
33785 * @return {Roo.menu.Item} The menu item that was added
33787 addItem : function(item){
33788 this.items.add(item);
33790 var li = document.createElement("li");
33791 li.className = "x-menu-list-item";
33792 this.ul.dom.appendChild(li);
33793 item.render(li, this);
33794 this.delayAutoWidth();
33800 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
33801 * @param {Object} config A MenuItem config object
33802 * @return {Roo.menu.Item} The menu item that was added
33804 addMenuItem : function(config){
33805 if(!(config instanceof Roo.menu.Item)){
33806 if(typeof config.checked == "boolean"){ // must be check menu item config?
33807 config = new Roo.menu.CheckItem(config);
33809 config = new Roo.menu.Item(config);
33812 return this.addItem(config);
33816 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
33817 * @param {String} text The text to display in the menu item
33818 * @return {Roo.menu.Item} The menu item that was added
33820 addText : function(text){
33821 return this.addItem(new Roo.menu.TextItem(text));
33825 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
33826 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
33827 * @param {Roo.menu.Item} item The menu item to add
33828 * @return {Roo.menu.Item} The menu item that was added
33830 insert : function(index, item){
33831 this.items.insert(index, item);
33833 var li = document.createElement("li");
33834 li.className = "x-menu-list-item";
33835 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
33836 item.render(li, this);
33837 this.delayAutoWidth();
33843 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
33844 * @param {Roo.menu.Item} item The menu item to remove
33846 remove : function(item){
33847 this.items.removeKey(item.id);
33852 * Removes and destroys all items in the menu
33854 removeAll : function(){
33856 while(f = this.items.first()){
33862 // MenuNav is a private utility class used internally by the Menu
33863 Roo.menu.MenuNav = function(menu){
33864 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
33865 this.scope = this.menu = menu;
33868 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
33869 doRelay : function(e, h){
33870 var k = e.getKey();
33871 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
33872 this.menu.tryActivate(0, 1);
33875 return h.call(this.scope || this, e, this.menu);
33878 up : function(e, m){
33879 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
33880 m.tryActivate(m.items.length-1, -1);
33884 down : function(e, m){
33885 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
33886 m.tryActivate(0, 1);
33890 right : function(e, m){
33892 m.activeItem.expandMenu(true);
33896 left : function(e, m){
33898 if(m.parentMenu && m.parentMenu.activeItem){
33899 m.parentMenu.activeItem.activate();
33903 enter : function(e, m){
33905 e.stopPropagation();
33906 m.activeItem.onClick(e);
33907 m.fireEvent("click", this, m.activeItem);
33913 * Ext JS Library 1.1.1
33914 * Copyright(c) 2006-2007, Ext JS, LLC.
33916 * Originally Released Under LGPL - original licence link has changed is not relivant.
33919 * <script type="text/javascript">
33923 * @class Roo.menu.MenuMgr
33924 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
33927 Roo.menu.MenuMgr = function(){
33928 var menus, active, groups = {}, attached = false, lastShow = new Date();
33930 // private - called when first menu is created
33933 active = new Roo.util.MixedCollection();
33934 Roo.get(document).addKeyListener(27, function(){
33935 if(active.length > 0){
33942 function hideAll(){
33943 if(active && active.length > 0){
33944 var c = active.clone();
33945 c.each(function(m){
33952 function onHide(m){
33954 if(active.length < 1){
33955 Roo.get(document).un("mousedown", onMouseDown);
33961 function onShow(m){
33962 var last = active.last();
33963 lastShow = new Date();
33966 Roo.get(document).on("mousedown", onMouseDown);
33970 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
33971 m.parentMenu.activeChild = m;
33972 }else if(last && last.isVisible()){
33973 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
33978 function onBeforeHide(m){
33980 m.activeChild.hide();
33982 if(m.autoHideTimer){
33983 clearTimeout(m.autoHideTimer);
33984 delete m.autoHideTimer;
33989 function onBeforeShow(m){
33990 var pm = m.parentMenu;
33991 if(!pm && !m.allowOtherMenus){
33993 }else if(pm && pm.activeChild && active != m){
33994 pm.activeChild.hide();
33999 function onMouseDown(e){
34000 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34006 function onBeforeCheck(mi, state){
34008 var g = groups[mi.group];
34009 for(var i = 0, l = g.length; i < l; i++){
34011 g[i].setChecked(false);
34020 * Hides all menus that are currently visible
34022 hideAll : function(){
34027 register : function(menu){
34031 menus[menu.id] = menu;
34032 menu.on("beforehide", onBeforeHide);
34033 menu.on("hide", onHide);
34034 menu.on("beforeshow", onBeforeShow);
34035 menu.on("show", onShow);
34036 var g = menu.group;
34037 if(g && menu.events["checkchange"]){
34041 groups[g].push(menu);
34042 menu.on("checkchange", onCheck);
34047 * Returns a {@link Roo.menu.Menu} object
34048 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34049 * be used to generate and return a new Menu instance.
34051 get : function(menu){
34052 if(typeof menu == "string"){ // menu id
34053 return menus[menu];
34054 }else if(menu.events){ // menu instance
34056 }else if(typeof menu.length == 'number'){ // array of menu items?
34057 return new Roo.menu.Menu({items:menu});
34058 }else{ // otherwise, must be a config
34059 return new Roo.menu.Menu(menu);
34064 unregister : function(menu){
34065 delete menus[menu.id];
34066 menu.un("beforehide", onBeforeHide);
34067 menu.un("hide", onHide);
34068 menu.un("beforeshow", onBeforeShow);
34069 menu.un("show", onShow);
34070 var g = menu.group;
34071 if(g && menu.events["checkchange"]){
34072 groups[g].remove(menu);
34073 menu.un("checkchange", onCheck);
34078 registerCheckable : function(menuItem){
34079 var g = menuItem.group;
34084 groups[g].push(menuItem);
34085 menuItem.on("beforecheckchange", onBeforeCheck);
34090 unregisterCheckable : function(menuItem){
34091 var g = menuItem.group;
34093 groups[g].remove(menuItem);
34094 menuItem.un("beforecheckchange", onBeforeCheck);
34100 * Ext JS Library 1.1.1
34101 * Copyright(c) 2006-2007, Ext JS, LLC.
34103 * Originally Released Under LGPL - original licence link has changed is not relivant.
34106 * <script type="text/javascript">
34111 * @class Roo.menu.BaseItem
34112 * @extends Roo.Component
34113 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34114 * management and base configuration options shared by all menu components.
34116 * Creates a new BaseItem
34117 * @param {Object} config Configuration options
34119 Roo.menu.BaseItem = function(config){
34120 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34125 * Fires when this item is clicked
34126 * @param {Roo.menu.BaseItem} this
34127 * @param {Roo.EventObject} e
34132 * Fires when this item is activated
34133 * @param {Roo.menu.BaseItem} this
34137 * @event deactivate
34138 * Fires when this item is deactivated
34139 * @param {Roo.menu.BaseItem} this
34145 this.on("click", this.handler, this.scope, true);
34149 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34151 * @cfg {Function} handler
34152 * A function that will handle the click event of this menu item (defaults to undefined)
34155 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34157 canActivate : false,
34159 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34161 activeClass : "x-menu-item-active",
34163 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34165 hideOnClick : true,
34167 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34172 ctype: "Roo.menu.BaseItem",
34175 actionMode : "container",
34178 render : function(container, parentMenu){
34179 this.parentMenu = parentMenu;
34180 Roo.menu.BaseItem.superclass.render.call(this, container);
34181 this.container.menuItemId = this.id;
34185 onRender : function(container, position){
34186 this.el = Roo.get(this.el);
34187 container.dom.appendChild(this.el.dom);
34191 onClick : function(e){
34192 if(!this.disabled && this.fireEvent("click", this, e) !== false
34193 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34194 this.handleClick(e);
34201 activate : function(){
34205 var li = this.container;
34206 li.addClass(this.activeClass);
34207 this.region = li.getRegion().adjust(2, 2, -2, -2);
34208 this.fireEvent("activate", this);
34213 deactivate : function(){
34214 this.container.removeClass(this.activeClass);
34215 this.fireEvent("deactivate", this);
34219 shouldDeactivate : function(e){
34220 return !this.region || !this.region.contains(e.getPoint());
34224 handleClick : function(e){
34225 if(this.hideOnClick){
34226 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34231 expandMenu : function(autoActivate){
34236 hideMenu : function(){
34241 * Ext JS Library 1.1.1
34242 * Copyright(c) 2006-2007, Ext JS, LLC.
34244 * Originally Released Under LGPL - original licence link has changed is not relivant.
34247 * <script type="text/javascript">
34251 * @class Roo.menu.Adapter
34252 * @extends Roo.menu.BaseItem
34253 * A base utility class that adapts a non-menu component so that it can be wrapped by a menu item and added to a menu.
34254 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34256 * Creates a new Adapter
34257 * @param {Object} config Configuration options
34259 Roo.menu.Adapter = function(component, config){
34260 Roo.menu.Adapter.superclass.constructor.call(this, config);
34261 this.component = component;
34263 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34265 canActivate : true,
34268 onRender : function(container, position){
34269 this.component.render(container);
34270 this.el = this.component.getEl();
34274 activate : function(){
34278 this.component.focus();
34279 this.fireEvent("activate", this);
34284 deactivate : function(){
34285 this.fireEvent("deactivate", this);
34289 disable : function(){
34290 this.component.disable();
34291 Roo.menu.Adapter.superclass.disable.call(this);
34295 enable : function(){
34296 this.component.enable();
34297 Roo.menu.Adapter.superclass.enable.call(this);
34301 * Ext JS Library 1.1.1
34302 * Copyright(c) 2006-2007, Ext JS, LLC.
34304 * Originally Released Under LGPL - original licence link has changed is not relivant.
34307 * <script type="text/javascript">
34311 * @class Roo.menu.TextItem
34312 * @extends Roo.menu.BaseItem
34313 * Adds a static text string to a menu, usually used as either a heading or group separator.
34315 * Creates a new TextItem
34316 * @param {String} text The text to display
34318 Roo.menu.TextItem = function(text){
34320 Roo.menu.TextItem.superclass.constructor.call(this);
34323 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34325 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34327 hideOnClick : false,
34329 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34331 itemCls : "x-menu-text",
34334 onRender : function(){
34335 var s = document.createElement("span");
34336 s.className = this.itemCls;
34337 s.innerHTML = this.text;
34339 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34343 * Ext JS Library 1.1.1
34344 * Copyright(c) 2006-2007, Ext JS, LLC.
34346 * Originally Released Under LGPL - original licence link has changed is not relivant.
34349 * <script type="text/javascript">
34353 * @class Roo.menu.Separator
34354 * @extends Roo.menu.BaseItem
34355 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34356 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34358 * @param {Object} config Configuration options
34360 Roo.menu.Separator = function(config){
34361 Roo.menu.Separator.superclass.constructor.call(this, config);
34364 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34366 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34368 itemCls : "x-menu-sep",
34370 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34372 hideOnClick : false,
34375 onRender : function(li){
34376 var s = document.createElement("span");
34377 s.className = this.itemCls;
34378 s.innerHTML = " ";
34380 li.addClass("x-menu-sep-li");
34381 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34385 * Ext JS Library 1.1.1
34386 * Copyright(c) 2006-2007, Ext JS, LLC.
34388 * Originally Released Under LGPL - original licence link has changed is not relivant.
34391 * <script type="text/javascript">
34394 * @class Roo.menu.Item
34395 * @extends Roo.menu.BaseItem
34396 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34397 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34398 * activation and click handling.
34400 * Creates a new Item
34401 * @param {Object} config Configuration options
34403 Roo.menu.Item = function(config){
34404 Roo.menu.Item.superclass.constructor.call(this, config);
34406 this.menu = Roo.menu.MenuMgr.get(this.menu);
34409 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34411 * @cfg {String} icon
34412 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34415 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34417 itemCls : "x-menu-item",
34419 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34421 canActivate : true,
34423 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34426 // doc'd in BaseItem
34430 ctype: "Roo.menu.Item",
34433 onRender : function(container, position){
34434 var el = document.createElement("a");
34435 el.hideFocus = true;
34436 el.unselectable = "on";
34437 el.href = this.href || "#";
34438 if(this.hrefTarget){
34439 el.target = this.hrefTarget;
34441 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34442 el.innerHTML = String.format(
34443 '<img src="{0}" class="x-menu-item-icon {2}" />{1}',
34444 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || '');
34446 Roo.menu.Item.superclass.onRender.call(this, container, position);
34450 * Sets the text to display in this menu item
34451 * @param {String} text The text to display
34453 setText : function(text){
34456 this.el.update(String.format(
34457 '<img src="{0}" class="x-menu-item-icon {2}">{1}',
34458 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34459 this.parentMenu.autoWidth();
34464 handleClick : function(e){
34465 if(!this.href){ // if no link defined, stop the event automatically
34468 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34472 activate : function(autoExpand){
34473 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34483 shouldDeactivate : function(e){
34484 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34485 if(this.menu && this.menu.isVisible()){
34486 return !this.menu.getEl().getRegion().contains(e.getPoint());
34494 deactivate : function(){
34495 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34500 expandMenu : function(autoActivate){
34501 if(!this.disabled && this.menu){
34502 clearTimeout(this.hideTimer);
34503 delete this.hideTimer;
34504 if(!this.menu.isVisible() && !this.showTimer){
34505 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34506 }else if (this.menu.isVisible() && autoActivate){
34507 this.menu.tryActivate(0, 1);
34513 deferExpand : function(autoActivate){
34514 delete this.showTimer;
34515 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34517 this.menu.tryActivate(0, 1);
34522 hideMenu : function(){
34523 clearTimeout(this.showTimer);
34524 delete this.showTimer;
34525 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34526 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34531 deferHide : function(){
34532 delete this.hideTimer;
34537 * Ext JS Library 1.1.1
34538 * Copyright(c) 2006-2007, Ext JS, LLC.
34540 * Originally Released Under LGPL - original licence link has changed is not relivant.
34543 * <script type="text/javascript">
34547 * @class Roo.menu.CheckItem
34548 * @extends Roo.menu.Item
34549 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34551 * Creates a new CheckItem
34552 * @param {Object} config Configuration options
34554 Roo.menu.CheckItem = function(config){
34555 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34558 * @event beforecheckchange
34559 * Fires before the checked value is set, providing an opportunity to cancel if needed
34560 * @param {Roo.menu.CheckItem} this
34561 * @param {Boolean} checked The new checked value that will be set
34563 "beforecheckchange" : true,
34565 * @event checkchange
34566 * Fires after the checked value has been set
34567 * @param {Roo.menu.CheckItem} this
34568 * @param {Boolean} checked The checked value that was set
34570 "checkchange" : true
34572 if(this.checkHandler){
34573 this.on('checkchange', this.checkHandler, this.scope);
34576 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34578 * @cfg {String} group
34579 * All check items with the same group name will automatically be grouped into a single-select
34580 * radio button group (defaults to '')
34583 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34585 itemCls : "x-menu-item x-menu-check-item",
34587 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34589 groupClass : "x-menu-group-item",
34592 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34593 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34594 * initialized with checked = true will be rendered as checked.
34599 ctype: "Roo.menu.CheckItem",
34602 onRender : function(c){
34603 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34605 this.el.addClass(this.groupClass);
34607 Roo.menu.MenuMgr.registerCheckable(this);
34609 this.checked = false;
34610 this.setChecked(true, true);
34615 destroy : function(){
34617 Roo.menu.MenuMgr.unregisterCheckable(this);
34619 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
34623 * Set the checked state of this item
34624 * @param {Boolean} checked The new checked value
34625 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
34627 setChecked : function(state, suppressEvent){
34628 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
34629 if(this.container){
34630 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
34632 this.checked = state;
34633 if(suppressEvent !== true){
34634 this.fireEvent("checkchange", this, state);
34640 handleClick : function(e){
34641 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
34642 this.setChecked(!this.checked);
34644 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
34648 * Ext JS Library 1.1.1
34649 * Copyright(c) 2006-2007, Ext JS, LLC.
34651 * Originally Released Under LGPL - original licence link has changed is not relivant.
34654 * <script type="text/javascript">
34658 * @class Roo.menu.DateItem
34659 * @extends Roo.menu.Adapter
34660 * A menu item that wraps the {@link Roo.DatPicker} component.
34662 * Creates a new DateItem
34663 * @param {Object} config Configuration options
34665 Roo.menu.DateItem = function(config){
34666 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
34667 /** The Roo.DatePicker object @type Roo.DatePicker */
34668 this.picker = this.component;
34669 this.addEvents({select: true});
34671 this.picker.on("render", function(picker){
34672 picker.getEl().swallowEvent("click");
34673 picker.container.addClass("x-menu-date-item");
34676 this.picker.on("select", this.onSelect, this);
34679 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
34681 onSelect : function(picker, date){
34682 this.fireEvent("select", this, date, picker);
34683 Roo.menu.DateItem.superclass.handleClick.call(this);
34687 * Ext JS Library 1.1.1
34688 * Copyright(c) 2006-2007, Ext JS, LLC.
34690 * Originally Released Under LGPL - original licence link has changed is not relivant.
34693 * <script type="text/javascript">
34697 * @class Roo.menu.ColorItem
34698 * @extends Roo.menu.Adapter
34699 * A menu item that wraps the {@link Roo.ColorPalette} component.
34701 * Creates a new ColorItem
34702 * @param {Object} config Configuration options
34704 Roo.menu.ColorItem = function(config){
34705 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
34706 /** The Roo.ColorPalette object @type Roo.ColorPalette */
34707 this.palette = this.component;
34708 this.relayEvents(this.palette, ["select"]);
34709 if(this.selectHandler){
34710 this.on('select', this.selectHandler, this.scope);
34713 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
34715 * Ext JS Library 1.1.1
34716 * Copyright(c) 2006-2007, Ext JS, LLC.
34718 * Originally Released Under LGPL - original licence link has changed is not relivant.
34721 * <script type="text/javascript">
34726 * @class Roo.menu.DateMenu
34727 * @extends Roo.menu.Menu
34728 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
34730 * Creates a new DateMenu
34731 * @param {Object} config Configuration options
34733 Roo.menu.DateMenu = function(config){
34734 Roo.menu.DateMenu.superclass.constructor.call(this, config);
34736 var di = new Roo.menu.DateItem(config);
34739 * The {@link Roo.DatePicker} instance for this DateMenu
34742 this.picker = di.picker;
34745 * @param {DatePicker} picker
34746 * @param {Date} date
34748 this.relayEvents(di, ["select"]);
34750 this.on('beforeshow', function(){
34752 this.picker.hideMonthPicker(true);
34756 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
34760 * Ext JS Library 1.1.1
34761 * Copyright(c) 2006-2007, Ext JS, LLC.
34763 * Originally Released Under LGPL - original licence link has changed is not relivant.
34766 * <script type="text/javascript">
34771 * @class Roo.menu.ColorMenu
34772 * @extends Roo.menu.Menu
34773 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
34775 * Creates a new ColorMenu
34776 * @param {Object} config Configuration options
34778 Roo.menu.ColorMenu = function(config){
34779 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
34781 var ci = new Roo.menu.ColorItem(config);
34784 * The {@link Roo.ColorPalette} instance for this ColorMenu
34785 * @type ColorPalette
34787 this.palette = ci.palette;
34790 * @param {ColorPalette} palette
34791 * @param {String} color
34793 this.relayEvents(ci, ["select"]);
34795 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
34797 * Ext JS Library 1.1.1
34798 * Copyright(c) 2006-2007, Ext JS, LLC.
34800 * Originally Released Under LGPL - original licence link has changed is not relivant.
34803 * <script type="text/javascript">
34807 * @class Roo.form.Field
34808 * @extends Roo.BoxComponent
34809 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
34811 * Creates a new Field
34812 * @param {Object} config Configuration options
34814 Roo.form.Field = function(config){
34815 Roo.form.Field.superclass.constructor.call(this, config);
34818 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
34820 * @cfg {String} fieldLabel Label to use when rendering a form.
34823 * @cfg {String} qtip Mouse over tip
34827 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
34829 invalidClass : "x-form-invalid",
34831 * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided (defaults to "The value in this field is invalid")
34833 invalidText : "The value in this field is invalid",
34835 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
34837 focusClass : "x-form-focus",
34839 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
34840 automatic validation (defaults to "keyup").
34842 validationEvent : "keyup",
34844 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
34846 validateOnBlur : true,
34848 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
34850 validationDelay : 250,
34852 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
34853 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
34855 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
34857 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
34859 fieldClass : "x-form-field",
34861 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
34864 ----------- ----------------------------------------------------------------------
34865 qtip Display a quick tip when the user hovers over the field
34866 title Display a default browser title attribute popup
34867 under Add a block div beneath the field containing the error text
34868 side Add an error icon to the right of the field with a popup on hover
34869 [element id] Add the error text directly to the innerHTML of the specified element
34872 msgTarget : 'qtip',
34874 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
34879 * @cfg {Boolean} readOnly True to mark the field as readOnly in HTML (defaults to false) -- Note: this only sets the element's readOnly DOM attribute.
34884 * @cfg {Boolean} disabled True to disable the field (defaults to false).
34889 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
34891 inputType : undefined,
34894 * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered, not those which are built via applyTo (defaults to undefined).
34896 tabIndex : undefined,
34899 isFormField : true,
34904 * @property {Roo.Element} fieldEl
34905 * Element Containing the rendered Field (with label etc.)
34908 * @cfg {Mixed} value A value to initialize this field with.
34913 * @cfg {String} name The field's HTML name attribute.
34916 * @cfg {String} cls A CSS class to apply to the field's underlying element.
34920 initComponent : function(){
34921 Roo.form.Field.superclass.initComponent.call(this);
34925 * Fires when this field receives input focus.
34926 * @param {Roo.form.Field} this
34931 * Fires when this field loses input focus.
34932 * @param {Roo.form.Field} this
34936 * @event specialkey
34937 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
34938 * {@link Roo.EventObject#getKey} to determine which key was pressed.
34939 * @param {Roo.form.Field} this
34940 * @param {Roo.EventObject} e The event object
34945 * Fires just before the field blurs if the field value has changed.
34946 * @param {Roo.form.Field} this
34947 * @param {Mixed} newValue The new value
34948 * @param {Mixed} oldValue The original value
34953 * Fires after the field has been marked as invalid.
34954 * @param {Roo.form.Field} this
34955 * @param {String} msg The validation message
34960 * Fires after the field has been validated with no errors.
34961 * @param {Roo.form.Field} this
34968 * Returns the name attribute of the field if available
34969 * @return {String} name The field name
34971 getName: function(){
34972 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
34976 onRender : function(ct, position){
34977 Roo.form.Field.superclass.onRender.call(this, ct, position);
34979 var cfg = this.getAutoCreate();
34981 cfg.name = this.name || this.id;
34983 if(this.inputType){
34984 cfg.type = this.inputType;
34986 this.el = ct.createChild(cfg, position);
34988 var type = this.el.dom.type;
34990 if(type == 'password'){
34993 this.el.addClass('x-form-'+type);
34996 this.el.dom.readOnly = true;
34998 if(this.tabIndex !== undefined){
34999 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35002 this.el.addClass([this.fieldClass, this.cls]);
35007 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35008 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35009 * @return {Roo.form.Field} this
35011 applyTo : function(target){
35012 this.allowDomMove = false;
35013 this.el = Roo.get(target);
35014 this.render(this.el.dom.parentNode);
35019 initValue : function(){
35020 if(this.value !== undefined){
35021 this.setValue(this.value);
35022 }else if(this.el.dom.value.length > 0){
35023 this.setValue(this.el.dom.value);
35028 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35030 isDirty : function() {
35031 if(this.disabled) {
35034 return String(this.getValue()) !== String(this.originalValue);
35038 afterRender : function(){
35039 Roo.form.Field.superclass.afterRender.call(this);
35044 fireKey : function(e){
35045 if(e.isNavKeyPress()){
35046 this.fireEvent("specialkey", this, e);
35051 * Resets the current field value to the originally loaded value and clears any validation messages
35053 reset : function(){
35054 this.setValue(this.originalValue);
35055 this.clearInvalid();
35059 initEvents : function(){
35060 this.el.on(Roo.isIE ? "keydown" : "keypress", this.fireKey, this);
35061 this.el.on("focus", this.onFocus, this);
35062 this.el.on("blur", this.onBlur, this);
35064 // reference to original value for reset
35065 this.originalValue = this.getValue();
35069 onFocus : function(){
35070 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35071 this.el.addClass(this.focusClass);
35073 if(!this.hasFocus){
35074 this.hasFocus = true;
35075 this.startValue = this.getValue();
35076 this.fireEvent("focus", this);
35080 beforeBlur : Roo.emptyFn,
35083 onBlur : function(){
35085 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35086 this.el.removeClass(this.focusClass);
35088 this.hasFocus = false;
35089 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35092 var v = this.getValue();
35093 if(String(v) !== String(this.startValue)){
35094 this.fireEvent('change', this, v, this.startValue);
35096 this.fireEvent("blur", this);
35100 * Returns whether or not the field value is currently valid
35101 * @param {Boolean} preventMark True to disable marking the field invalid
35102 * @return {Boolean} True if the value is valid, else false
35104 isValid : function(preventMark){
35108 var restore = this.preventMark;
35109 this.preventMark = preventMark === true;
35110 var v = this.validateValue(this.processValue(this.getRawValue()));
35111 this.preventMark = restore;
35116 * Validates the field value
35117 * @return {Boolean} True if the value is valid, else false
35119 validate : function(){
35120 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35121 this.clearInvalid();
35127 processValue : function(value){
35132 // Subclasses should provide the validation implementation by overriding this
35133 validateValue : function(value){
35138 * Mark this field as invalid
35139 * @param {String} msg The validation message
35141 markInvalid : function(msg){
35142 if(!this.rendered || this.preventMark){ // not rendered
35145 this.el.addClass(this.invalidClass);
35146 msg = msg || this.invalidText;
35147 switch(this.msgTarget){
35149 this.el.dom.qtip = msg;
35150 this.el.dom.qclass = 'x-form-invalid-tip';
35151 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35152 Roo.QuickTips.enable();
35156 this.el.dom.title = msg;
35160 var elp = this.el.findParent('.x-form-element', 5, true);
35161 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35162 this.errorEl.setWidth(elp.getWidth(true)-20);
35164 this.errorEl.update(msg);
35165 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35168 if(!this.errorIcon){
35169 var elp = this.el.findParent('.x-form-element', 5, true);
35170 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35172 this.alignErrorIcon();
35173 this.errorIcon.dom.qtip = msg;
35174 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35175 this.errorIcon.show();
35176 this.on('resize', this.alignErrorIcon, this);
35179 var t = Roo.getDom(this.msgTarget);
35181 t.style.display = this.msgDisplay;
35184 this.fireEvent('invalid', this, msg);
35188 alignErrorIcon : function(){
35189 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35193 * Clear any invalid styles/messages for this field
35195 clearInvalid : function(){
35196 if(!this.rendered || this.preventMark){ // not rendered
35199 this.el.removeClass(this.invalidClass);
35200 switch(this.msgTarget){
35202 this.el.dom.qtip = '';
35205 this.el.dom.title = '';
35209 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35213 if(this.errorIcon){
35214 this.errorIcon.dom.qtip = '';
35215 this.errorIcon.hide();
35216 this.un('resize', this.alignErrorIcon, this);
35220 var t = Roo.getDom(this.msgTarget);
35222 t.style.display = 'none';
35225 this.fireEvent('valid', this);
35229 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35230 * @return {Mixed} value The field value
35232 getRawValue : function(){
35233 var v = this.el.getValue();
35234 if(v === this.emptyText){
35241 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35242 * @return {Mixed} value The field value
35244 getValue : function(){
35245 var v = this.el.getValue();
35246 if(v === this.emptyText || v === undefined){
35253 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35254 * @param {Mixed} value The value to set
35256 setRawValue : function(v){
35257 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35261 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35262 * @param {Mixed} value The value to set
35264 setValue : function(v){
35267 this.el.dom.value = (v === null || v === undefined ? '' : v);
35272 adjustSize : function(w, h){
35273 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35274 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35278 adjustWidth : function(tag, w){
35279 tag = tag.toLowerCase();
35280 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35281 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35282 if(tag == 'input'){
35285 if(tag = 'textarea'){
35288 }else if(Roo.isOpera){
35289 if(tag == 'input'){
35292 if(tag = 'textarea'){
35302 // anything other than normal should be considered experimental
35303 Roo.form.Field.msgFx = {
35305 show: function(msgEl, f){
35306 msgEl.setDisplayed('block');
35309 hide : function(msgEl, f){
35310 msgEl.setDisplayed(false).update('');
35315 show: function(msgEl, f){
35316 msgEl.slideIn('t', {stopFx:true});
35319 hide : function(msgEl, f){
35320 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35325 show: function(msgEl, f){
35326 msgEl.fixDisplay();
35327 msgEl.alignTo(f.el, 'tl-tr');
35328 msgEl.slideIn('l', {stopFx:true});
35331 hide : function(msgEl, f){
35332 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35337 * Ext JS Library 1.1.1
35338 * Copyright(c) 2006-2007, Ext JS, LLC.
35340 * Originally Released Under LGPL - original licence link has changed is not relivant.
35343 * <script type="text/javascript">
35348 * @class Roo.form.TextField
35349 * @extends Roo.form.Field
35350 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35351 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35353 * Creates a new TextField
35354 * @param {Object} config Configuration options
35356 Roo.form.TextField = function(config){
35357 Roo.form.TextField.superclass.constructor.call(this, config);
35361 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35362 * according to the default logic, but this event provides a hook for the developer to apply additional
35363 * logic at runtime to resize the field if needed.
35364 * @param {Roo.form.Field} this This text field
35365 * @param {Number} width The new field width
35371 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35373 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35377 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35381 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35385 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35389 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35393 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35395 disableKeyFilter : false,
35397 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35401 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35405 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35407 maxLength : Number.MAX_VALUE,
35409 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35411 minLengthText : "The minimum length for this field is {0}",
35413 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35415 maxLengthText : "The maximum length for this field is {0}",
35417 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35419 selectOnFocus : false,
35421 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35423 blankText : "This field is required",
35425 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35426 * If available, this function will be called only after the basic validators all return true, and will be passed the
35427 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35431 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35432 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35433 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35437 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35441 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35445 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35446 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35448 emptyClass : 'x-form-empty-field',
35451 initEvents : function(){
35452 Roo.form.TextField.superclass.initEvents.call(this);
35453 if(this.validationEvent == 'keyup'){
35454 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35455 this.el.on('keyup', this.filterValidation, this);
35457 else if(this.validationEvent !== false){
35458 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35460 if(this.selectOnFocus || this.emptyText){
35461 this.on("focus", this.preFocus, this);
35462 if(this.emptyText){
35463 this.on('blur', this.postBlur, this);
35464 this.applyEmptyText();
35467 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35468 this.el.on("keypress", this.filterKeys, this);
35471 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35472 this.el.on("click", this.autoSize, this);
35476 processValue : function(value){
35477 if(this.stripCharsRe){
35478 var newValue = value.replace(this.stripCharsRe, '');
35479 if(newValue !== value){
35480 this.setRawValue(newValue);
35487 filterValidation : function(e){
35488 if(!e.isNavKeyPress()){
35489 this.validationTask.delay(this.validationDelay);
35494 onKeyUp : function(e){
35495 if(!e.isNavKeyPress()){
35501 * Resets the current field value to the originally-loaded value and clears any validation messages.
35502 * Also adds emptyText and emptyClass if the original value was blank.
35504 reset : function(){
35505 Roo.form.TextField.superclass.reset.call(this);
35506 this.applyEmptyText();
35509 applyEmptyText : function(){
35510 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35511 this.setRawValue(this.emptyText);
35512 this.el.addClass(this.emptyClass);
35517 preFocus : function(){
35518 if(this.emptyText){
35519 if(this.el.dom.value == this.emptyText){
35520 this.setRawValue('');
35522 this.el.removeClass(this.emptyClass);
35524 if(this.selectOnFocus){
35525 this.el.dom.select();
35530 postBlur : function(){
35531 this.applyEmptyText();
35535 filterKeys : function(e){
35536 var k = e.getKey();
35537 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35540 var c = e.getCharCode(), cc = String.fromCharCode(c);
35541 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35544 if(!this.maskRe.test(cc)){
35549 setValue : function(v){
35550 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35551 this.el.removeClass(this.emptyClass);
35553 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35554 this.applyEmptyText();
35559 * Validates a value according to the field's validation rules and marks the field as invalid
35560 * if the validation fails
35561 * @param {Mixed} value The value to validate
35562 * @return {Boolean} True if the value is valid, else false
35564 validateValue : function(value){
35565 if(value.length < 1 || value === this.emptyText){ // if it's blank
35566 if(this.allowBlank){
35567 this.clearInvalid();
35570 this.markInvalid(this.blankText);
35574 if(value.length < this.minLength){
35575 this.markInvalid(String.format(this.minLengthText, this.minLength));
35578 if(value.length > this.maxLength){
35579 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35583 var vt = Roo.form.VTypes;
35584 if(!vt[this.vtype](value, this)){
35585 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35589 if(typeof this.validator == "function"){
35590 var msg = this.validator(value);
35592 this.markInvalid(msg);
35596 if(this.regex && !this.regex.test(value)){
35597 this.markInvalid(this.regexText);
35604 * Selects text in this field
35605 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
35606 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
35608 selectText : function(start, end){
35609 var v = this.getRawValue();
35611 start = start === undefined ? 0 : start;
35612 end = end === undefined ? v.length : end;
35613 var d = this.el.dom;
35614 if(d.setSelectionRange){
35615 d.setSelectionRange(start, end);
35616 }else if(d.createTextRange){
35617 var range = d.createTextRange();
35618 range.moveStart("character", start);
35619 range.moveEnd("character", v.length-end);
35626 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
35627 * This only takes effect if grow = true, and fires the autosize event.
35629 autoSize : function(){
35630 if(!this.grow || !this.rendered){
35634 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
35637 var v = el.dom.value;
35638 var d = document.createElement('div');
35639 d.appendChild(document.createTextNode(v));
35643 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
35644 this.el.setWidth(w);
35645 this.fireEvent("autosize", this, w);
35649 * Ext JS Library 1.1.1
35650 * Copyright(c) 2006-2007, Ext JS, LLC.
35652 * Originally Released Under LGPL - original licence link has changed is not relivant.
35655 * <script type="text/javascript">
35659 * @class Roo.form.Hidden
35660 * @extends Roo.form.TextField
35661 * Simple Hidden element used on forms
35663 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
35666 * Creates a new Hidden form element.
35667 * @param {Object} config Configuration options
35672 // easy hidden field...
35673 Roo.form.Hidden = function(config){
35674 Roo.form.Hidden.superclass.constructor.call(this, config);
35677 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
35679 inputType: 'hidden',
35682 labelSeparator: '',
35684 itemCls : 'x-form-item-display-none'
35692 * Ext JS Library 1.1.1
35693 * Copyright(c) 2006-2007, Ext JS, LLC.
35695 * Originally Released Under LGPL - original licence link has changed is not relivant.
35698 * <script type="text/javascript">
35702 * @class Roo.form.TriggerField
35703 * @extends Roo.form.TextField
35704 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
35705 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
35706 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
35707 * for which you can provide a custom implementation. For example:
35709 var trigger = new Roo.form.TriggerField();
35710 trigger.onTriggerClick = myTriggerFn;
35711 trigger.applyTo('my-field');
35714 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
35715 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
35716 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
35717 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
35719 * Create a new TriggerField.
35720 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
35721 * to the base TextField)
35723 Roo.form.TriggerField = function(config){
35724 this.mimicing = false;
35725 Roo.form.TriggerField.superclass.constructor.call(this, config);
35728 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
35730 * @cfg {String} triggerClass A CSS class to apply to the trigger
35733 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35734 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
35736 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
35738 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
35742 /** @cfg {Boolean} grow @hide */
35743 /** @cfg {Number} growMin @hide */
35744 /** @cfg {Number} growMax @hide */
35750 autoSize: Roo.emptyFn,
35754 deferHeight : true,
35757 actionMode : 'wrap',
35759 onResize : function(w, h){
35760 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
35761 if(typeof w == 'number'){
35762 this.el.setWidth(this.adjustWidth('input', w - this.trigger.getWidth()));
35767 adjustSize : Roo.BoxComponent.prototype.adjustSize,
35770 getResizeEl : function(){
35775 getPositionEl : function(){
35780 alignErrorIcon : function(){
35781 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
35785 onRender : function(ct, position){
35786 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
35787 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
35788 this.trigger = this.wrap.createChild(this.triggerConfig ||
35789 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
35790 if(this.hideTrigger){
35791 this.trigger.setDisplayed(false);
35793 this.initTrigger();
35795 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
35800 initTrigger : function(){
35801 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
35802 this.trigger.addClassOnOver('x-form-trigger-over');
35803 this.trigger.addClassOnClick('x-form-trigger-click');
35807 onDestroy : function(){
35809 this.trigger.removeAllListeners();
35810 this.trigger.remove();
35813 this.wrap.remove();
35815 Roo.form.TriggerField.superclass.onDestroy.call(this);
35819 onFocus : function(){
35820 Roo.form.TriggerField.superclass.onFocus.call(this);
35821 if(!this.mimicing){
35822 this.wrap.addClass('x-trigger-wrap-focus');
35823 this.mimicing = true;
35824 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
35825 if(this.monitorTab){
35826 this.el.on("keydown", this.checkTab, this);
35832 checkTab : function(e){
35833 if(e.getKey() == e.TAB){
35834 this.triggerBlur();
35839 onBlur : function(){
35844 mimicBlur : function(e, t){
35845 if(!this.wrap.contains(t) && this.validateBlur()){
35846 this.triggerBlur();
35851 triggerBlur : function(){
35852 this.mimicing = false;
35853 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
35854 if(this.monitorTab){
35855 this.el.un("keydown", this.checkTab, this);
35857 this.wrap.removeClass('x-trigger-wrap-focus');
35858 Roo.form.TriggerField.superclass.onBlur.call(this);
35862 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
35863 validateBlur : function(e, t){
35868 onDisable : function(){
35869 Roo.form.TriggerField.superclass.onDisable.call(this);
35871 this.wrap.addClass('x-item-disabled');
35876 onEnable : function(){
35877 Roo.form.TriggerField.superclass.onEnable.call(this);
35879 this.wrap.removeClass('x-item-disabled');
35884 onShow : function(){
35885 var ae = this.getActionEl();
35888 ae.dom.style.display = '';
35889 ae.dom.style.visibility = 'visible';
35895 onHide : function(){
35896 var ae = this.getActionEl();
35897 ae.dom.style.display = 'none';
35901 * The function that should handle the trigger's click event. This method does nothing by default until overridden
35902 * by an implementing function.
35904 * @param {EventObject} e
35906 onTriggerClick : Roo.emptyFn
35909 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
35910 // to be extended by an implementing class. For an example of implementing this class, see the custom
35911 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
35912 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
35913 initComponent : function(){
35914 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
35916 this.triggerConfig = {
35917 tag:'span', cls:'x-form-twin-triggers', cn:[
35918 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
35919 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
35923 getTrigger : function(index){
35924 return this.triggers[index];
35927 initTrigger : function(){
35928 var ts = this.trigger.select('.x-form-trigger', true);
35929 this.wrap.setStyle('overflow', 'hidden');
35930 var triggerField = this;
35931 ts.each(function(t, all, index){
35932 t.hide = function(){
35933 var w = triggerField.wrap.getWidth();
35934 this.dom.style.display = 'none';
35935 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
35937 t.show = function(){
35938 var w = triggerField.wrap.getWidth();
35939 this.dom.style.display = '';
35940 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
35942 var triggerIndex = 'Trigger'+(index+1);
35944 if(this['hide'+triggerIndex]){
35945 t.dom.style.display = 'none';
35947 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
35948 t.addClassOnOver('x-form-trigger-over');
35949 t.addClassOnClick('x-form-trigger-click');
35951 this.triggers = ts.elements;
35954 onTrigger1Click : Roo.emptyFn,
35955 onTrigger2Click : Roo.emptyFn
35958 * Ext JS Library 1.1.1
35959 * Copyright(c) 2006-2007, Ext JS, LLC.
35961 * Originally Released Under LGPL - original licence link has changed is not relivant.
35964 * <script type="text/javascript">
35968 * @class Roo.form.TextArea
35969 * @extends Roo.form.TextField
35970 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
35971 * support for auto-sizing.
35973 * Creates a new TextArea
35974 * @param {Object} config Configuration options
35976 Roo.form.TextArea = function(config){
35977 Roo.form.TextArea.superclass.constructor.call(this, config);
35978 // these are provided exchanges for backwards compat
35979 // minHeight/maxHeight were replaced by growMin/growMax to be
35980 // compatible with TextField growing config values
35981 if(this.minHeight !== undefined){
35982 this.growMin = this.minHeight;
35984 if(this.maxHeight !== undefined){
35985 this.growMax = this.maxHeight;
35989 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
35991 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
35995 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
35999 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36000 * in the field (equivalent to setting overflow: hidden, defaults to false)
36002 preventScrollbars: false,
36004 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36005 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36009 onRender : function(ct, position){
36011 this.defaultAutoCreate = {
36013 style:"width:300px;height:60px;",
36014 autocomplete: "off"
36017 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36019 this.textSizeEl = Roo.DomHelper.append(document.body, {
36020 tag: "pre", cls: "x-form-grow-sizer"
36022 if(this.preventScrollbars){
36023 this.el.setStyle("overflow", "hidden");
36025 this.el.setHeight(this.growMin);
36029 onDestroy : function(){
36030 if(this.textSizeEl){
36031 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36033 Roo.form.TextArea.superclass.onDestroy.call(this);
36037 onKeyUp : function(e){
36038 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36044 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36045 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36047 autoSize : function(){
36048 if(!this.grow || !this.textSizeEl){
36052 var v = el.dom.value;
36053 var ts = this.textSizeEl;
36056 ts.appendChild(document.createTextNode(v));
36059 Roo.fly(ts).setWidth(this.el.getWidth());
36061 v = "  ";
36064 v = v.replace(/\n/g, '<p> </p>');
36066 v += " \n ";
36069 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36070 if(h != this.lastHeight){
36071 this.lastHeight = h;
36072 this.el.setHeight(h);
36073 this.fireEvent("autosize", this, h);
36078 * Ext JS Library 1.1.1
36079 * Copyright(c) 2006-2007, Ext JS, LLC.
36081 * Originally Released Under LGPL - original licence link has changed is not relivant.
36084 * <script type="text/javascript">
36089 * @class Roo.form.NumberField
36090 * @extends Roo.form.TextField
36091 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36093 * Creates a new NumberField
36094 * @param {Object} config Configuration options
36096 Roo.form.NumberField = function(config){
36097 Roo.form.NumberField.superclass.constructor.call(this, config);
36100 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36102 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36104 fieldClass: "x-form-field x-form-num-field",
36106 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36108 allowDecimals : true,
36110 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36112 decimalSeparator : ".",
36114 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36116 decimalPrecision : 2,
36118 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36120 allowNegative : true,
36122 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36124 minValue : Number.NEGATIVE_INFINITY,
36126 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36128 maxValue : Number.MAX_VALUE,
36130 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36132 minText : "The minimum value for this field is {0}",
36134 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36136 maxText : "The maximum value for this field is {0}",
36138 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36139 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36141 nanText : "{0} is not a valid number",
36144 initEvents : function(){
36145 Roo.form.NumberField.superclass.initEvents.call(this);
36146 var allowed = "0123456789";
36147 if(this.allowDecimals){
36148 allowed += this.decimalSeparator;
36150 if(this.allowNegative){
36153 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36154 var keyPress = function(e){
36155 var k = e.getKey();
36156 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36159 var c = e.getCharCode();
36160 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36164 this.el.on("keypress", keyPress, this);
36168 validateValue : function(value){
36169 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36172 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36175 var num = this.parseValue(value);
36177 this.markInvalid(String.format(this.nanText, value));
36180 if(num < this.minValue){
36181 this.markInvalid(String.format(this.minText, this.minValue));
36184 if(num > this.maxValue){
36185 this.markInvalid(String.format(this.maxText, this.maxValue));
36191 getValue : function(){
36192 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36196 parseValue : function(value){
36197 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36198 return isNaN(value) ? '' : value;
36202 fixPrecision : function(value){
36203 var nan = isNaN(value);
36204 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36205 return nan ? '' : value;
36207 return parseFloat(value).toFixed(this.decimalPrecision);
36210 setValue : function(v){
36211 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36215 decimalPrecisionFcn : function(v){
36216 return Math.floor(v);
36219 beforeBlur : function(){
36220 var v = this.parseValue(this.getRawValue());
36222 this.setValue(this.fixPrecision(v));
36227 * Ext JS Library 1.1.1
36228 * Copyright(c) 2006-2007, Ext JS, LLC.
36230 * Originally Released Under LGPL - original licence link has changed is not relivant.
36233 * <script type="text/javascript">
36237 * @class Roo.form.DateField
36238 * @extends Roo.form.TriggerField
36239 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36241 * Create a new DateField
36242 * @param {Object} config
36244 Roo.form.DateField = function(config){
36245 Roo.form.DateField.superclass.constructor.call(this, config);
36251 * Fires when a date is selected
36252 * @param {Roo.form.DateField} combo This combo box
36253 * @param {Date} date The date selected
36260 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36261 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36262 this.ddMatch = null;
36263 if(this.disabledDates){
36264 var dd = this.disabledDates;
36266 for(var i = 0; i < dd.length; i++){
36268 if(i != dd.length-1) re += "|";
36270 this.ddMatch = new RegExp(re + ")");
36274 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36276 * @cfg {String} format
36277 * The default date format string which can be overriden for localization support. The format must be
36278 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36282 * @cfg {String} altFormats
36283 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36284 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36286 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36288 * @cfg {Array} disabledDays
36289 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36291 disabledDays : null,
36293 * @cfg {String} disabledDaysText
36294 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36296 disabledDaysText : "Disabled",
36298 * @cfg {Array} disabledDates
36299 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36300 * expression so they are very powerful. Some examples:
36302 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36303 * <li>["03/08", "09/16"] would disable those days for every year</li>
36304 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36305 * <li>["03/../2006"] would disable every day in March 2006</li>
36306 * <li>["^03"] would disable every day in every March</li>
36308 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36309 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36311 disabledDates : null,
36313 * @cfg {String} disabledDatesText
36314 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36316 disabledDatesText : "Disabled",
36318 * @cfg {Date/String} minValue
36319 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36320 * valid format (defaults to null).
36324 * @cfg {Date/String} maxValue
36325 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36326 * valid format (defaults to null).
36330 * @cfg {String} minText
36331 * The error text to display when the date in the cell is before minValue (defaults to
36332 * 'The date in this field must be after {minValue}').
36334 minText : "The date in this field must be equal to or after {0}",
36336 * @cfg {String} maxText
36337 * The error text to display when the date in the cell is after maxValue (defaults to
36338 * 'The date in this field must be before {maxValue}').
36340 maxText : "The date in this field must be equal to or before {0}",
36342 * @cfg {String} invalidText
36343 * The error text to display when the date in the field is invalid (defaults to
36344 * '{value} is not a valid date - it must be in the format {format}').
36346 invalidText : "{0} is not a valid date - it must be in the format {1}",
36348 * @cfg {String} triggerClass
36349 * An additional CSS class used to style the trigger button. The trigger will always get the
36350 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36351 * which displays a calendar icon).
36353 triggerClass : 'x-form-date-trigger',
36357 * @cfg {bool} useIso
36358 * if enabled, then the date field will use a hidden field to store the
36359 * real value as iso formated date. default (false)
36363 * @cfg {String/Object} autoCreate
36364 * A DomHelper element spec, or true for a default element spec (defaults to
36365 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36368 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36371 hiddenField: false,
36373 onRender : function(ct, position)
36375 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36377 this.el.dom.removeAttribute('name');
36378 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36380 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36381 // prevent input submission
36382 this.hiddenName = this.name;
36389 validateValue : function(value)
36391 value = this.formatDate(value);
36392 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36395 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36398 var svalue = value;
36399 value = this.parseDate(value);
36401 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36404 var time = value.getTime();
36405 if(this.minValue && time < this.minValue.getTime()){
36406 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36409 if(this.maxValue && time > this.maxValue.getTime()){
36410 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36413 if(this.disabledDays){
36414 var day = value.getDay();
36415 for(var i = 0; i < this.disabledDays.length; i++) {
36416 if(day === this.disabledDays[i]){
36417 this.markInvalid(this.disabledDaysText);
36422 var fvalue = this.formatDate(value);
36423 if(this.ddMatch && this.ddMatch.test(fvalue)){
36424 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36431 // Provides logic to override the default TriggerField.validateBlur which just returns true
36432 validateBlur : function(){
36433 return !this.menu || !this.menu.isVisible();
36437 * Returns the current date value of the date field.
36438 * @return {Date} The date value
36440 getValue : function(){
36442 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36446 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36447 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36448 * (the default format used is "m/d/y").
36451 //All of these calls set the same date value (May 4, 2006)
36453 //Pass a date object:
36454 var dt = new Date('5/4/06');
36455 dateField.setValue(dt);
36457 //Pass a date string (default format):
36458 dateField.setValue('5/4/06');
36460 //Pass a date string (custom format):
36461 dateField.format = 'Y-m-d';
36462 dateField.setValue('2006-5-4');
36464 * @param {String/Date} date The date or valid date string
36466 setValue : function(date){
36467 if (this.hiddenField) {
36468 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36470 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36474 parseDate : function(value){
36475 if(!value || value instanceof Date){
36478 var v = Date.parseDate(value, this.format);
36479 if(!v && this.altFormats){
36480 if(!this.altFormatsArray){
36481 this.altFormatsArray = this.altFormats.split("|");
36483 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36484 v = Date.parseDate(value, this.altFormatsArray[i]);
36491 formatDate : function(date, fmt){
36492 return (!date || !(date instanceof Date)) ?
36493 date : date.dateFormat(fmt || this.format);
36498 select: function(m, d){
36500 this.fireEvent('select', this, d);
36502 show : function(){ // retain focus styling
36506 this.focus.defer(10, this);
36507 var ml = this.menuListeners;
36508 this.menu.un("select", ml.select, this);
36509 this.menu.un("show", ml.show, this);
36510 this.menu.un("hide", ml.hide, this);
36515 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36516 onTriggerClick : function(){
36520 if(this.menu == null){
36521 this.menu = new Roo.menu.DateMenu();
36523 Roo.apply(this.menu.picker, {
36524 showClear: this.allowBlank,
36525 minDate : this.minValue,
36526 maxDate : this.maxValue,
36527 disabledDatesRE : this.ddMatch,
36528 disabledDatesText : this.disabledDatesText,
36529 disabledDays : this.disabledDays,
36530 disabledDaysText : this.disabledDaysText,
36531 format : this.format,
36532 minText : String.format(this.minText, this.formatDate(this.minValue)),
36533 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36535 this.menu.on(Roo.apply({}, this.menuListeners, {
36538 this.menu.picker.setValue(this.getValue() || new Date());
36539 this.menu.show(this.el, "tl-bl?");
36542 beforeBlur : function(){
36543 var v = this.parseDate(this.getRawValue());
36549 /** @cfg {Boolean} grow @hide */
36550 /** @cfg {Number} growMin @hide */
36551 /** @cfg {Number} growMax @hide */
36558 * Ext JS Library 1.1.1
36559 * Copyright(c) 2006-2007, Ext JS, LLC.
36561 * Originally Released Under LGPL - original licence link has changed is not relivant.
36564 * <script type="text/javascript">
36569 * @class Roo.form.ComboBox
36570 * @extends Roo.form.TriggerField
36571 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36573 * Create a new ComboBox.
36574 * @param {Object} config Configuration options
36576 Roo.form.ComboBox = function(config){
36577 Roo.form.ComboBox.superclass.constructor.call(this, config);
36581 * Fires when the dropdown list is expanded
36582 * @param {Roo.form.ComboBox} combo This combo box
36587 * Fires when the dropdown list is collapsed
36588 * @param {Roo.form.ComboBox} combo This combo box
36592 * @event beforeselect
36593 * Fires before a list item is selected. Return false to cancel the selection.
36594 * @param {Roo.form.ComboBox} combo This combo box
36595 * @param {Roo.data.Record} record The data record returned from the underlying store
36596 * @param {Number} index The index of the selected item in the dropdown list
36598 'beforeselect' : true,
36601 * Fires when a list item is selected
36602 * @param {Roo.form.ComboBox} combo This combo box
36603 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
36604 * @param {Number} index The index of the selected item in the dropdown list
36608 * @event beforequery
36609 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
36610 * The event object passed has these properties:
36611 * @param {Roo.form.ComboBox} combo This combo box
36612 * @param {String} query The query
36613 * @param {Boolean} forceAll true to force "all" query
36614 * @param {Boolean} cancel true to cancel the query
36615 * @param {Object} e The query event object
36617 'beforequery': true
36619 if(this.transform){
36620 this.allowDomMove = false;
36621 var s = Roo.getDom(this.transform);
36622 if(!this.hiddenName){
36623 this.hiddenName = s.name;
36626 this.mode = 'local';
36627 var d = [], opts = s.options;
36628 for(var i = 0, len = opts.length;i < len; i++){
36630 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
36632 this.value = value;
36634 d.push([value, o.text]);
36636 this.store = new Roo.data.SimpleStore({
36638 fields: ['value', 'text'],
36641 this.valueField = 'value';
36642 this.displayField = 'text';
36644 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
36645 if(!this.lazyRender){
36646 this.target = true;
36647 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
36648 s.parentNode.removeChild(s); // remove it
36649 this.render(this.el.parentNode);
36651 s.parentNode.removeChild(s); // remove it
36656 this.store = Roo.factory(this.store, Roo.data);
36659 this.selectedIndex = -1;
36660 if(this.mode == 'local'){
36661 if(config.queryDelay === undefined){
36662 this.queryDelay = 10;
36664 if(config.minChars === undefined){
36670 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
36672 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
36675 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
36676 * rendering into an Roo.Editor, defaults to false)
36679 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
36680 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
36683 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
36686 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
36687 * the dropdown list (defaults to undefined, with no header element)
36691 * @cfg {String/Roo.Template} tpl The template to use to render the output
36695 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
36697 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
36699 listWidth: undefined,
36701 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
36702 * mode = 'remote' or 'text' if mode = 'local')
36704 displayField: undefined,
36706 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
36707 * mode = 'remote' or 'value' if mode = 'local').
36708 * Note: use of a valueField requires the user make a selection
36709 * in order for a value to be mapped.
36711 valueField: undefined,
36713 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
36714 * field's data value (defaults to the underlying DOM element's name)
36716 hiddenName: undefined,
36718 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
36722 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
36724 selectedClass: 'x-combo-selected',
36726 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36727 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
36728 * which displays a downward arrow icon).
36730 triggerClass : 'x-form-arrow-trigger',
36732 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
36736 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
36737 * anchor positions (defaults to 'tl-bl')
36739 listAlign: 'tl-bl?',
36741 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
36745 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
36746 * query specified by the allQuery config option (defaults to 'query')
36748 triggerAction: 'query',
36750 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
36751 * (defaults to 4, does not apply if editable = false)
36755 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
36756 * delay (typeAheadDelay) if it matches a known value (defaults to false)
36760 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
36761 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
36765 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
36766 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
36770 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
36771 * when editable = true (defaults to false)
36773 selectOnFocus:false,
36775 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
36777 queryParam: 'query',
36779 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
36780 * when mode = 'remote' (defaults to 'Loading...')
36782 loadingText: 'Loading...',
36784 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
36788 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
36792 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
36793 * traditional select (defaults to true)
36797 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
36801 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
36805 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
36806 * listWidth has a higher value)
36810 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
36811 * allow the user to set arbitrary text into the field (defaults to false)
36813 forceSelection:false,
36815 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
36816 * if typeAhead = true (defaults to 250)
36818 typeAheadDelay : 250,
36820 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
36821 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
36823 valueNotFoundText : undefined,
36825 * @cfg {bool} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
36827 blockFocus : false,
36830 * @cfg {bool} disableClear Disable showing of clear button.
36832 disableClear : false,
36835 onRender : function(ct, position){
36836 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
36837 if(this.hiddenName){
36838 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
36840 this.hiddenField.value =
36841 this.hiddenValue !== undefined ? this.hiddenValue :
36842 this.value !== undefined ? this.value : '';
36844 // prevent input submission
36845 this.el.dom.removeAttribute('name');
36848 this.el.dom.setAttribute('autocomplete', 'off');
36851 var cls = 'x-combo-list';
36853 this.list = new Roo.Layer({
36854 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
36857 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
36858 this.list.setWidth(lw);
36859 this.list.swallowEvent('mousewheel');
36860 this.assetHeight = 0;
36863 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
36864 this.assetHeight += this.header.getHeight();
36867 this.innerList = this.list.createChild({cls:cls+'-inner'});
36868 this.innerList.on('mouseover', this.onViewOver, this);
36869 this.innerList.on('mousemove', this.onViewMove, this);
36870 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
36872 if(this.allowBlank && !this.pageSize && !this.disableClear){
36873 this.footer = this.list.createChild({cls:cls+'-ft'});
36874 this.pageTb = new Roo.Toolbar(this.footer);
36878 this.footer = this.list.createChild({cls:cls+'-ft'});
36879 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
36880 {pageSize: this.pageSize});
36884 if (this.pageTb && this.allowBlank && !this.disableClear) {
36886 this.pageTb.add(new Roo.Toolbar.Fill(), {
36887 cls: 'x-btn-icon x-btn-clear',
36889 handler: function()
36892 _this.clearValue();
36893 _this.onSelect(false, -1);
36898 this.assetHeight += this.footer.getHeight();
36903 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
36906 this.view = new Roo.View(this.innerList, this.tpl, {
36907 singleSelect:true, store: this.store, selectedClass: this.selectedClass
36910 this.view.on('click', this.onViewClick, this);
36912 this.store.on('beforeload', this.onBeforeLoad, this);
36913 this.store.on('load', this.onLoad, this);
36914 this.store.on('loadexception', this.collapse, this);
36916 if(this.resizable){
36917 this.resizer = new Roo.Resizable(this.list, {
36918 pinned:true, handles:'se'
36920 this.resizer.on('resize', function(r, w, h){
36921 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
36922 this.listWidth = w;
36923 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
36924 this.restrictHeight();
36926 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
36928 if(!this.editable){
36929 this.editable = true;
36930 this.setEditable(false);
36935 initEvents : function(){
36936 Roo.form.ComboBox.superclass.initEvents.call(this);
36938 this.keyNav = new Roo.KeyNav(this.el, {
36939 "up" : function(e){
36940 this.inKeyMode = true;
36944 "down" : function(e){
36945 if(!this.isExpanded()){
36946 this.onTriggerClick();
36948 this.inKeyMode = true;
36953 "enter" : function(e){
36954 this.onViewClick();
36958 "esc" : function(e){
36962 "tab" : function(e){
36963 this.onViewClick(false);
36969 doRelay : function(foo, bar, hname){
36970 if(hname == 'down' || this.scope.isExpanded()){
36971 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
36978 this.queryDelay = Math.max(this.queryDelay || 10,
36979 this.mode == 'local' ? 10 : 250);
36980 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
36981 if(this.typeAhead){
36982 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
36984 if(this.editable !== false){
36985 this.el.on("keyup", this.onKeyUp, this);
36987 if(this.forceSelection){
36988 this.on('blur', this.doForce, this);
36992 onDestroy : function(){
36994 this.view.setStore(null);
36995 this.view.el.removeAllListeners();
36996 this.view.el.remove();
36997 this.view.purgeListeners();
37000 this.list.destroy();
37003 this.store.un('beforeload', this.onBeforeLoad, this);
37004 this.store.un('load', this.onLoad, this);
37005 this.store.un('loadexception', this.collapse, this);
37007 Roo.form.ComboBox.superclass.onDestroy.call(this);
37011 fireKey : function(e){
37012 if(e.isNavKeyPress() && !this.list.isVisible()){
37013 this.fireEvent("specialkey", this, e);
37018 onResize: function(w, h){
37019 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37020 if(this.list && this.listWidth === undefined){
37021 var lw = Math.max(w, this.minListWidth);
37022 this.list.setWidth(lw);
37023 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37028 * Allow or prevent the user from directly editing the field text. If false is passed,
37029 * the user will only be able to select from the items defined in the dropdown list. This method
37030 * is the runtime equivalent of setting the 'editable' config option at config time.
37031 * @param {Boolean} value True to allow the user to directly edit the field text
37033 setEditable : function(value){
37034 if(value == this.editable){
37037 this.editable = value;
37039 this.el.dom.setAttribute('readOnly', true);
37040 this.el.on('mousedown', this.onTriggerClick, this);
37041 this.el.addClass('x-combo-noedit');
37043 this.el.dom.setAttribute('readOnly', false);
37044 this.el.un('mousedown', this.onTriggerClick, this);
37045 this.el.removeClass('x-combo-noedit');
37050 onBeforeLoad : function(){
37051 if(!this.hasFocus){
37054 this.innerList.update(this.loadingText ?
37055 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37056 this.restrictHeight();
37057 this.selectedIndex = -1;
37061 onLoad : function(){
37062 if(!this.hasFocus){
37065 if(this.store.getCount() > 0){
37067 this.restrictHeight();
37068 if(this.lastQuery == this.allQuery){
37070 this.el.dom.select();
37072 if(!this.selectByValue(this.value, true)){
37073 this.select(0, true);
37077 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37078 this.taTask.delay(this.typeAheadDelay);
37082 this.onEmptyResults();
37088 onTypeAhead : function(){
37089 if(this.store.getCount() > 0){
37090 var r = this.store.getAt(0);
37091 var newValue = r.data[this.displayField];
37092 var len = newValue.length;
37093 var selStart = this.getRawValue().length;
37094 if(selStart != len){
37095 this.setRawValue(newValue);
37096 this.selectText(selStart, newValue.length);
37102 onSelect : function(record, index){
37103 if(this.fireEvent('beforeselect', this, record, index) !== false){
37104 this.setFromData(index > -1 ? record.data : false);
37106 this.fireEvent('select', this, record, index);
37111 * Returns the currently selected field value or empty string if no value is set.
37112 * @return {String} value The selected value
37114 getValue : function(){
37115 if(this.valueField){
37116 return typeof this.value != 'undefined' ? this.value : '';
37118 return Roo.form.ComboBox.superclass.getValue.call(this);
37123 * Clears any text/value currently set in the field
37125 clearValue : function(){
37126 if(this.hiddenField){
37127 this.hiddenField.value = '';
37130 this.setRawValue('');
37131 this.lastSelectionText = '';
37132 this.applyEmptyText();
37136 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37137 * will be displayed in the field. If the value does not match the data value of an existing item,
37138 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37139 * Otherwise the field will be blank (although the value will still be set).
37140 * @param {String} value The value to match
37142 setValue : function(v){
37144 if(this.valueField){
37145 var r = this.findRecord(this.valueField, v);
37147 text = r.data[this.displayField];
37148 }else if(this.valueNotFoundText !== undefined){
37149 text = this.valueNotFoundText;
37152 this.lastSelectionText = text;
37153 if(this.hiddenField){
37154 this.hiddenField.value = v;
37156 Roo.form.ComboBox.superclass.setValue.call(this, text);
37160 * @property {Object} the last set data for the element
37165 * Sets the value of the field based on a object which is related to the record format for the store.
37166 * @param {Object} value the value to set as. or false on reset?
37168 setFromData : function(o){
37169 var dv = ''; // display value
37170 var vv = ''; // value value..
37172 if (this.displayField) {
37173 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37175 // this is an error condition!!!
37176 console.log('no value field set for '+ this.name);
37179 if(this.valueField){
37180 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37182 if(this.hiddenField){
37183 this.hiddenField.value = vv;
37185 this.lastSelectionText = dv;
37186 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37190 // no hidden field.. - we store the value in 'value', but still display
37191 // display field!!!!
37192 this.lastSelectionText = dv;
37193 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37199 reset : function(){
37200 // overridden so that last data is reset..
37201 this.setValue(this.originalValue);
37202 this.clearInvalid();
37203 this.lastData = false;
37206 findRecord : function(prop, value){
37208 if(this.store.getCount() > 0){
37209 this.store.each(function(r){
37210 if(r.data[prop] == value){
37220 onViewMove : function(e, t){
37221 this.inKeyMode = false;
37225 onViewOver : function(e, t){
37226 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37229 var item = this.view.findItemFromChild(t);
37231 var index = this.view.indexOf(item);
37232 this.select(index, false);
37237 onViewClick : function(doFocus){
37238 var index = this.view.getSelectedIndexes()[0];
37239 var r = this.store.getAt(index);
37241 this.onSelect(r, index);
37243 if(doFocus !== false && !this.blockFocus){
37249 restrictHeight : function(){
37250 this.innerList.dom.style.height = '';
37251 var inner = this.innerList.dom;
37252 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37253 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37254 this.list.beginUpdate();
37255 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37256 this.list.alignTo(this.el, this.listAlign);
37257 this.list.endUpdate();
37261 onEmptyResults : function(){
37266 * Returns true if the dropdown list is expanded, else false.
37268 isExpanded : function(){
37269 return this.list.isVisible();
37273 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37274 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37275 * @param {String} value The data value of the item to select
37276 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37277 * selected item if it is not currently in view (defaults to true)
37278 * @return {Boolean} True if the value matched an item in the list, else false
37280 selectByValue : function(v, scrollIntoView){
37281 if(v !== undefined && v !== null){
37282 var r = this.findRecord(this.valueField || this.displayField, v);
37284 this.select(this.store.indexOf(r), scrollIntoView);
37292 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37293 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37294 * @param {Number} index The zero-based index of the list item to select
37295 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37296 * selected item if it is not currently in view (defaults to true)
37298 select : function(index, scrollIntoView){
37299 this.selectedIndex = index;
37300 this.view.select(index);
37301 if(scrollIntoView !== false){
37302 var el = this.view.getNode(index);
37304 this.innerList.scrollChildIntoView(el, false);
37310 selectNext : function(){
37311 var ct = this.store.getCount();
37313 if(this.selectedIndex == -1){
37315 }else if(this.selectedIndex < ct-1){
37316 this.select(this.selectedIndex+1);
37322 selectPrev : function(){
37323 var ct = this.store.getCount();
37325 if(this.selectedIndex == -1){
37327 }else if(this.selectedIndex != 0){
37328 this.select(this.selectedIndex-1);
37334 onKeyUp : function(e){
37335 if(this.editable !== false && !e.isSpecialKey()){
37336 this.lastKey = e.getKey();
37337 this.dqTask.delay(this.queryDelay);
37342 validateBlur : function(){
37343 return !this.list || !this.list.isVisible();
37347 initQuery : function(){
37348 this.doQuery(this.getRawValue());
37352 doForce : function(){
37353 if(this.el.dom.value.length > 0){
37354 this.el.dom.value =
37355 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37356 this.applyEmptyText();
37361 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37362 * query allowing the query action to be canceled if needed.
37363 * @param {String} query The SQL query to execute
37364 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37365 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37366 * saved in the current store (defaults to false)
37368 doQuery : function(q, forceAll){
37369 if(q === undefined || q === null){
37374 forceAll: forceAll,
37378 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37382 forceAll = qe.forceAll;
37383 if(forceAll === true || (q.length >= this.minChars)){
37384 if(this.lastQuery != q){
37385 this.lastQuery = q;
37386 if(this.mode == 'local'){
37387 this.selectedIndex = -1;
37389 this.store.clearFilter();
37391 this.store.filter(this.displayField, q);
37395 this.store.baseParams[this.queryParam] = q;
37397 params: this.getParams(q)
37402 this.selectedIndex = -1;
37409 getParams : function(q){
37411 //p[this.queryParam] = q;
37414 p.limit = this.pageSize;
37420 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37422 collapse : function(){
37423 if(!this.isExpanded()){
37427 Roo.get(document).un('mousedown', this.collapseIf, this);
37428 Roo.get(document).un('mousewheel', this.collapseIf, this);
37429 this.fireEvent('collapse', this);
37433 collapseIf : function(e){
37434 if(!e.within(this.wrap) && !e.within(this.list)){
37440 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37442 expand : function(){
37443 if(this.isExpanded() || !this.hasFocus){
37446 this.list.alignTo(this.el, this.listAlign);
37448 Roo.get(document).on('mousedown', this.collapseIf, this);
37449 Roo.get(document).on('mousewheel', this.collapseIf, this);
37450 this.fireEvent('expand', this);
37454 // Implements the default empty TriggerField.onTriggerClick function
37455 onTriggerClick : function(){
37459 if(this.isExpanded()){
37461 if (!this.blockFocus) {
37466 this.hasFocus = true;
37467 if(this.triggerAction == 'all') {
37468 this.doQuery(this.allQuery, true);
37470 this.doQuery(this.getRawValue());
37472 if (!this.blockFocus) {
37479 * @cfg {Boolean} grow
37483 * @cfg {Number} growMin
37487 * @cfg {Number} growMax
37496 * Ext JS Library 1.1.1
37497 * Copyright(c) 2006-2007, Ext JS, LLC.
37499 * Originally Released Under LGPL - original licence link has changed is not relivant.
37502 * <script type="text/javascript">
37505 * @class Roo.form.Checkbox
37506 * @extends Roo.form.Field
37507 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
37509 * Creates a new Checkbox
37510 * @param {Object} config Configuration options
37512 Roo.form.Checkbox = function(config){
37513 Roo.form.Checkbox.superclass.constructor.call(this, config);
37517 * Fires when the checkbox is checked or unchecked.
37518 * @param {Roo.form.Checkbox} this This checkbox
37519 * @param {Boolean} checked The new checked value
37525 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
37527 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
37529 focusClass : undefined,
37531 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
37533 fieldClass: "x-form-field",
37535 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
37539 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37540 * {tag: "input", type: "checkbox", autocomplete: "off"})
37542 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
37544 * @cfg {String} boxLabel The text that appears beside the checkbox
37548 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
37552 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
37554 valueOff: '0', // value when not checked..
37556 actionMode : 'viewEl',
37559 itemCls : 'x-menu-check-item x-form-item',
37560 groupClass : 'x-menu-group-item',
37561 inputType : 'hidden',
37564 inSetChecked: false, // check that we are not calling self...
37566 inputElement: false, // real input element?
37567 basedOn: false, // ????
37569 isFormField: true, // not sure where this is needed!!!!
37571 onResize : function(){
37572 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
37573 if(!this.boxLabel){
37574 this.el.alignTo(this.wrap, 'c-c');
37578 initEvents : function(){
37579 Roo.form.Checkbox.superclass.initEvents.call(this);
37580 this.el.on("click", this.onClick, this);
37581 this.el.on("change", this.onClick, this);
37585 getResizeEl : function(){
37589 getPositionEl : function(){
37594 onRender : function(ct, position){
37595 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
37597 if(this.inputValue !== undefined){
37598 this.el.dom.value = this.inputValue;
37601 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
37602 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
37603 var viewEl = this.wrap.createChild({
37604 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
37605 this.viewEl = viewEl;
37606 this.wrap.on('click', this.onClick, this);
37608 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
37609 this.el.on('propertychange', this.setFromHidden, this); //ie
37614 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
37615 // viewEl.on('click', this.onClick, this);
37617 //if(this.checked){
37618 this.setChecked(this.checked);
37620 //this.checked = this.el.dom;
37626 initValue : Roo.emptyFn,
37629 * Returns the checked state of the checkbox.
37630 * @return {Boolean} True if checked, else false
37632 getValue : function(){
37634 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
37636 return this.valueOff;
37641 onClick : function(){
37642 this.setChecked(!this.checked);
37644 //if(this.el.dom.checked != this.checked){
37645 // this.setValue(this.el.dom.checked);
37650 * Sets the checked state of the checkbox.
37651 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
37653 setValue : function(v,suppressEvent){
37654 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
37655 //if(this.el && this.el.dom){
37656 // this.el.dom.checked = this.checked;
37657 // this.el.dom.defaultChecked = this.checked;
37659 this.setChecked(v === this.inputValue);
37660 //this.fireEvent("check", this, this.checked);
37663 setChecked : function(state,suppressEvent)
37665 if (this.inSetChecked) {
37666 this.checked = state;
37672 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
37674 this.checked = state;
37675 if(suppressEvent !== true){
37676 this.fireEvent('checkchange', this, state);
37678 this.inSetChecked = true;
37679 this.el.dom.value = state ? this.inputValue : this.valueOff;
37680 this.inSetChecked = false;
37683 // handle setting of hidden value by some other method!!?!?
37684 setFromHidden: function()
37689 //console.log("SET FROM HIDDEN");
37690 //alert('setFrom hidden');
37691 this.setValue(this.el.dom.value);
37694 onDestroy : function()
37697 Roo.get(this.viewEl).remove();
37700 Roo.form.Checkbox.superclass.onDestroy.call(this);
37705 * Ext JS Library 1.1.1
37706 * Copyright(c) 2006-2007, Ext JS, LLC.
37708 * Originally Released Under LGPL - original licence link has changed is not relivant.
37711 * <script type="text/javascript">
37715 * @class Roo.form.Radio
37716 * @extends Roo.form.Checkbox
37717 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
37718 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
37720 * Creates a new Radio
37721 * @param {Object} config Configuration options
37723 Roo.form.Radio = function(){
37724 Roo.form.Radio.superclass.constructor.apply(this, arguments);
37726 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
37727 inputType: 'radio',
37730 * If this radio is part of a group, it will return the selected value
37733 getGroupValue : function(){
37734 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
37736 });//<script type="text/javascript">
37739 * Ext JS Library 1.1.1
37740 * Copyright(c) 2006-2007, Ext JS, LLC.
37741 * licensing@extjs.com
37743 * http://www.extjs.com/license
37749 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
37750 * - IE ? - no idea how much works there.
37758 * @class Ext.form.HtmlEditor
37759 * @extends Ext.form.Field
37760 * Provides a lightweight HTML Editor component.
37761 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
37763 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
37764 * supported by this editor.</b><br/><br/>
37765 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
37766 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
37768 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
37770 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
37774 * @cfg {String} createLinkText The default text for the create link prompt
37776 createLinkText : 'Please enter the URL for the link:',
37778 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
37780 defaultLinkValue : 'http:/'+'/',
37786 // private properties
37787 validationEvent : false,
37789 initialized : false,
37791 sourceEditMode : false,
37792 onFocus : Roo.emptyFn,
37794 hideMode:'offsets',
37795 defaultAutoCreate : {
37797 style:"width:500px;height:300px;",
37798 autocomplete: "off"
37802 initComponent : function(){
37805 * @event initialize
37806 * Fires when the editor is fully initialized (including the iframe)
37807 * @param {HtmlEditor} this
37812 * Fires when the editor is first receives the focus. Any insertion must wait
37813 * until after this event.
37814 * @param {HtmlEditor} this
37818 * @event beforesync
37819 * Fires before the textarea is updated with content from the editor iframe. Return false
37820 * to cancel the sync.
37821 * @param {HtmlEditor} this
37822 * @param {String} html
37826 * @event beforepush
37827 * Fires before the iframe editor is updated with content from the textarea. Return false
37828 * to cancel the push.
37829 * @param {HtmlEditor} this
37830 * @param {String} html
37835 * Fires when the textarea is updated with content from the editor iframe.
37836 * @param {HtmlEditor} this
37837 * @param {String} html
37842 * Fires when the iframe editor is updated with content from the textarea.
37843 * @param {HtmlEditor} this
37844 * @param {String} html
37848 * @event editmodechange
37849 * Fires when the editor switches edit modes
37850 * @param {HtmlEditor} this
37851 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
37853 editmodechange: true,
37855 * @event editorevent
37856 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
37857 * @param {HtmlEditor} this
37864 * Protected method that will not generally be called directly. It
37865 * is called when the editor creates its toolbar. Override this method if you need to
37866 * add custom toolbar buttons.
37867 * @param {HtmlEditor} editor
37869 createToolbar : function(editor){
37870 if (!editor.toolbars || !editor.toolbars.length) {
37871 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
37874 for (var i =0 ; i < editor.toolbars.length;i++) {
37875 editor.toolbars[i].init(editor);
37882 * Protected method that will not generally be called directly. It
37883 * is called when the editor initializes the iframe with HTML contents. Override this method if you
37884 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
37886 getDocMarkup : function(){
37887 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
37891 onRender : function(ct, position){
37892 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
37893 this.el.dom.style.border = '0 none';
37894 this.el.dom.setAttribute('tabIndex', -1);
37895 this.el.addClass('x-hidden');
37896 if(Roo.isIE){ // fix IE 1px bogus margin
37897 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
37899 this.wrap = this.el.wrap({
37900 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
37903 this.frameId = Roo.id();
37904 this.createToolbar(this);
37911 var iframe = this.wrap.createChild({
37914 name: this.frameId,
37915 frameBorder : 'no',
37916 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
37919 // console.log(iframe);
37920 //this.wrap.dom.appendChild(iframe);
37922 this.iframe = iframe.dom;
37924 this.assignDocWin();
37926 this.doc.designMode = 'on';
37929 this.doc.write(this.getDocMarkup());
37933 var task = { // must defer to wait for browser to be ready
37935 //console.log("run task?" + this.doc.readyState);
37936 this.assignDocWin();
37937 if(this.doc.body || this.doc.readyState == 'complete'){
37941 this.doc.designMode="on";
37945 Roo.TaskMgr.stop(task);
37946 this.initEditor.defer(10, this);
37953 Roo.TaskMgr.start(task);
37956 this.setSize(this.el.getSize());
37961 onResize : function(w, h){
37962 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
37963 if(this.el && this.iframe){
37964 if(typeof w == 'number'){
37965 var aw = w - this.wrap.getFrameWidth('lr');
37966 this.el.setWidth(this.adjustWidth('textarea', aw));
37967 this.iframe.style.width = aw + 'px';
37969 if(typeof h == 'number'){
37971 for (var i =0; i < this.toolbars.length;i++) {
37972 // fixme - ask toolbars for heights?
37973 tbh += this.toolbars[i].tb.el.getHeight();
37979 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
37980 this.el.setHeight(this.adjustWidth('textarea', ah));
37981 this.iframe.style.height = ah + 'px';
37983 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
37990 * Toggles the editor between standard and source edit mode.
37991 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
37993 toggleSourceEdit : function(sourceEditMode){
37995 this.sourceEditMode = sourceEditMode === true;
37997 if(this.sourceEditMode){
38000 this.iframe.className = 'x-hidden';
38001 this.el.removeClass('x-hidden');
38002 this.el.dom.removeAttribute('tabIndex');
38007 this.iframe.className = '';
38008 this.el.addClass('x-hidden');
38009 this.el.dom.setAttribute('tabIndex', -1);
38012 this.setSize(this.wrap.getSize());
38013 this.fireEvent('editmodechange', this, this.sourceEditMode);
38016 // private used internally
38017 createLink : function(){
38018 var url = prompt(this.createLinkText, this.defaultLinkValue);
38019 if(url && url != 'http:/'+'/'){
38020 this.relayCmd('createlink', url);
38024 // private (for BoxComponent)
38025 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38027 // private (for BoxComponent)
38028 getResizeEl : function(){
38032 // private (for BoxComponent)
38033 getPositionEl : function(){
38038 initEvents : function(){
38039 this.originalValue = this.getValue();
38043 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38046 markInvalid : Roo.emptyFn,
38048 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38051 clearInvalid : Roo.emptyFn,
38053 setValue : function(v){
38054 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38059 * Protected method that will not generally be called directly. If you need/want
38060 * custom HTML cleanup, this is the method you should override.
38061 * @param {String} html The HTML to be cleaned
38062 * return {String} The cleaned HTML
38064 cleanHtml : function(html){
38065 html = String(html);
38066 if(html.length > 5){
38067 if(Roo.isSafari){ // strip safari nonsense
38068 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38071 if(html == ' '){
38078 * Protected method that will not generally be called directly. Syncs the contents
38079 * of the editor iframe with the textarea.
38081 syncValue : function(){
38082 if(this.initialized){
38083 var bd = (this.doc.body || this.doc.documentElement);
38084 var html = bd.innerHTML;
38086 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38087 var m = bs.match(/text-align:(.*?);/i);
38089 html = '<div style="'+m[0]+'">' + html + '</div>';
38092 html = this.cleanHtml(html);
38093 if(this.fireEvent('beforesync', this, html) !== false){
38094 this.el.dom.value = html;
38095 this.fireEvent('sync', this, html);
38101 * Protected method that will not generally be called directly. Pushes the value of the textarea
38102 * into the iframe editor.
38104 pushValue : function(){
38105 if(this.initialized){
38106 var v = this.el.dom.value;
38110 if(this.fireEvent('beforepush', this, v) !== false){
38111 (this.doc.body || this.doc.documentElement).innerHTML = v;
38112 this.fireEvent('push', this, v);
38118 deferFocus : function(){
38119 this.focus.defer(10, this);
38123 focus : function(){
38124 if(this.win && !this.sourceEditMode){
38131 assignDocWin: function()
38133 var iframe = this.iframe;
38136 this.doc = iframe.contentWindow.document;
38137 this.win = iframe.contentWindow;
38139 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38140 this.win = Roo.get(this.frameId).dom.contentWindow;
38145 initEditor : function(){
38146 //console.log("INIT EDITOR");
38147 this.assignDocWin();
38151 this.doc.designMode="on";
38153 this.doc.write(this.getDocMarkup());
38156 var dbody = (this.doc.body || this.doc.documentElement);
38157 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38158 // this copies styles from the containing element into thsi one..
38159 // not sure why we need all of this..
38160 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38161 ss['background-attachment'] = 'fixed'; // w3c
38162 dbody.bgProperties = 'fixed'; // ie
38163 Roo.DomHelper.applyStyles(dbody, ss);
38164 Roo.EventManager.on(this.doc, {
38165 'mousedown': this.onEditorEvent,
38166 'dblclick': this.onEditorEvent,
38167 'click': this.onEditorEvent,
38168 'keyup': this.onEditorEvent,
38173 Roo.EventManager.on(this.doc, 'keypress', this.applyCommand, this);
38175 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38176 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38178 this.initialized = true;
38180 this.fireEvent('initialize', this);
38185 onDestroy : function(){
38191 for (var i =0; i < this.toolbars.length;i++) {
38192 // fixme - ask toolbars for heights?
38193 this.toolbars[i].onDestroy();
38196 this.wrap.dom.innerHTML = '';
38197 this.wrap.remove();
38202 onFirstFocus : function(){
38204 this.assignDocWin();
38207 this.activated = true;
38208 for (var i =0; i < this.toolbars.length;i++) {
38209 this.toolbars[i].onFirstFocus();
38212 if(Roo.isGecko){ // prevent silly gecko errors
38214 var s = this.win.getSelection();
38215 if(!s.focusNode || s.focusNode.nodeType != 3){
38216 var r = s.getRangeAt(0);
38217 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38222 this.execCmd('useCSS', true);
38223 this.execCmd('styleWithCSS', false);
38226 this.fireEvent('activate', this);
38230 adjustFont: function(btn){
38231 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38232 //if(Roo.isSafari){ // safari
38235 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38236 if(Roo.isSafari){ // safari
38237 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38238 v = (v < 10) ? 10 : v;
38239 v = (v > 48) ? 48 : v;
38240 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38245 v = Math.max(1, v+adjust);
38247 this.execCmd('FontSize', v );
38250 onEditorEvent : function(e){
38251 this.fireEvent('editorevent', this, e);
38252 // this.updateToolbar();
38256 insertTag : function(tg)
38258 // could be a bit smarter... -> wrap the current selected tRoo..
38260 this.execCmd("formatblock", tg);
38264 insertText : function(txt)
38268 range = this.createRange();
38269 range.deleteContents();
38270 //alert(Sender.getAttribute('label'));
38272 range.insertNode(this.doc.createTextNode(txt));
38276 relayBtnCmd : function(btn){
38277 this.relayCmd(btn.cmd);
38281 * Executes a Midas editor command on the editor document and performs necessary focus and
38282 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38283 * @param {String} cmd The Midas command
38284 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38286 relayCmd : function(cmd, value){
38288 this.execCmd(cmd, value);
38289 this.fireEvent('editorevent', this);
38290 //this.updateToolbar();
38295 * Executes a Midas editor command directly on the editor document.
38296 * For visual commands, you should use {@link #relayCmd} instead.
38297 * <b>This should only be called after the editor is initialized.</b>
38298 * @param {String} cmd The Midas command
38299 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38301 execCmd : function(cmd, value){
38302 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38307 applyCommand : function(e){
38309 var c = e.getCharCode(), cmd;
38311 c = String.fromCharCode(c);
38327 e.preventDefault();
38334 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38336 * @param {String} text
38338 insertAtCursor : function(text){
38339 if(!this.activated){
38344 var r = this.doc.selection.createRange();
38351 }else if(Roo.isGecko || Roo.isOpera){
38353 this.execCmd('InsertHTML', text);
38355 }else if(Roo.isSafari){
38356 this.execCmd('InsertText', text);
38362 fixKeys : function(){ // load time branching for fastest keydown performance
38364 return function(e){
38365 var k = e.getKey(), r;
38368 r = this.doc.selection.createRange();
38371 r.pasteHTML('    ');
38374 }else if(k == e.ENTER){
38375 r = this.doc.selection.createRange();
38377 var target = r.parentElement();
38378 if(!target || target.tagName.toLowerCase() != 'li'){
38380 r.pasteHTML('<br />');
38387 }else if(Roo.isOpera){
38388 return function(e){
38389 var k = e.getKey();
38393 this.execCmd('InsertHTML','    ');
38397 }else if(Roo.isSafari){
38398 return function(e){
38399 var k = e.getKey();
38402 this.execCmd('InsertText','\t');
38409 getAllAncestors: function()
38411 var p = this.getSelectedNode();
38414 a.push(p); // push blank onto stack..
38415 p = this.getParentElement();
38419 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38423 a.push(this.doc.body);
38427 lastSelNode : false,
38430 getSelection : function()
38432 this.assignDocWin();
38433 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38436 getSelectedNode: function()
38438 // this may only work on Gecko!!!
38440 // should we cache this!!!!
38445 var range = this.createRange(this.getSelection());
38448 var parent = range.parentElement();
38450 var testRange = range.duplicate();
38451 testRange.moveToElementText(parent);
38452 if (testRange.inRange(range)) {
38455 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
38458 parent = parent.parentElement;
38464 var ar = range.endContainer.childNodes;
38466 ar = range.commonAncestorContainer.childNodes;
38467 //alert(ar.length);
38470 var other_nodes = [];
38471 var has_other_nodes = false;
38472 for (var i=0;i<ar.length;i++) {
38473 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
38476 // fullly contained node.
38478 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
38483 // probably selected..
38484 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
38485 other_nodes.push(ar[i]);
38488 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
38493 has_other_nodes = true;
38495 if (!nodes.length && other_nodes.length) {
38496 nodes= other_nodes;
38498 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
38504 createRange: function(sel)
38506 // this has strange effects when using with
38507 // top toolbar - not sure if it's a great idea.
38508 //this.editor.contentWindow.focus();
38509 if (typeof sel != "undefined") {
38511 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
38513 return this.doc.createRange();
38516 return this.doc.createRange();
38519 getParentElement: function()
38522 this.assignDocWin();
38523 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
38525 var range = this.createRange(sel);
38528 var p = range.commonAncestorContainer;
38529 while (p.nodeType == 3) { // text node
38541 // BC Hacks - cause I cant work out what i was trying to do..
38542 rangeIntersectsNode : function(range, node)
38544 var nodeRange = node.ownerDocument.createRange();
38546 nodeRange.selectNode(node);
38549 nodeRange.selectNodeContents(node);
38552 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
38553 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
38555 rangeCompareNode : function(range, node) {
38556 var nodeRange = node.ownerDocument.createRange();
38558 nodeRange.selectNode(node);
38560 nodeRange.selectNodeContents(node);
38562 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
38563 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
38565 if (nodeIsBefore && !nodeIsAfter)
38567 if (!nodeIsBefore && nodeIsAfter)
38569 if (nodeIsBefore && nodeIsAfter)
38577 // hide stuff that is not compatible
38591 * @event specialkey
38595 * @cfg {String} fieldClass @hide
38598 * @cfg {String} focusClass @hide
38601 * @cfg {String} autoCreate @hide
38604 * @cfg {String} inputType @hide
38607 * @cfg {String} invalidClass @hide
38610 * @cfg {String} invalidText @hide
38613 * @cfg {String} msgFx @hide
38616 * @cfg {String} validateOnBlur @hide
38618 });// <script type="text/javascript">
38621 * Ext JS Library 1.1.1
38622 * Copyright(c) 2006-2007, Ext JS, LLC.
38628 * @class Roo.form.HtmlEditorToolbar1
38633 new Roo.form.HtmlEditor({
38636 new Roo.form.HtmlEditorToolbar1({
38637 disable : { fonts: 1 , format: 1, ..., ... , ...],
38643 * @cfg {Object} disable List of elements to disable..
38644 * @cfg {Array} btns List of additional buttons.
38648 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
38651 Roo.form.HtmlEditor.ToolbarStandard = function(config)
38654 Roo.apply(this, config);
38655 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
38656 // dont call parent... till later.
38659 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
38667 * @cfg {Object} disable List of toolbar elements to disable
38672 * @cfg {Array} fontFamilies An array of available font families
38690 // "á" , ?? a acute?
38695 "°" // , // degrees
38697 // "é" , // e ecute
38698 // "ú" , // u ecute?
38701 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
38702 "input:submit", "input:button", "select", "textarea", "label" ],
38705 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
38707 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
38710 * @cfg {String} defaultFont default font to use.
38712 defaultFont: 'tahoma',
38714 fontSelect : false,
38717 formatCombo : false,
38719 init : function(editor)
38721 this.editor = editor;
38724 var fid = editor.frameId;
38726 function btn(id, toggle, handler){
38727 var xid = fid + '-'+ id ;
38731 cls : 'x-btn-icon x-edit-'+id,
38732 enableToggle:toggle !== false,
38733 scope: editor, // was editor...
38734 handler:handler||editor.relayBtnCmd,
38735 clickEvent:'mousedown',
38736 tooltip: etb.buttonTips[id] || undefined, ///tips ???
38743 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
38745 // stop form submits
38746 tb.el.on('click', function(e){
38747 e.preventDefault(); // what does this do?
38750 if(!this.disable.font && !Roo.isSafari){
38751 /* why no safari for fonts
38752 editor.fontSelect = tb.el.createChild({
38755 cls:'x-font-select',
38756 html: editor.createFontOptions()
38758 editor.fontSelect.on('change', function(){
38759 var font = editor.fontSelect.dom.value;
38760 editor.relayCmd('fontname', font);
38761 editor.deferFocus();
38764 editor.fontSelect.dom,
38769 if(!this.disable.formats){
38770 this.formatCombo = new Roo.form.ComboBox({
38771 store: new Roo.data.SimpleStore({
38774 data : this.formats // from states.js
38777 //autoCreate : {tag: "div", size: "20"},
38778 displayField:'tag',
38782 triggerAction: 'all',
38783 emptyText:'Add tag',
38784 selectOnFocus:true,
38787 'select': function(c, r, i) {
38788 editor.insertTag(r.get('tag'));
38794 tb.addField(this.formatCombo);
38798 if(!this.disable.format){
38805 if(!this.disable.fontSize){
38810 btn('increasefontsize', false, editor.adjustFont),
38811 btn('decreasefontsize', false, editor.adjustFont)
38816 if(this.disable.colors){
38819 id:editor.frameId +'-forecolor',
38820 cls:'x-btn-icon x-edit-forecolor',
38821 clickEvent:'mousedown',
38822 tooltip: this.buttonTips['forecolor'] || undefined,
38824 menu : new Roo.menu.ColorMenu({
38825 allowReselect: true,
38826 focus: Roo.emptyFn,
38829 selectHandler: function(cp, color){
38830 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
38831 editor.deferFocus();
38834 clickEvent:'mousedown'
38837 id:editor.frameId +'backcolor',
38838 cls:'x-btn-icon x-edit-backcolor',
38839 clickEvent:'mousedown',
38840 tooltip: this.buttonTips['backcolor'] || undefined,
38842 menu : new Roo.menu.ColorMenu({
38843 focus: Roo.emptyFn,
38846 allowReselect: true,
38847 selectHandler: function(cp, color){
38849 editor.execCmd('useCSS', false);
38850 editor.execCmd('hilitecolor', color);
38851 editor.execCmd('useCSS', true);
38852 editor.deferFocus();
38854 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
38855 Roo.isSafari || Roo.isIE ? '#'+color : color);
38856 editor.deferFocus();
38860 clickEvent:'mousedown'
38865 // now add all the items...
38868 if(!this.disable.alignments){
38871 btn('justifyleft'),
38872 btn('justifycenter'),
38873 btn('justifyright')
38877 //if(!Roo.isSafari){
38878 if(!this.disable.links){
38881 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
38885 if(!this.disable.lists){
38888 btn('insertorderedlist'),
38889 btn('insertunorderedlist')
38892 if(!this.disable.sourceEdit){
38895 btn('sourceedit', true, function(btn){
38896 this.toggleSourceEdit(btn.pressed);
38903 // special menu.. - needs to be tidied up..
38904 if (!this.disable.special) {
38907 cls: 'x-edit-none',
38912 for (var i =0; i < this.specialChars.length; i++) {
38913 smenu.menu.items.push({
38915 text: this.specialChars[i],
38916 handler: function(a,b) {
38917 editor.insertAtCursor(String.fromCharCode(a.text.replace('&#','').replace(';', '')));
38929 for(var i =0; i< this.btns.length;i++) {
38930 var b = this.btns[i];
38931 b.cls = 'x-edit-none';
38940 // disable everything...
38942 this.tb.items.each(function(item){
38943 if(item.id != editor.frameId+ '-sourceedit'){
38947 this.rendered = true;
38949 // the all the btns;
38950 editor.on('editorevent', this.updateToolbar, this);
38951 // other toolbars need to implement this..
38952 //editor.on('editmodechange', this.updateToolbar, this);
38958 * Protected method that will not generally be called directly. It triggers
38959 * a toolbar update by reading the markup state of the current selection in the editor.
38961 updateToolbar: function(){
38963 if(!this.editor.activated){
38964 this.editor.onFirstFocus();
38968 var btns = this.tb.items.map,
38969 doc = this.editor.doc,
38970 frameId = this.editor.frameId;
38972 if(!this.disable.font && !Roo.isSafari){
38974 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
38975 if(name != this.fontSelect.dom.value){
38976 this.fontSelect.dom.value = name;
38980 if(!this.disable.format){
38981 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
38982 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
38983 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
38985 if(!this.disable.alignments){
38986 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
38987 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
38988 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
38990 if(!Roo.isSafari && !this.disable.lists){
38991 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
38992 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
38995 var ans = this.editor.getAllAncestors();
38996 if (this.formatCombo) {
38999 var store = this.formatCombo.store;
39000 this.formatCombo.setValue("");
39001 for (var i =0; i < ans.length;i++) {
39002 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), true).length) {
39004 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39012 // hides menus... - so this cant be on a menu...
39013 Roo.menu.MenuMgr.hideAll();
39015 //this.editorsyncValue();
39019 createFontOptions : function(){
39020 var buf = [], fs = this.fontFamilies, ff, lc;
39021 for(var i = 0, len = fs.length; i< len; i++){
39023 lc = ff.toLowerCase();
39025 '<option value="',lc,'" style="font-family:',ff,';"',
39026 (this.defaultFont == lc ? ' selected="true">' : '>'),
39031 return buf.join('');
39034 toggleSourceEdit : function(sourceEditMode){
39035 if(sourceEditMode === undefined){
39036 sourceEditMode = !this.sourceEditMode;
39038 this.sourceEditMode = sourceEditMode === true;
39039 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39040 // just toggle the button?
39041 if(btn.pressed !== this.editor.sourceEditMode){
39042 btn.toggle(this.editor.sourceEditMode);
39046 if(this.sourceEditMode){
39047 this.tb.items.each(function(item){
39048 if(item.cmd != 'sourceedit'){
39054 if(this.initialized){
39055 this.tb.items.each(function(item){
39061 // tell the editor that it's been pressed..
39062 this.editor.toggleSourceEdit(sourceEditMode);
39066 * Object collection of toolbar tooltips for the buttons in the editor. The key
39067 * is the command id associated with that button and the value is a valid QuickTips object.
39072 title: 'Bold (Ctrl+B)',
39073 text: 'Make the selected text bold.',
39074 cls: 'x-html-editor-tip'
39077 title: 'Italic (Ctrl+I)',
39078 text: 'Make the selected text italic.',
39079 cls: 'x-html-editor-tip'
39087 title: 'Bold (Ctrl+B)',
39088 text: 'Make the selected text bold.',
39089 cls: 'x-html-editor-tip'
39092 title: 'Italic (Ctrl+I)',
39093 text: 'Make the selected text italic.',
39094 cls: 'x-html-editor-tip'
39097 title: 'Underline (Ctrl+U)',
39098 text: 'Underline the selected text.',
39099 cls: 'x-html-editor-tip'
39101 increasefontsize : {
39102 title: 'Grow Text',
39103 text: 'Increase the font size.',
39104 cls: 'x-html-editor-tip'
39106 decreasefontsize : {
39107 title: 'Shrink Text',
39108 text: 'Decrease the font size.',
39109 cls: 'x-html-editor-tip'
39112 title: 'Text Highlight Color',
39113 text: 'Change the background color of the selected text.',
39114 cls: 'x-html-editor-tip'
39117 title: 'Font Color',
39118 text: 'Change the color of the selected text.',
39119 cls: 'x-html-editor-tip'
39122 title: 'Align Text Left',
39123 text: 'Align text to the left.',
39124 cls: 'x-html-editor-tip'
39127 title: 'Center Text',
39128 text: 'Center text in the editor.',
39129 cls: 'x-html-editor-tip'
39132 title: 'Align Text Right',
39133 text: 'Align text to the right.',
39134 cls: 'x-html-editor-tip'
39136 insertunorderedlist : {
39137 title: 'Bullet List',
39138 text: 'Start a bulleted list.',
39139 cls: 'x-html-editor-tip'
39141 insertorderedlist : {
39142 title: 'Numbered List',
39143 text: 'Start a numbered list.',
39144 cls: 'x-html-editor-tip'
39147 title: 'Hyperlink',
39148 text: 'Make the selected text a hyperlink.',
39149 cls: 'x-html-editor-tip'
39152 title: 'Source Edit',
39153 text: 'Switch to source editing mode.',
39154 cls: 'x-html-editor-tip'
39158 onDestroy : function(){
39161 this.tb.items.each(function(item){
39163 item.menu.removeAll();
39165 item.menu.el.destroy();
39173 onFirstFocus: function() {
39174 this.tb.items.each(function(item){
39183 // <script type="text/javascript">
39186 * Ext JS Library 1.1.1
39187 * Copyright(c) 2006-2007, Ext JS, LLC.
39194 * @class Roo.form.HtmlEditor.ToolbarContext
39199 new Roo.form.HtmlEditor({
39202 new Roo.form.HtmlEditor.ToolbarStandard(),
39203 new Roo.form.HtmlEditor.ToolbarContext()
39208 * @config : {Object} disable List of elements to disable.. (not done yet.)
39213 Roo.form.HtmlEditor.ToolbarContext = function(config)
39216 Roo.apply(this, config);
39217 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39218 // dont call parent... till later.
39220 Roo.form.HtmlEditor.ToolbarContext.types = {
39232 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39294 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
39299 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
39363 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
39371 * @cfg {Object} disable List of toolbar elements to disable
39380 init : function(editor)
39382 this.editor = editor;
39385 var fid = editor.frameId;
39387 function btn(id, toggle, handler){
39388 var xid = fid + '-'+ id ;
39392 cls : 'x-btn-icon x-edit-'+id,
39393 enableToggle:toggle !== false,
39394 scope: editor, // was editor...
39395 handler:handler||editor.relayBtnCmd,
39396 clickEvent:'mousedown',
39397 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39401 // create a new element.
39402 var wdiv = editor.wrap.createChild({
39404 }, editor.wrap.dom.firstChild.nextSibling, true);
39406 // can we do this more than once??
39408 // stop form submits
39411 // disable everything...
39412 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39413 this.toolbars = {};
39415 for (var i in ty) {
39416 this.toolbars[i] = this.buildToolbar(ty[i],i);
39418 this.tb = this.toolbars.BODY;
39422 this.rendered = true;
39424 // the all the btns;
39425 editor.on('editorevent', this.updateToolbar, this);
39426 // other toolbars need to implement this..
39427 //editor.on('editmodechange', this.updateToolbar, this);
39433 * Protected method that will not generally be called directly. It triggers
39434 * a toolbar update by reading the markup state of the current selection in the editor.
39436 updateToolbar: function(){
39438 if(!this.editor.activated){
39439 this.editor.onFirstFocus();
39444 var ans = this.editor.getAllAncestors();
39447 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39448 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
39449 sel = sel ? sel : this.editor.doc.body;
39450 sel = sel.tagName.length ? sel : this.editor.doc.body;
39451 var tn = sel.tagName.toUpperCase();
39452 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
39453 tn = sel.tagName.toUpperCase();
39454 if (this.tb.name == tn) {
39455 return; // no change
39458 ///console.log("show: " + tn);
39459 this.tb = this.toolbars[tn];
39461 this.tb.fields.each(function(e) {
39462 e.setValue(sel.getAttribute(e.name));
39464 this.tb.selectedNode = sel;
39467 Roo.menu.MenuMgr.hideAll();
39469 //this.editorsyncValue();
39474 onDestroy : function(){
39477 this.tb.items.each(function(item){
39479 item.menu.removeAll();
39481 item.menu.el.destroy();
39489 onFirstFocus: function() {
39490 // need to do this for all the toolbars..
39491 this.tb.items.each(function(item){
39495 buildToolbar: function(tlist, nm)
39497 var editor = this.editor;
39498 // create a new element.
39499 var wdiv = editor.wrap.createChild({
39501 }, editor.wrap.dom.firstChild.nextSibling, true);
39504 var tb = new Roo.Toolbar(wdiv);
39505 tb.add(nm+ ": ");
39506 for (var i in tlist) {
39507 var item = tlist[i];
39508 tb.add(item.title + ": ");
39513 tb.addField( new Roo.form.ComboBox({
39514 store: new Roo.data.SimpleStore({
39517 data : item.opts // from states.js
39520 displayField:'val',
39524 triggerAction: 'all',
39525 emptyText:'Select',
39526 selectOnFocus:true,
39527 width: item.width ? item.width : 130,
39529 'select': function(c, r, i) {
39530 tb.selectedNode.setAttribute(c.name, r.get('val'));
39541 tb.addField( new Roo.form.TextField({
39544 //allowBlank:false,
39549 tb.addField( new Roo.form.TextField({
39555 'change' : function(f, nv, ov) {
39556 tb.selectedNode.setAttribute(f.name, nv);
39562 tb.el.on('click', function(e){
39563 e.preventDefault(); // what does this do?
39565 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
39568 // dont need to disable them... as they will get hidden
39585 * Ext JS Library 1.1.1
39586 * Copyright(c) 2006-2007, Ext JS, LLC.
39588 * Originally Released Under LGPL - original licence link has changed is not relivant.
39591 * <script type="text/javascript">
39595 * @class Roo.form.BasicForm
39596 * @extends Roo.util.Observable
39597 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
39599 * @param {String/HTMLElement/Roo.Element} el The form element or its id
39600 * @param {Object} config Configuration options
39602 Roo.form.BasicForm = function(el, config){
39603 Roo.apply(this, config);
39605 * The Roo.form.Field items in this form.
39606 * @type MixedCollection
39608 this.items = new Roo.util.MixedCollection(false, function(o){
39609 return o.id || (o.id = Roo.id());
39613 * @event beforeaction
39614 * Fires before any action is performed. Return false to cancel the action.
39615 * @param {Form} this
39616 * @param {Action} action The action to be performed
39618 beforeaction: true,
39620 * @event actionfailed
39621 * Fires when an action fails.
39622 * @param {Form} this
39623 * @param {Action} action The action that failed
39625 actionfailed : true,
39627 * @event actioncomplete
39628 * Fires when an action is completed.
39629 * @param {Form} this
39630 * @param {Action} action The action that completed
39632 actioncomplete : true
39637 Roo.form.BasicForm.superclass.constructor.call(this);
39640 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
39642 * @cfg {String} method
39643 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
39646 * @cfg {DataReader} reader
39647 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
39648 * This is optional as there is built-in support for processing JSON.
39651 * @cfg {DataReader} errorReader
39652 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
39653 * This is completely optional as there is built-in support for processing JSON.
39656 * @cfg {String} url
39657 * The URL to use for form actions if one isn't supplied in the action options.
39660 * @cfg {Boolean} fileUpload
39661 * Set to true if this form is a file upload.
39664 * @cfg {Object} baseParams
39665 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
39668 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
39673 activeAction : null,
39676 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
39677 * or setValues() data instead of when the form was first created.
39679 trackResetOnLoad : false,
39682 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
39683 * element by passing it or its id or mask the form itself by passing in true.
39686 waitMsgTarget : undefined,
39689 initEl : function(el){
39690 this.el = Roo.get(el);
39691 this.id = this.el.id || Roo.id();
39692 this.el.on('submit', this.onSubmit, this);
39693 this.el.addClass('x-form');
39697 onSubmit : function(e){
39702 * Returns true if client-side validation on the form is successful.
39705 isValid : function(){
39707 this.items.each(function(f){
39716 * Returns true if any fields in this form have changed since their original load.
39719 isDirty : function(){
39721 this.items.each(function(f){
39731 * Performs a predefined action (submit or load) or custom actions you define on this form.
39732 * @param {String} actionName The name of the action type
39733 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
39734 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
39735 * accept other config options):
39737 Property Type Description
39738 ---------------- --------------- ----------------------------------------------------------------------------------
39739 url String The url for the action (defaults to the form's url)
39740 method String The form method to use (defaults to the form's method, or POST if not defined)
39741 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
39742 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
39743 validate the form on the client (defaults to false)
39745 * @return {BasicForm} this
39747 doAction : function(action, options){
39748 if(typeof action == 'string'){
39749 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
39751 if(this.fireEvent('beforeaction', this, action) !== false){
39752 this.beforeAction(action);
39753 action.run.defer(100, action);
39759 * Shortcut to do a submit action.
39760 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39761 * @return {BasicForm} this
39763 submit : function(options){
39764 this.doAction('submit', options);
39769 * Shortcut to do a load action.
39770 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39771 * @return {BasicForm} this
39773 load : function(options){
39774 this.doAction('load', options);
39779 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
39780 * @param {Record} record The record to edit
39781 * @return {BasicForm} this
39783 updateRecord : function(record){
39784 record.beginEdit();
39785 var fs = record.fields;
39786 fs.each(function(f){
39787 var field = this.findField(f.name);
39789 record.set(f.name, field.getValue());
39797 * Loads an Roo.data.Record into this form.
39798 * @param {Record} record The record to load
39799 * @return {BasicForm} this
39801 loadRecord : function(record){
39802 this.setValues(record.data);
39807 beforeAction : function(action){
39808 var o = action.options;
39810 if(this.waitMsgTarget === true){
39811 this.el.mask(o.waitMsg, 'x-mask-loading');
39812 }else if(this.waitMsgTarget){
39813 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
39814 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
39816 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
39822 afterAction : function(action, success){
39823 this.activeAction = null;
39824 var o = action.options;
39826 if(this.waitMsgTarget === true){
39828 }else if(this.waitMsgTarget){
39829 this.waitMsgTarget.unmask();
39831 Roo.MessageBox.updateProgress(1);
39832 Roo.MessageBox.hide();
39839 Roo.callback(o.success, o.scope, [this, action]);
39840 this.fireEvent('actioncomplete', this, action);
39842 Roo.callback(o.failure, o.scope, [this, action]);
39843 this.fireEvent('actionfailed', this, action);
39848 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
39849 * @param {String} id The value to search for
39852 findField : function(id){
39853 var field = this.items.get(id);
39855 this.items.each(function(f){
39856 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
39862 return field || null;
39867 * Mark fields in this form invalid in bulk.
39868 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
39869 * @return {BasicForm} this
39871 markInvalid : function(errors){
39872 if(errors instanceof Array){
39873 for(var i = 0, len = errors.length; i < len; i++){
39874 var fieldError = errors[i];
39875 var f = this.findField(fieldError.id);
39877 f.markInvalid(fieldError.msg);
39883 if(typeof errors[id] != 'function' && (field = this.findField(id))){
39884 field.markInvalid(errors[id]);
39892 * Set values for fields in this form in bulk.
39893 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
39894 * @return {BasicForm} this
39896 setValues : function(values){
39897 if(values instanceof Array){ // array of objects
39898 for(var i = 0, len = values.length; i < len; i++){
39900 var f = this.findField(v.id);
39902 f.setValue(v.value);
39903 if(this.trackResetOnLoad){
39904 f.originalValue = f.getValue();
39908 }else{ // object hash
39911 if(typeof values[id] != 'function' && (field = this.findField(id))){
39913 if (field.setFromData &&
39914 field.valueField &&
39915 field.displayField &&
39916 // combos' with local stores can
39917 // be queried via setValue()
39918 // to set their value..
39919 (field.store && !field.store.isLocal)
39923 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
39924 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
39925 field.setFromData(sd);
39928 field.setValue(values[id]);
39932 if(this.trackResetOnLoad){
39933 field.originalValue = field.getValue();
39942 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
39943 * they are returned as an array.
39944 * @param {Boolean} asString
39947 getValues : function(asString){
39948 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
39949 if(asString === true){
39952 return Roo.urlDecode(fs);
39956 * Clears all invalid messages in this form.
39957 * @return {BasicForm} this
39959 clearInvalid : function(){
39960 this.items.each(function(f){
39967 * Resets this form.
39968 * @return {BasicForm} this
39970 reset : function(){
39971 this.items.each(function(f){
39978 * Add Roo.form components to this form.
39979 * @param {Field} field1
39980 * @param {Field} field2 (optional)
39981 * @param {Field} etc (optional)
39982 * @return {BasicForm} this
39985 this.items.addAll(Array.prototype.slice.call(arguments, 0));
39991 * Removes a field from the items collection (does NOT remove its markup).
39992 * @param {Field} field
39993 * @return {BasicForm} this
39995 remove : function(field){
39996 this.items.remove(field);
40001 * Looks at the fields in this form, checks them for an id attribute,
40002 * and calls applyTo on the existing dom element with that id.
40003 * @return {BasicForm} this
40005 render : function(){
40006 this.items.each(function(f){
40007 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40015 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40016 * @param {Object} values
40017 * @return {BasicForm} this
40019 applyToFields : function(o){
40020 this.items.each(function(f){
40027 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40028 * @param {Object} values
40029 * @return {BasicForm} this
40031 applyIfToFields : function(o){
40032 this.items.each(function(f){
40040 Roo.BasicForm = Roo.form.BasicForm;/*
40042 * Ext JS Library 1.1.1
40043 * Copyright(c) 2006-2007, Ext JS, LLC.
40045 * Originally Released Under LGPL - original licence link has changed is not relivant.
40048 * <script type="text/javascript">
40052 * @class Roo.form.Form
40053 * @extends Roo.form.BasicForm
40054 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40056 * @param {Object} config Configuration options
40058 Roo.form.Form = function(config){
40060 if (config.items) {
40061 xitems = config.items;
40062 delete config.items;
40066 Roo.form.Form.superclass.constructor.call(this, null, config);
40067 this.url = this.url || this.action;
40069 this.root = new Roo.form.Layout(Roo.applyIf({
40073 this.active = this.root;
40075 * Array of all the buttons that have been added to this form via {@link addButton}
40079 this.allItems = [];
40082 * @event clientvalidation
40083 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40084 * @param {Form} this
40085 * @param {Boolean} valid true if the form has passed client-side validation
40087 clientvalidation: true,
40090 * Fires when the form is rendered
40091 * @param {Roo.form.Form} form
40096 Roo.each(xitems, this.addxtype, this);
40102 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40104 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40107 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40110 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40112 buttonAlign:'center',
40115 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40120 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40121 * This property cascades to child containers if not set.
40126 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40127 * fires a looping event with that state. This is required to bind buttons to the valid
40128 * state using the config value formBind:true on the button.
40130 monitorValid : false,
40133 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40138 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40139 * fields are added and the column is closed. If no fields are passed the column remains open
40140 * until end() is called.
40141 * @param {Object} config The config to pass to the column
40142 * @param {Field} field1 (optional)
40143 * @param {Field} field2 (optional)
40144 * @param {Field} etc (optional)
40145 * @return Column The column container object
40147 column : function(c){
40148 var col = new Roo.form.Column(c);
40150 if(arguments.length > 1){ // duplicate code required because of Opera
40151 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40158 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40159 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40160 * until end() is called.
40161 * @param {Object} config The config to pass to the fieldset
40162 * @param {Field} field1 (optional)
40163 * @param {Field} field2 (optional)
40164 * @param {Field} etc (optional)
40165 * @return FieldSet The fieldset container object
40167 fieldset : function(c){
40168 var fs = new Roo.form.FieldSet(c);
40170 if(arguments.length > 1){ // duplicate code required because of Opera
40171 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40178 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
40179 * fields are added and the container is closed. If no fields are passed the container remains open
40180 * until end() is called.
40181 * @param {Object} config The config to pass to the Layout
40182 * @param {Field} field1 (optional)
40183 * @param {Field} field2 (optional)
40184 * @param {Field} etc (optional)
40185 * @return Layout The container object
40187 container : function(c){
40188 var l = new Roo.form.Layout(c);
40190 if(arguments.length > 1){ // duplicate code required because of Opera
40191 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40198 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
40199 * @param {Object} container A Roo.form.Layout or subclass of Layout
40200 * @return {Form} this
40202 start : function(c){
40203 // cascade label info
40204 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
40205 this.active.stack.push(c);
40206 c.ownerCt = this.active;
40212 * Closes the current open container
40213 * @return {Form} this
40216 if(this.active == this.root){
40219 this.active = this.active.ownerCt;
40224 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
40225 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
40226 * as the label of the field.
40227 * @param {Field} field1
40228 * @param {Field} field2 (optional)
40229 * @param {Field} etc. (optional)
40230 * @return {Form} this
40233 this.active.stack.push.apply(this.active.stack, arguments);
40234 this.allItems.push.apply(this.allItems,arguments);
40236 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
40237 if(a[i].isFormField){
40242 Roo.form.Form.superclass.add.apply(this, r);
40247 * Find any element that has been added to a form, using it's ID or name
40248 * This can include framesets, columns etc. along with regular fields..
40249 * @param {String} id - id or name to find.
40251 * @return {Element} e - or false if nothing found.
40253 findbyId : function(id)
40259 Ext.each(this.allItems, function(f){
40260 if (f.id == id || f.name == id ){
40271 * Render this form into the passed container. This should only be called once!
40272 * @param {String/HTMLElement/Element} container The element this component should be rendered into
40273 * @return {Form} this
40275 render : function(ct){
40277 var o = this.autoCreate || {
40279 method : this.method || 'POST',
40280 id : this.id || Roo.id()
40282 this.initEl(ct.createChild(o));
40284 this.root.render(this.el);
40286 this.items.each(function(f){
40287 f.render('x-form-el-'+f.id);
40290 if(this.buttons.length > 0){
40291 // tables are required to maintain order and for correct IE layout
40292 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
40293 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
40294 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
40296 var tr = tb.getElementsByTagName('tr')[0];
40297 for(var i = 0, len = this.buttons.length; i < len; i++) {
40298 var b = this.buttons[i];
40299 var td = document.createElement('td');
40300 td.className = 'x-form-btn-td';
40301 b.render(tr.appendChild(td));
40304 if(this.monitorValid){ // initialize after render
40305 this.startMonitoring();
40307 this.fireEvent('rendered', this);
40312 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
40313 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
40314 * object or a valid Roo.DomHelper element config
40315 * @param {Function} handler The function called when the button is clicked
40316 * @param {Object} scope (optional) The scope of the handler function
40317 * @return {Roo.Button}
40319 addButton : function(config, handler, scope){
40323 minWidth: this.minButtonWidth,
40326 if(typeof config == "string"){
40329 Roo.apply(bc, config);
40331 var btn = new Roo.Button(null, bc);
40332 this.buttons.push(btn);
40337 * Adds a series of form elements (using the xtype property as the factory method.
40338 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
40339 * @param {Object} config
40342 addxtype : function()
40344 var ar = Array.prototype.slice.call(arguments, 0);
40346 for(var i = 0; i < ar.length; i++) {
40348 continue; // skip -- if this happends something invalid got sent, we
40349 // should ignore it, as basically that interface element will not show up
40350 // and that should be pretty obvious!!
40353 if (Roo.form[ar[i].xtype]) {
40355 var fe = Roo.factory(ar[i], Roo.form);
40361 fe.store.form = this;
40366 this.allItems.push(fe);
40367 if (fe.items && fe.addxtype) {
40368 fe.addxtype.apply(fe, fe.items);
40378 // console.log('adding ' + ar[i].xtype);
40380 if (ar[i].xtype == 'Button') {
40381 //console.log('adding button');
40382 //console.log(ar[i]);
40383 this.addButton(ar[i]);
40384 this.allItems.push(fe);
40388 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
40389 alert('end is not supported on xtype any more, use items');
40391 // //console.log('adding end');
40399 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
40400 * option "monitorValid"
40402 startMonitoring : function(){
40405 Roo.TaskMgr.start({
40406 run : this.bindHandler,
40407 interval : this.monitorPoll || 200,
40414 * Stops monitoring of the valid state of this form
40416 stopMonitoring : function(){
40417 this.bound = false;
40421 bindHandler : function(){
40423 return false; // stops binding
40426 this.items.each(function(f){
40427 if(!f.isValid(true)){
40432 for(var i = 0, len = this.buttons.length; i < len; i++){
40433 var btn = this.buttons[i];
40434 if(btn.formBind === true && btn.disabled === valid){
40435 btn.setDisabled(!valid);
40438 this.fireEvent('clientvalidation', this, valid);
40452 Roo.Form = Roo.form.Form;
40455 * Ext JS Library 1.1.1
40456 * Copyright(c) 2006-2007, Ext JS, LLC.
40458 * Originally Released Under LGPL - original licence link has changed is not relivant.
40461 * <script type="text/javascript">
40465 * @class Roo.form.Action
40466 * Internal Class used to handle form actions
40468 * @param {Roo.form.BasicForm} el The form element or its id
40469 * @param {Object} config Configuration options
40473 // define the action interface
40474 Roo.form.Action = function(form, options){
40476 this.options = options || {};
40479 * Client Validation Failed
40482 Roo.form.Action.CLIENT_INVALID = 'client';
40484 * Server Validation Failed
40487 Roo.form.Action.SERVER_INVALID = 'server';
40489 * Connect to Server Failed
40492 Roo.form.Action.CONNECT_FAILURE = 'connect';
40494 * Reading Data from Server Failed
40497 Roo.form.Action.LOAD_FAILURE = 'load';
40499 Roo.form.Action.prototype = {
40501 failureType : undefined,
40502 response : undefined,
40503 result : undefined,
40505 // interface method
40506 run : function(options){
40510 // interface method
40511 success : function(response){
40515 // interface method
40516 handleResponse : function(response){
40520 // default connection failure
40521 failure : function(response){
40522 this.response = response;
40523 this.failureType = Roo.form.Action.CONNECT_FAILURE;
40524 this.form.afterAction(this, false);
40527 processResponse : function(response){
40528 this.response = response;
40529 if(!response.responseText){
40532 this.result = this.handleResponse(response);
40533 return this.result;
40536 // utility functions used internally
40537 getUrl : function(appendParams){
40538 var url = this.options.url || this.form.url || this.form.el.dom.action;
40540 var p = this.getParams();
40542 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
40548 getMethod : function(){
40549 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
40552 getParams : function(){
40553 var bp = this.form.baseParams;
40554 var p = this.options.params;
40556 if(typeof p == "object"){
40557 p = Roo.urlEncode(Roo.applyIf(p, bp));
40558 }else if(typeof p == 'string' && bp){
40559 p += '&' + Roo.urlEncode(bp);
40562 p = Roo.urlEncode(bp);
40567 createCallback : function(){
40569 success: this.success,
40570 failure: this.failure,
40572 timeout: (this.form.timeout*1000),
40573 upload: this.form.fileUpload ? this.success : undefined
40578 Roo.form.Action.Submit = function(form, options){
40579 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
40582 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
40586 var o = this.options;
40587 var method = this.getMethod();
40588 var isPost = method == 'POST';
40589 if(o.clientValidation === false || this.form.isValid()){
40590 Roo.Ajax.request(Roo.apply(this.createCallback(), {
40591 form:this.form.el.dom,
40592 url:this.getUrl(!isPost),
40594 params:isPost ? this.getParams() : null,
40595 isUpload: this.form.fileUpload
40598 }else if (o.clientValidation !== false){ // client validation failed
40599 this.failureType = Roo.form.Action.CLIENT_INVALID;
40600 this.form.afterAction(this, false);
40604 success : function(response){
40605 var result = this.processResponse(response);
40606 if(result === true || result.success){
40607 this.form.afterAction(this, true);
40611 this.form.markInvalid(result.errors);
40612 this.failureType = Roo.form.Action.SERVER_INVALID;
40614 this.form.afterAction(this, false);
40617 handleResponse : function(response){
40618 if(this.form.errorReader){
40619 var rs = this.form.errorReader.read(response);
40622 for(var i = 0, len = rs.records.length; i < len; i++) {
40623 var r = rs.records[i];
40624 errors[i] = r.data;
40627 if(errors.length < 1){
40631 success : rs.success,
40637 ret = Roo.decode(response.responseText);
40641 errorMsg: "Failed to read server message: " + response.responseText,
40651 Roo.form.Action.Load = function(form, options){
40652 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
40653 this.reader = this.form.reader;
40656 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
40660 Roo.Ajax.request(Roo.apply(
40661 this.createCallback(), {
40662 method:this.getMethod(),
40663 url:this.getUrl(false),
40664 params:this.getParams()
40668 success : function(response){
40669 var result = this.processResponse(response);
40670 if(result === true || !result.success || !result.data){
40671 this.failureType = Roo.form.Action.LOAD_FAILURE;
40672 this.form.afterAction(this, false);
40675 this.form.clearInvalid();
40676 this.form.setValues(result.data);
40677 this.form.afterAction(this, true);
40680 handleResponse : function(response){
40681 if(this.form.reader){
40682 var rs = this.form.reader.read(response);
40683 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
40685 success : rs.success,
40689 return Roo.decode(response.responseText);
40693 Roo.form.Action.ACTION_TYPES = {
40694 'load' : Roo.form.Action.Load,
40695 'submit' : Roo.form.Action.Submit
40698 * Ext JS Library 1.1.1
40699 * Copyright(c) 2006-2007, Ext JS, LLC.
40701 * Originally Released Under LGPL - original licence link has changed is not relivant.
40704 * <script type="text/javascript">
40708 * @class Roo.form.Layout
40709 * @extends Roo.Component
40710 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
40712 * @param {Object} config Configuration options
40714 Roo.form.Layout = function(config){
40716 if (config.items) {
40717 xitems = config.items;
40718 delete config.items;
40720 Roo.form.Layout.superclass.constructor.call(this, config);
40722 Roo.each(xitems, this.addxtype, this);
40726 Roo.extend(Roo.form.Layout, Roo.Component, {
40728 * @cfg {String/Object} autoCreate
40729 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
40732 * @cfg {String/Object/Function} style
40733 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
40734 * a function which returns such a specification.
40737 * @cfg {String} labelAlign
40738 * Valid values are "left," "top" and "right" (defaults to "left")
40741 * @cfg {Number} labelWidth
40742 * Fixed width in pixels of all field labels (defaults to undefined)
40745 * @cfg {Boolean} clear
40746 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
40750 * @cfg {String} labelSeparator
40751 * The separator to use after field labels (defaults to ':')
40753 labelSeparator : ':',
40755 * @cfg {Boolean} hideLabels
40756 * True to suppress the display of field labels in this layout (defaults to false)
40758 hideLabels : false,
40761 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
40766 onRender : function(ct, position){
40767 if(this.el){ // from markup
40768 this.el = Roo.get(this.el);
40769 }else { // generate
40770 var cfg = this.getAutoCreate();
40771 this.el = ct.createChild(cfg, position);
40774 this.el.applyStyles(this.style);
40776 if(this.labelAlign){
40777 this.el.addClass('x-form-label-'+this.labelAlign);
40779 if(this.hideLabels){
40780 this.labelStyle = "display:none";
40781 this.elementStyle = "padding-left:0;";
40783 if(typeof this.labelWidth == 'number'){
40784 this.labelStyle = "width:"+this.labelWidth+"px;";
40785 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
40787 if(this.labelAlign == 'top'){
40788 this.labelStyle = "width:auto;";
40789 this.elementStyle = "padding-left:0;";
40792 var stack = this.stack;
40793 var slen = stack.length;
40795 if(!this.fieldTpl){
40796 var t = new Roo.Template(
40797 '<div class="x-form-item {5}">',
40798 '<label for="{0}" style="{2}">{1}{4}</label>',
40799 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
40801 '</div><div class="x-form-clear-left"></div>'
40803 t.disableFormats = true;
40805 Roo.form.Layout.prototype.fieldTpl = t;
40807 for(var i = 0; i < slen; i++) {
40808 if(stack[i].isFormField){
40809 this.renderField(stack[i]);
40811 this.renderComponent(stack[i]);
40816 this.el.createChild({cls:'x-form-clear'});
40821 renderField : function(f){
40822 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
40825 f.labelStyle||this.labelStyle||'', //2
40826 this.elementStyle||'', //3
40827 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
40828 f.itemCls||this.itemCls||'' //5
40829 ], true).getPrevSibling());
40833 renderComponent : function(c){
40834 c.render(c.isLayout ? this.el : this.el.createChild());
40837 * Adds a object form elements (using the xtype property as the factory method.)
40838 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
40839 * @param {Object} config
40841 addxtype : function(o)
40843 // create the lement.
40844 o.form = this.form;
40845 var fe = Roo.factory(o, Roo.form);
40846 this.form.allItems.push(fe);
40847 this.stack.push(fe);
40849 if (fe.isFormField) {
40850 this.form.items.add(fe);
40858 * @class Roo.form.Column
40859 * @extends Roo.form.Layout
40860 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
40862 * @param {Object} config Configuration options
40864 Roo.form.Column = function(config){
40865 Roo.form.Column.superclass.constructor.call(this, config);
40868 Roo.extend(Roo.form.Column, Roo.form.Layout, {
40870 * @cfg {Number/String} width
40871 * The fixed width of the column in pixels or CSS value (defaults to "auto")
40874 * @cfg {String/Object} autoCreate
40875 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
40879 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
40882 onRender : function(ct, position){
40883 Roo.form.Column.superclass.onRender.call(this, ct, position);
40885 this.el.setWidth(this.width);
40892 * @class Roo.form.Row
40893 * @extends Roo.form.Layout
40894 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
40896 * @param {Object} config Configuration options
40900 Roo.form.Row = function(config){
40901 Roo.form.Row.superclass.constructor.call(this, config);
40904 Roo.extend(Roo.form.Row, Roo.form.Layout, {
40906 * @cfg {Number/String} width
40907 * The fixed width of the column in pixels or CSS value (defaults to "auto")
40910 * @cfg {Number/String} height
40911 * The fixed height of the column in pixels or CSS value (defaults to "auto")
40913 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
40917 onRender : function(ct, position){
40918 //console.log('row render');
40920 var t = new Roo.Template(
40921 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
40922 '<label for="{0}" style="{2}">{1}{4}</label>',
40923 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
40927 t.disableFormats = true;
40929 Roo.form.Layout.prototype.rowTpl = t;
40931 this.fieldTpl = this.rowTpl;
40933 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
40934 var labelWidth = 100;
40936 if ((this.labelAlign != 'top')) {
40937 if (typeof this.labelWidth == 'number') {
40938 labelWidth = this.labelWidth
40940 this.padWidth = 20 + labelWidth;
40944 Roo.form.Column.superclass.onRender.call(this, ct, position);
40946 this.el.setWidth(this.width);
40949 this.el.setHeight(this.height);
40954 renderField : function(f){
40955 f.fieldEl = this.fieldTpl.append(this.el, [
40956 f.id, f.fieldLabel,
40957 f.labelStyle||this.labelStyle||'',
40958 this.elementStyle||'',
40959 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
40960 f.itemCls||this.itemCls||'',
40961 f.width ? f.width + this.padWidth : 160 + this.padWidth
40968 * @class Roo.form.FieldSet
40969 * @extends Roo.form.Layout
40970 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
40972 * @param {Object} config Configuration options
40974 Roo.form.FieldSet = function(config){
40975 Roo.form.FieldSet.superclass.constructor.call(this, config);
40978 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
40980 * @cfg {String} legend
40981 * The text to display as the legend for the FieldSet (defaults to '')
40984 * @cfg {String/Object} autoCreate
40985 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
40989 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
40992 onRender : function(ct, position){
40993 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
40995 this.setLegend(this.legend);
41000 setLegend : function(text){
41002 this.el.child('legend').update(text);
41007 * Ext JS Library 1.1.1
41008 * Copyright(c) 2006-2007, Ext JS, LLC.
41010 * Originally Released Under LGPL - original licence link has changed is not relivant.
41013 * <script type="text/javascript">
41016 * @class Roo.form.VTypes
41017 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
41020 Roo.form.VTypes = function(){
41021 // closure these in so they are only created once.
41022 var alpha = /^[a-zA-Z_]+$/;
41023 var alphanum = /^[a-zA-Z0-9_]+$/;
41024 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
41025 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
41027 // All these messages and functions are configurable
41030 * The function used to validate email addresses
41031 * @param {String} value The email address
41033 'email' : function(v){
41034 return email.test(v);
41037 * The error text to display when the email validation function returns false
41040 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
41042 * The keystroke filter mask to be applied on email input
41045 'emailMask' : /[a-z0-9_\.\-@]/i,
41048 * The function used to validate URLs
41049 * @param {String} value The URL
41051 'url' : function(v){
41052 return url.test(v);
41055 * The error text to display when the url validation function returns false
41058 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
41061 * The function used to validate alpha values
41062 * @param {String} value The value
41064 'alpha' : function(v){
41065 return alpha.test(v);
41068 * The error text to display when the alpha validation function returns false
41071 'alphaText' : 'This field should only contain letters and _',
41073 * The keystroke filter mask to be applied on alpha input
41076 'alphaMask' : /[a-z_]/i,
41079 * The function used to validate alphanumeric values
41080 * @param {String} value The value
41082 'alphanum' : function(v){
41083 return alphanum.test(v);
41086 * The error text to display when the alphanumeric validation function returns false
41089 'alphanumText' : 'This field should only contain letters, numbers and _',
41091 * The keystroke filter mask to be applied on alphanumeric input
41094 'alphanumMask' : /[a-z0-9_]/i
41096 }();//<script type="text/javascript">
41099 * @class Roo.form.FCKeditor
41100 * @extends Roo.form.TextArea
41101 * Wrapper around the FCKEditor http://www.fckeditor.net
41103 * Creates a new FCKeditor
41104 * @param {Object} config Configuration options
41106 Roo.form.FCKeditor = function(config){
41107 Roo.form.FCKeditor.superclass.constructor.call(this, config);
41110 * @event editorinit
41111 * Fired when the editor is initialized - you can add extra handlers here..
41112 * @param {FCKeditor} this
41113 * @param {Object} the FCK object.
41120 Roo.form.FCKeditor.editors = { };
41121 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
41123 //defaultAutoCreate : {
41124 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
41128 * @cfg {Object} fck options - see fck manual for details.
41133 * @cfg {Object} fck toolbar set (Basic or Default)
41135 toolbarSet : 'Basic',
41137 * @cfg {Object} fck BasePath
41139 basePath : '/fckeditor/',
41147 onRender : function(ct, position)
41150 this.defaultAutoCreate = {
41152 style:"width:300px;height:60px;",
41153 autocomplete: "off"
41156 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
41159 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
41160 if(this.preventScrollbars){
41161 this.el.setStyle("overflow", "hidden");
41163 this.el.setHeight(this.growMin);
41166 //console.log('onrender' + this.getId() );
41167 Roo.form.FCKeditor.editors[this.getId()] = this;
41170 this.replaceTextarea() ;
41174 getEditor : function() {
41175 return this.fckEditor;
41178 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
41179 * @param {Mixed} value The value to set
41183 setValue : function(value)
41185 //console.log('setValue: ' + value);
41187 if(typeof(value) == 'undefined') { // not sure why this is happending...
41190 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41192 //if(!this.el || !this.getEditor()) {
41193 // this.value = value;
41194 //this.setValue.defer(100,this,[value]);
41198 if(!this.getEditor()) {
41202 this.getEditor().SetData(value);
41209 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
41210 * @return {Mixed} value The field value
41212 getValue : function()
41215 if (this.frame && this.frame.dom.style.display == 'none') {
41216 return Roo.form.FCKeditor.superclass.getValue.call(this);
41219 if(!this.el || !this.getEditor()) {
41221 // this.getValue.defer(100,this);
41226 var value=this.getEditor().GetData();
41227 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41228 return Roo.form.FCKeditor.superclass.getValue.call(this);
41234 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
41235 * @return {Mixed} value The field value
41237 getRawValue : function()
41239 if (this.frame && this.frame.dom.style.display == 'none') {
41240 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41243 if(!this.el || !this.getEditor()) {
41244 //this.getRawValue.defer(100,this);
41251 var value=this.getEditor().GetData();
41252 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
41253 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41257 setSize : function(w,h) {
41261 //if (this.frame && this.frame.dom.style.display == 'none') {
41262 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41265 //if(!this.el || !this.getEditor()) {
41266 // this.setSize.defer(100,this, [w,h]);
41272 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41274 this.frame.dom.setAttribute('width', w);
41275 this.frame.dom.setAttribute('height', h);
41276 this.frame.setSize(w,h);
41280 toggleSourceEdit : function(value) {
41284 this.el.dom.style.display = value ? '' : 'none';
41285 this.frame.dom.style.display = value ? 'none' : '';
41290 focus: function(tag)
41292 if (this.frame.dom.style.display == 'none') {
41293 return Roo.form.FCKeditor.superclass.focus.call(this);
41295 if(!this.el || !this.getEditor()) {
41296 this.focus.defer(100,this, [tag]);
41303 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
41304 this.getEditor().Focus();
41306 if (!this.getEditor().Selection.GetSelection()) {
41307 this.focus.defer(100,this, [tag]);
41312 var r = this.getEditor().EditorDocument.createRange();
41313 r.setStart(tgs[0],0);
41314 r.setEnd(tgs[0],0);
41315 this.getEditor().Selection.GetSelection().removeAllRanges();
41316 this.getEditor().Selection.GetSelection().addRange(r);
41317 this.getEditor().Focus();
41324 replaceTextarea : function()
41326 if ( document.getElementById( this.getId() + '___Frame' ) )
41328 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
41330 // We must check the elements firstly using the Id and then the name.
41331 var oTextarea = document.getElementById( this.getId() );
41333 var colElementsByName = document.getElementsByName( this.getId() ) ;
41335 oTextarea.style.display = 'none' ;
41337 if ( oTextarea.tabIndex ) {
41338 this.TabIndex = oTextarea.tabIndex ;
41341 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
41342 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
41343 this.frame = Roo.get(this.getId() + '___Frame')
41346 _getConfigHtml : function()
41350 for ( var o in this.fckconfig ) {
41351 sConfig += sConfig.length > 0 ? '&' : '';
41352 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
41355 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
41359 _getIFrameHtml : function()
41361 var sFile = 'fckeditor.html' ;
41362 /* no idea what this is about..
41365 if ( (/fcksource=true/i).test( window.top.location.search ) )
41366 sFile = 'fckeditor.original.html' ;
41371 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
41372 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
41375 var html = '<iframe id="' + this.getId() +
41376 '___Frame" src="' + sLink +
41377 '" width="' + this.width +
41378 '" height="' + this.height + '"' +
41379 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
41380 ' frameborder="0" scrolling="no"></iframe>' ;
41385 _insertHtmlBefore : function( html, element )
41387 if ( element.insertAdjacentHTML ) {
41389 element.insertAdjacentHTML( 'beforeBegin', html ) ;
41391 var oRange = document.createRange() ;
41392 oRange.setStartBefore( element ) ;
41393 var oFragment = oRange.createContextualFragment( html );
41394 element.parentNode.insertBefore( oFragment, element ) ;
41407 //Roo.reg('fckeditor', Roo.form.FCKeditor);
41409 function FCKeditor_OnComplete(editorInstance){
41410 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
41411 f.fckEditor = editorInstance;
41412 //console.log("loaded");
41413 f.fireEvent('editorinit', f, editorInstance);
41433 //<script type="text/javascript">
41435 * @class Roo.form.GridField
41436 * @extends Roo.form.Field
41437 * Embed a grid (or editable grid into a form)
41440 * Creates a new GridField
41441 * @param {Object} config Configuration options
41443 Roo.form.GridField = function(config){
41444 Roo.form.GridField.superclass.constructor.call(this, config);
41448 Roo.extend(Roo.form.GridField, Roo.form.Field, {
41450 * @cfg {Number} width - used to restrict width of grid..
41454 * @cfg {Number} height - used to restrict height of grid..
41458 * @cfg {Object} xgrid (xtype'd description of grid) Grid or EditorGrid
41462 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41463 * {tag: "input", type: "checkbox", autocomplete: "off"})
41465 // defaultAutoCreate : { tag: 'div' },
41466 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
41468 * @cfg {String} addTitle Text to include for adding a title.
41472 onResize : function(){
41473 Roo.form.Field.superclass.onResize.apply(this, arguments);
41476 initEvents : function(){
41477 // Roo.form.Checkbox.superclass.initEvents.call(this);
41478 // has no events...
41483 getResizeEl : function(){
41487 getPositionEl : function(){
41492 onRender : function(ct, position){
41494 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
41495 var style = this.style;
41498 Roo.form.DisplayImage.superclass.onRender.call(this, ct, position);
41499 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
41500 this.viewEl = this.wrap.createChild({ tag: 'div' });
41502 this.viewEl.applyStyles(style);
41505 this.viewEl.setWidth(this.width);
41508 this.viewEl.setHeight(this.height);
41510 //if(this.inputValue !== undefined){
41511 //this.setValue(this.value);
41514 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
41517 this.grid.render();
41518 this.grid.getDataSource().on('remove', this.refreshValue, this);
41519 this.grid.getDataSource().on('update', this.refreshValue, this);
41520 this.grid.on('afteredit', this.refreshValue, this);
41526 * Sets the value of the item.
41527 * @param {String} either an object or a string..
41529 setValue : function(v){
41531 v = v || []; // empty set..
41532 // this does not seem smart - it really only affects memoryproxy grids..
41533 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
41534 var ds = this.grid.getDataSource();
41535 // assumes a json reader..
41537 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
41538 ds.loadData( data);
41540 Roo.form.GridField.superclass.setValue.call(this, v);
41541 this.refreshValue();
41542 // should load data in the grid really....
41546 refreshValue: function() {
41548 this.grid.getDataSource().each(function(r) {
41551 this.el.dom.value = Roo.encode(val);
41557 });//<script type="text/javasscript">
41561 * @class Roo.DDView
41562 * A DnD enabled version of Roo.View.
41563 * @param {Element/String} container The Element in which to create the View.
41564 * @param {String} tpl The template string used to create the markup for each element of the View
41565 * @param {Object} config The configuration properties. These include all the config options of
41566 * {@link Roo.View} plus some specific to this class.<br>
41568 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
41569 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
41571 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
41572 .x-view-drag-insert-above {
41573 border-top:1px dotted #3366cc;
41575 .x-view-drag-insert-below {
41576 border-bottom:1px dotted #3366cc;
41582 Roo.DDView = function(container, tpl, config) {
41583 Roo.DDView.superclass.constructor.apply(this, arguments);
41584 this.getEl().setStyle("outline", "0px none");
41585 this.getEl().unselectable();
41586 if (this.dragGroup) {
41587 this.setDraggable(this.dragGroup.split(","));
41589 if (this.dropGroup) {
41590 this.setDroppable(this.dropGroup.split(","));
41592 if (this.deletable) {
41593 this.setDeletable();
41595 this.isDirtyFlag = false;
41601 Roo.extend(Roo.DDView, Roo.View, {
41602 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
41603 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
41604 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
41605 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
41609 reset: Roo.emptyFn,
41611 clearInvalid: Roo.form.Field.prototype.clearInvalid,
41613 validate: function() {
41617 destroy: function() {
41618 this.purgeListeners();
41619 this.getEl.removeAllListeners();
41620 this.getEl().remove();
41621 if (this.dragZone) {
41622 if (this.dragZone.destroy) {
41623 this.dragZone.destroy();
41626 if (this.dropZone) {
41627 if (this.dropZone.destroy) {
41628 this.dropZone.destroy();
41633 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
41634 getName: function() {
41638 /** Loads the View from a JSON string representing the Records to put into the Store. */
41639 setValue: function(v) {
41641 throw "DDView.setValue(). DDView must be constructed with a valid Store";
41644 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
41645 this.store.proxy = new Roo.data.MemoryProxy(data);
41649 /** @return {String} a parenthesised list of the ids of the Records in the View. */
41650 getValue: function() {
41652 this.store.each(function(rec) {
41653 result += rec.id + ',';
41655 return result.substr(0, result.length - 1) + ')';
41658 getIds: function() {
41659 var i = 0, result = new Array(this.store.getCount());
41660 this.store.each(function(rec) {
41661 result[i++] = rec.id;
41666 isDirty: function() {
41667 return this.isDirtyFlag;
41671 * Part of the Roo.dd.DropZone interface. If no target node is found, the
41672 * whole Element becomes the target, and this causes the drop gesture to append.
41674 getTargetFromEvent : function(e) {
41675 var target = e.getTarget();
41676 while ((target !== null) && (target.parentNode != this.el.dom)) {
41677 target = target.parentNode;
41680 target = this.el.dom.lastChild || this.el.dom;
41686 * Create the drag data which consists of an object which has the property "ddel" as
41687 * the drag proxy element.
41689 getDragData : function(e) {
41690 var target = this.findItemFromChild(e.getTarget());
41692 this.handleSelection(e);
41693 var selNodes = this.getSelectedNodes();
41696 copy: this.copy || (this.allowCopy && e.ctrlKey),
41700 var selectedIndices = this.getSelectedIndexes();
41701 for (var i = 0; i < selectedIndices.length; i++) {
41702 dragData.records.push(this.store.getAt(selectedIndices[i]));
41704 if (selNodes.length == 1) {
41705 dragData.ddel = target.cloneNode(true); // the div element
41707 var div = document.createElement('div'); // create the multi element drag "ghost"
41708 div.className = 'multi-proxy';
41709 for (var i = 0, len = selNodes.length; i < len; i++) {
41710 div.appendChild(selNodes[i].cloneNode(true));
41712 dragData.ddel = div;
41714 //console.log(dragData)
41715 //console.log(dragData.ddel.innerHTML)
41718 //console.log('nodragData')
41722 /** Specify to which ddGroup items in this DDView may be dragged. */
41723 setDraggable: function(ddGroup) {
41724 if (ddGroup instanceof Array) {
41725 Roo.each(ddGroup, this.setDraggable, this);
41728 if (this.dragZone) {
41729 this.dragZone.addToGroup(ddGroup);
41731 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
41732 containerScroll: true,
41736 // Draggability implies selection. DragZone's mousedown selects the element.
41737 if (!this.multiSelect) { this.singleSelect = true; }
41739 // Wire the DragZone's handlers up to methods in *this*
41740 this.dragZone.getDragData = this.getDragData.createDelegate(this);
41744 /** Specify from which ddGroup this DDView accepts drops. */
41745 setDroppable: function(ddGroup) {
41746 if (ddGroup instanceof Array) {
41747 Roo.each(ddGroup, this.setDroppable, this);
41750 if (this.dropZone) {
41751 this.dropZone.addToGroup(ddGroup);
41753 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
41754 containerScroll: true,
41758 // Wire the DropZone's handlers up to methods in *this*
41759 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
41760 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
41761 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
41762 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
41763 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
41767 /** Decide whether to drop above or below a View node. */
41768 getDropPoint : function(e, n, dd){
41769 if (n == this.el.dom) { return "above"; }
41770 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
41771 var c = t + (b - t) / 2;
41772 var y = Roo.lib.Event.getPageY(e);
41780 onNodeEnter : function(n, dd, e, data){
41784 onNodeOver : function(n, dd, e, data){
41785 var pt = this.getDropPoint(e, n, dd);
41786 // set the insert point style on the target node
41787 var dragElClass = this.dropNotAllowed;
41790 if (pt == "above"){
41791 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
41792 targetElClass = "x-view-drag-insert-above";
41794 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
41795 targetElClass = "x-view-drag-insert-below";
41797 if (this.lastInsertClass != targetElClass){
41798 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
41799 this.lastInsertClass = targetElClass;
41802 return dragElClass;
41805 onNodeOut : function(n, dd, e, data){
41806 this.removeDropIndicators(n);
41809 onNodeDrop : function(n, dd, e, data){
41810 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
41813 var pt = this.getDropPoint(e, n, dd);
41814 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
41815 if (pt == "below") { insertAt++; }
41816 for (var i = 0; i < data.records.length; i++) {
41817 var r = data.records[i];
41818 var dup = this.store.getById(r.id);
41819 if (dup && (dd != this.dragZone)) {
41820 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
41823 this.store.insert(insertAt++, r.copy());
41825 data.source.isDirtyFlag = true;
41827 this.store.insert(insertAt++, r);
41829 this.isDirtyFlag = true;
41832 this.dragZone.cachedTarget = null;
41836 removeDropIndicators : function(n){
41838 Roo.fly(n).removeClass([
41839 "x-view-drag-insert-above",
41840 "x-view-drag-insert-below"]);
41841 this.lastInsertClass = "_noclass";
41846 * Utility method. Add a delete option to the DDView's context menu.
41847 * @param {String} imageUrl The URL of the "delete" icon image.
41849 setDeletable: function(imageUrl) {
41850 if (!this.singleSelect && !this.multiSelect) {
41851 this.singleSelect = true;
41853 var c = this.getContextMenu();
41854 this.contextMenu.on("itemclick", function(item) {
41857 this.remove(this.getSelectedIndexes());
41861 this.contextMenu.add({
41868 /** Return the context menu for this DDView. */
41869 getContextMenu: function() {
41870 if (!this.contextMenu) {
41871 // Create the View's context menu
41872 this.contextMenu = new Roo.menu.Menu({
41873 id: this.id + "-contextmenu"
41875 this.el.on("contextmenu", this.showContextMenu, this);
41877 return this.contextMenu;
41880 disableContextMenu: function() {
41881 if (this.contextMenu) {
41882 this.el.un("contextmenu", this.showContextMenu, this);
41886 showContextMenu: function(e, item) {
41887 item = this.findItemFromChild(e.getTarget());
41890 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
41891 this.contextMenu.showAt(e.getXY());
41896 * Remove {@link Roo.data.Record}s at the specified indices.
41897 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
41899 remove: function(selectedIndices) {
41900 selectedIndices = [].concat(selectedIndices);
41901 for (var i = 0; i < selectedIndices.length; i++) {
41902 var rec = this.store.getAt(selectedIndices[i]);
41903 this.store.remove(rec);
41908 * Double click fires the event, but also, if this is draggable, and there is only one other
41909 * related DropZone, it transfers the selected node.
41911 onDblClick : function(e){
41912 var item = this.findItemFromChild(e.getTarget());
41914 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
41917 if (this.dragGroup) {
41918 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
41919 while (targets.indexOf(this.dropZone) > -1) {
41920 targets.remove(this.dropZone);
41922 if (targets.length == 1) {
41923 this.dragZone.cachedTarget = null;
41924 var el = Roo.get(targets[0].getEl());
41925 var box = el.getBox(true);
41926 targets[0].onNodeDrop(el.dom, {
41928 xy: [box.x, box.y + box.height - 1]
41929 }, null, this.getDragData(e));
41935 handleSelection: function(e) {
41936 this.dragZone.cachedTarget = null;
41937 var item = this.findItemFromChild(e.getTarget());
41939 this.clearSelections(true);
41942 if (item && (this.multiSelect || this.singleSelect)){
41943 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
41944 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
41945 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
41946 this.unselect(item);
41948 this.select(item, this.multiSelect && e.ctrlKey);
41949 this.lastSelection = item;
41954 onItemClick : function(item, index, e){
41955 if(this.fireEvent("beforeclick", this, index, item, e) === false){
41961 unselect : function(nodeInfo, suppressEvent){
41962 var node = this.getNode(nodeInfo);
41963 if(node && this.isSelected(node)){
41964 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
41965 Roo.fly(node).removeClass(this.selectedClass);
41966 this.selections.remove(node);
41967 if(!suppressEvent){
41968 this.fireEvent("selectionchange", this, this.selections);
41976 * Ext JS Library 1.1.1
41977 * Copyright(c) 2006-2007, Ext JS, LLC.
41979 * Originally Released Under LGPL - original licence link has changed is not relivant.
41982 * <script type="text/javascript">
41986 * @class Roo.LayoutManager
41987 * @extends Roo.util.Observable
41988 * Base class for layout managers.
41990 Roo.LayoutManager = function(container, config){
41991 Roo.LayoutManager.superclass.constructor.call(this);
41992 this.el = Roo.get(container);
41993 // ie scrollbar fix
41994 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
41995 document.body.scroll = "no";
41996 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
41997 this.el.position('relative');
41999 this.id = this.el.id;
42000 this.el.addClass("x-layout-container");
42001 /** false to disable window resize monitoring @type Boolean */
42002 this.monitorWindowResize = true;
42007 * Fires when a layout is performed.
42008 * @param {Roo.LayoutManager} this
42012 * @event regionresized
42013 * Fires when the user resizes a region.
42014 * @param {Roo.LayoutRegion} region The resized region
42015 * @param {Number} newSize The new size (width for east/west, height for north/south)
42017 "regionresized" : true,
42019 * @event regioncollapsed
42020 * Fires when a region is collapsed.
42021 * @param {Roo.LayoutRegion} region The collapsed region
42023 "regioncollapsed" : true,
42025 * @event regionexpanded
42026 * Fires when a region is expanded.
42027 * @param {Roo.LayoutRegion} region The expanded region
42029 "regionexpanded" : true
42031 this.updating = false;
42032 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
42035 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
42037 * Returns true if this layout is currently being updated
42038 * @return {Boolean}
42040 isUpdating : function(){
42041 return this.updating;
42045 * Suspend the LayoutManager from doing auto-layouts while
42046 * making multiple add or remove calls
42048 beginUpdate : function(){
42049 this.updating = true;
42053 * Restore auto-layouts and optionally disable the manager from performing a layout
42054 * @param {Boolean} noLayout true to disable a layout update
42056 endUpdate : function(noLayout){
42057 this.updating = false;
42063 layout: function(){
42067 onRegionResized : function(region, newSize){
42068 this.fireEvent("regionresized", region, newSize);
42072 onRegionCollapsed : function(region){
42073 this.fireEvent("regioncollapsed", region);
42076 onRegionExpanded : function(region){
42077 this.fireEvent("regionexpanded", region);
42081 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
42082 * performs box-model adjustments.
42083 * @return {Object} The size as an object {width: (the width), height: (the height)}
42085 getViewSize : function(){
42087 if(this.el.dom != document.body){
42088 size = this.el.getSize();
42090 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
42092 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
42093 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
42098 * Returns the Element this layout is bound to.
42099 * @return {Roo.Element}
42101 getEl : function(){
42106 * Returns the specified region.
42107 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
42108 * @return {Roo.LayoutRegion}
42110 getRegion : function(target){
42111 return this.regions[target.toLowerCase()];
42114 onWindowResize : function(){
42115 if(this.monitorWindowResize){
42121 * Ext JS Library 1.1.1
42122 * Copyright(c) 2006-2007, Ext JS, LLC.
42124 * Originally Released Under LGPL - original licence link has changed is not relivant.
42127 * <script type="text/javascript">
42130 * @class Roo.BorderLayout
42131 * @extends Roo.LayoutManager
42132 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
42133 * please see: <br><br>
42134 * <a href="http://www.jackslocum.com/yui/2006/10/19/cross-browser-web-20-layouts-with-yahoo-ui/">Cross Browser Layouts - Part 1</a><br>
42135 * <a href="http://www.jackslocum.com/yui/2006/10/28/cross-browser-web-20-layouts-part-2-ajax-feed-viewer-20/">Cross Browser Layouts - Part 2</a><br><br>
42138 var layout = new Roo.BorderLayout(document.body, {
42172 preferredTabWidth: 150
42177 var CP = Roo.ContentPanel;
42179 layout.beginUpdate();
42180 layout.add("north", new CP("north", "North"));
42181 layout.add("south", new CP("south", {title: "South", closable: true}));
42182 layout.add("west", new CP("west", {title: "West"}));
42183 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
42184 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
42185 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
42186 layout.getRegion("center").showPanel("center1");
42187 layout.endUpdate();
42190 <b>The container the layout is rendered into can be either the body element or any other element.
42191 If it is not the body element, the container needs to either be an absolute positioned element,
42192 or you will need to add "position:relative" to the css of the container. You will also need to specify
42193 the container size if it is not the body element.</b>
42196 * Create a new BorderLayout
42197 * @param {String/HTMLElement/Element} container The container this layout is bound to
42198 * @param {Object} config Configuration options
42200 Roo.BorderLayout = function(container, config){
42201 config = config || {};
42202 Roo.BorderLayout.superclass.constructor.call(this, container, config);
42203 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
42204 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
42205 var target = this.factory.validRegions[i];
42206 if(config[target]){
42207 this.addRegion(target, config[target]);
42212 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
42214 * Creates and adds a new region if it doesn't already exist.
42215 * @param {String} target The target region key (north, south, east, west or center).
42216 * @param {Object} config The regions config object
42217 * @return {BorderLayoutRegion} The new region
42219 addRegion : function(target, config){
42220 if(!this.regions[target]){
42221 var r = this.factory.create(target, this, config);
42222 this.bindRegion(target, r);
42224 return this.regions[target];
42228 bindRegion : function(name, r){
42229 this.regions[name] = r;
42230 r.on("visibilitychange", this.layout, this);
42231 r.on("paneladded", this.layout, this);
42232 r.on("panelremoved", this.layout, this);
42233 r.on("invalidated", this.layout, this);
42234 r.on("resized", this.onRegionResized, this);
42235 r.on("collapsed", this.onRegionCollapsed, this);
42236 r.on("expanded", this.onRegionExpanded, this);
42240 * Performs a layout update.
42242 layout : function(){
42243 if(this.updating) return;
42244 var size = this.getViewSize();
42245 var w = size.width;
42246 var h = size.height;
42251 //var x = 0, y = 0;
42253 var rs = this.regions;
42254 var north = rs["north"];
42255 var south = rs["south"];
42256 var west = rs["west"];
42257 var east = rs["east"];
42258 var center = rs["center"];
42259 //if(this.hideOnLayout){ // not supported anymore
42260 //c.el.setStyle("display", "none");
42262 if(north && north.isVisible()){
42263 var b = north.getBox();
42264 var m = north.getMargins();
42265 b.width = w - (m.left+m.right);
42268 centerY = b.height + b.y + m.bottom;
42269 centerH -= centerY;
42270 north.updateBox(this.safeBox(b));
42272 if(south && south.isVisible()){
42273 var b = south.getBox();
42274 var m = south.getMargins();
42275 b.width = w - (m.left+m.right);
42277 var totalHeight = (b.height + m.top + m.bottom);
42278 b.y = h - totalHeight + m.top;
42279 centerH -= totalHeight;
42280 south.updateBox(this.safeBox(b));
42282 if(west && west.isVisible()){
42283 var b = west.getBox();
42284 var m = west.getMargins();
42285 b.height = centerH - (m.top+m.bottom);
42287 b.y = centerY + m.top;
42288 var totalWidth = (b.width + m.left + m.right);
42289 centerX += totalWidth;
42290 centerW -= totalWidth;
42291 west.updateBox(this.safeBox(b));
42293 if(east && east.isVisible()){
42294 var b = east.getBox();
42295 var m = east.getMargins();
42296 b.height = centerH - (m.top+m.bottom);
42297 var totalWidth = (b.width + m.left + m.right);
42298 b.x = w - totalWidth + m.left;
42299 b.y = centerY + m.top;
42300 centerW -= totalWidth;
42301 east.updateBox(this.safeBox(b));
42304 var m = center.getMargins();
42306 x: centerX + m.left,
42307 y: centerY + m.top,
42308 width: centerW - (m.left+m.right),
42309 height: centerH - (m.top+m.bottom)
42311 //if(this.hideOnLayout){
42312 //center.el.setStyle("display", "block");
42314 center.updateBox(this.safeBox(centerBox));
42317 this.fireEvent("layout", this);
42321 safeBox : function(box){
42322 box.width = Math.max(0, box.width);
42323 box.height = Math.max(0, box.height);
42328 * Adds a ContentPanel (or subclass) to this layout.
42329 * @param {String} target The target region key (north, south, east, west or center).
42330 * @param {Roo.ContentPanel} panel The panel to add
42331 * @return {Roo.ContentPanel} The added panel
42333 add : function(target, panel){
42335 target = target.toLowerCase();
42336 return this.regions[target].add(panel);
42340 * Remove a ContentPanel (or subclass) to this layout.
42341 * @param {String} target The target region key (north, south, east, west or center).
42342 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
42343 * @return {Roo.ContentPanel} The removed panel
42345 remove : function(target, panel){
42346 target = target.toLowerCase();
42347 return this.regions[target].remove(panel);
42351 * Searches all regions for a panel with the specified id
42352 * @param {String} panelId
42353 * @return {Roo.ContentPanel} The panel or null if it wasn't found
42355 findPanel : function(panelId){
42356 var rs = this.regions;
42357 for(var target in rs){
42358 if(typeof rs[target] != "function"){
42359 var p = rs[target].getPanel(panelId);
42369 * Searches all regions for a panel with the specified id and activates (shows) it.
42370 * @param {String/ContentPanel} panelId The panels id or the panel itself
42371 * @return {Roo.ContentPanel} The shown panel or null
42373 showPanel : function(panelId) {
42374 var rs = this.regions;
42375 for(var target in rs){
42376 var r = rs[target];
42377 if(typeof r != "function"){
42378 if(r.hasPanel(panelId)){
42379 return r.showPanel(panelId);
42387 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
42388 * @param {Roo.state.Provider} provider (optional) An alternate state provider
42390 restoreState : function(provider){
42392 provider = Roo.state.Manager;
42394 var sm = new Roo.LayoutStateManager();
42395 sm.init(this, provider);
42399 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
42400 * object should contain properties for each region to add ContentPanels to, and each property's value should be
42401 * a valid ContentPanel config object. Example:
42403 // Create the main layout
42404 var layout = new Roo.BorderLayout('main-ct', {
42415 // Create and add multiple ContentPanels at once via configs
42418 id: 'source-files',
42420 title:'Ext Source Files',
42433 * @param {Object} regions An object containing ContentPanel configs by region name
42435 batchAdd : function(regions){
42436 this.beginUpdate();
42437 for(var rname in regions){
42438 var lr = this.regions[rname];
42440 this.addTypedPanels(lr, regions[rname]);
42447 addTypedPanels : function(lr, ps){
42448 if(typeof ps == 'string'){
42449 lr.add(new Roo.ContentPanel(ps));
42451 else if(ps instanceof Array){
42452 for(var i =0, len = ps.length; i < len; i++){
42453 this.addTypedPanels(lr, ps[i]);
42456 else if(!ps.events){ // raw config?
42458 delete ps.el; // prevent conflict
42459 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
42461 else { // panel object assumed!
42466 * Adds a xtype elements to the layout.
42470 xtype : 'ContentPanel',
42477 xtype : 'NestedLayoutPanel',
42483 items : [ ... list of content panels or nested layout panels.. ]
42487 * @param {Object} cfg Xtype definition of item to add.
42489 addxtype : function(cfg)
42491 // basically accepts a pannel...
42492 // can accept a layout region..!?!?
42493 // console.log('BorderLayout add ' + cfg.xtype)
42495 if (!cfg.xtype.match(/Panel$/)) {
42499 var region = cfg.region;
42505 xitems = cfg.items;
42512 case 'ContentPanel': // ContentPanel (el, cfg)
42513 if(cfg.autoCreate) {
42514 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42516 var el = this.el.createChild();
42517 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
42520 this.add(region, ret);
42524 case 'TreePanel': // our new panel!
42525 cfg.el = this.el.createChild();
42526 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42527 this.add(region, ret);
42530 case 'NestedLayoutPanel':
42531 // create a new Layout (which is a Border Layout...
42532 var el = this.el.createChild();
42533 var clayout = cfg.layout;
42535 clayout.items = clayout.items || [];
42536 // replace this exitems with the clayout ones..
42537 xitems = clayout.items;
42540 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
42541 cfg.background = false;
42543 var layout = new Roo.BorderLayout(el, clayout);
42545 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
42546 //console.log('adding nested layout panel ' + cfg.toSource());
42547 this.add(region, ret);
42553 // needs grid and region
42555 //var el = this.getRegion(region).el.createChild();
42556 var el = this.el.createChild();
42557 // create the grid first...
42559 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
42561 if (region == 'center' && this.active ) {
42562 cfg.background = false;
42564 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
42566 this.add(region, ret);
42567 if (cfg.background) {
42568 ret.on('activate', function(gp) {
42569 if (!gp.grid.rendered) {
42582 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
42584 // GridPanel (grid, cfg)
42587 this.beginUpdate();
42589 Roo.each(xitems, function(i) {
42599 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
42600 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
42601 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
42602 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
42605 var CP = Roo.ContentPanel;
42607 var layout = Roo.BorderLayout.create({
42611 panels: [new CP("north", "North")]
42620 panels: [new CP("west", {title: "West"})]
42629 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
42638 panels: [new CP("south", {title: "South", closable: true})]
42645 preferredTabWidth: 150,
42647 new CP("center1", {title: "Close Me", closable: true}),
42648 new CP("center2", {title: "Center Panel", closable: false})
42653 layout.getRegion("center").showPanel("center1");
42658 Roo.BorderLayout.create = function(config, targetEl){
42659 var layout = new Roo.BorderLayout(targetEl || document.body, config);
42660 layout.beginUpdate();
42661 var regions = Roo.BorderLayout.RegionFactory.validRegions;
42662 for(var j = 0, jlen = regions.length; j < jlen; j++){
42663 var lr = regions[j];
42664 if(layout.regions[lr] && config[lr].panels){
42665 var r = layout.regions[lr];
42666 var ps = config[lr].panels;
42667 layout.addTypedPanels(r, ps);
42670 layout.endUpdate();
42675 Roo.BorderLayout.RegionFactory = {
42677 validRegions : ["north","south","east","west","center"],
42680 create : function(target, mgr, config){
42681 target = target.toLowerCase();
42682 if(config.lightweight || config.basic){
42683 return new Roo.BasicLayoutRegion(mgr, config, target);
42687 return new Roo.NorthLayoutRegion(mgr, config);
42689 return new Roo.SouthLayoutRegion(mgr, config);
42691 return new Roo.EastLayoutRegion(mgr, config);
42693 return new Roo.WestLayoutRegion(mgr, config);
42695 return new Roo.CenterLayoutRegion(mgr, config);
42697 throw 'Layout region "'+target+'" not supported.';
42701 * Ext JS Library 1.1.1
42702 * Copyright(c) 2006-2007, Ext JS, LLC.
42704 * Originally Released Under LGPL - original licence link has changed is not relivant.
42707 * <script type="text/javascript">
42711 * @class Roo.BasicLayoutRegion
42712 * @extends Roo.util.Observable
42713 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
42714 * and does not have a titlebar, tabs or any other features. All it does is size and position
42715 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
42717 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
42719 this.position = pos;
42722 * @scope Roo.BasicLayoutRegion
42726 * @event beforeremove
42727 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
42728 * @param {Roo.LayoutRegion} this
42729 * @param {Roo.ContentPanel} panel The panel
42730 * @param {Object} e The cancel event object
42732 "beforeremove" : true,
42734 * @event invalidated
42735 * Fires when the layout for this region is changed.
42736 * @param {Roo.LayoutRegion} this
42738 "invalidated" : true,
42740 * @event visibilitychange
42741 * Fires when this region is shown or hidden
42742 * @param {Roo.LayoutRegion} this
42743 * @param {Boolean} visibility true or false
42745 "visibilitychange" : true,
42747 * @event paneladded
42748 * Fires when a panel is added.
42749 * @param {Roo.LayoutRegion} this
42750 * @param {Roo.ContentPanel} panel The panel
42752 "paneladded" : true,
42754 * @event panelremoved
42755 * Fires when a panel is removed.
42756 * @param {Roo.LayoutRegion} this
42757 * @param {Roo.ContentPanel} panel The panel
42759 "panelremoved" : true,
42762 * Fires when this region is collapsed.
42763 * @param {Roo.LayoutRegion} this
42765 "collapsed" : true,
42768 * Fires when this region is expanded.
42769 * @param {Roo.LayoutRegion} this
42774 * Fires when this region is slid into view.
42775 * @param {Roo.LayoutRegion} this
42777 "slideshow" : true,
42780 * Fires when this region slides out of view.
42781 * @param {Roo.LayoutRegion} this
42783 "slidehide" : true,
42785 * @event panelactivated
42786 * Fires when a panel is activated.
42787 * @param {Roo.LayoutRegion} this
42788 * @param {Roo.ContentPanel} panel The activated panel
42790 "panelactivated" : true,
42793 * Fires when the user resizes this region.
42794 * @param {Roo.LayoutRegion} this
42795 * @param {Number} newSize The new size (width for east/west, height for north/south)
42799 /** A collection of panels in this region. @type Roo.util.MixedCollection */
42800 this.panels = new Roo.util.MixedCollection();
42801 this.panels.getKey = this.getPanelId.createDelegate(this);
42803 this.activePanel = null;
42804 // ensure listeners are added...
42806 if (config.listeners || config.events) {
42807 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
42808 listeners : config.listeners || {},
42809 events : config.events || {}
42813 if(skipConfig !== true){
42814 this.applyConfig(config);
42818 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
42819 getPanelId : function(p){
42823 applyConfig : function(config){
42824 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
42825 this.config = config;
42830 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
42831 * the width, for horizontal (north, south) the height.
42832 * @param {Number} newSize The new width or height
42834 resizeTo : function(newSize){
42835 var el = this.el ? this.el :
42836 (this.activePanel ? this.activePanel.getEl() : null);
42838 switch(this.position){
42841 el.setWidth(newSize);
42842 this.fireEvent("resized", this, newSize);
42846 el.setHeight(newSize);
42847 this.fireEvent("resized", this, newSize);
42853 getBox : function(){
42854 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
42857 getMargins : function(){
42858 return this.margins;
42861 updateBox : function(box){
42863 var el = this.activePanel.getEl();
42864 el.dom.style.left = box.x + "px";
42865 el.dom.style.top = box.y + "px";
42866 this.activePanel.setSize(box.width, box.height);
42870 * Returns the container element for this region.
42871 * @return {Roo.Element}
42873 getEl : function(){
42874 return this.activePanel;
42878 * Returns true if this region is currently visible.
42879 * @return {Boolean}
42881 isVisible : function(){
42882 return this.activePanel ? true : false;
42885 setActivePanel : function(panel){
42886 panel = this.getPanel(panel);
42887 if(this.activePanel && this.activePanel != panel){
42888 this.activePanel.setActiveState(false);
42889 this.activePanel.getEl().setLeftTop(-10000,-10000);
42891 this.activePanel = panel;
42892 panel.setActiveState(true);
42894 panel.setSize(this.box.width, this.box.height);
42896 this.fireEvent("panelactivated", this, panel);
42897 this.fireEvent("invalidated");
42901 * Show the specified panel.
42902 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
42903 * @return {Roo.ContentPanel} The shown panel or null
42905 showPanel : function(panel){
42906 if(panel = this.getPanel(panel)){
42907 this.setActivePanel(panel);
42913 * Get the active panel for this region.
42914 * @return {Roo.ContentPanel} The active panel or null
42916 getActivePanel : function(){
42917 return this.activePanel;
42921 * Add the passed ContentPanel(s)
42922 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
42923 * @return {Roo.ContentPanel} The panel added (if only one was added)
42925 add : function(panel){
42926 if(arguments.length > 1){
42927 for(var i = 0, len = arguments.length; i < len; i++) {
42928 this.add(arguments[i]);
42932 if(this.hasPanel(panel)){
42933 this.showPanel(panel);
42936 var el = panel.getEl();
42937 if(el.dom.parentNode != this.mgr.el.dom){
42938 this.mgr.el.dom.appendChild(el.dom);
42940 if(panel.setRegion){
42941 panel.setRegion(this);
42943 this.panels.add(panel);
42944 el.setStyle("position", "absolute");
42945 if(!panel.background){
42946 this.setActivePanel(panel);
42947 if(this.config.initialSize && this.panels.getCount()==1){
42948 this.resizeTo(this.config.initialSize);
42951 this.fireEvent("paneladded", this, panel);
42956 * Returns true if the panel is in this region.
42957 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
42958 * @return {Boolean}
42960 hasPanel : function(panel){
42961 if(typeof panel == "object"){ // must be panel obj
42962 panel = panel.getId();
42964 return this.getPanel(panel) ? true : false;
42968 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
42969 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
42970 * @param {Boolean} preservePanel Overrides the config preservePanel option
42971 * @return {Roo.ContentPanel} The panel that was removed
42973 remove : function(panel, preservePanel){
42974 panel = this.getPanel(panel);
42979 this.fireEvent("beforeremove", this, panel, e);
42980 if(e.cancel === true){
42983 var panelId = panel.getId();
42984 this.panels.removeKey(panelId);
42989 * Returns the panel specified or null if it's not in this region.
42990 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
42991 * @return {Roo.ContentPanel}
42993 getPanel : function(id){
42994 if(typeof id == "object"){ // must be panel obj
42997 return this.panels.get(id);
43001 * Returns this regions position (north/south/east/west/center).
43004 getPosition: function(){
43005 return this.position;
43009 * Ext JS Library 1.1.1
43010 * Copyright(c) 2006-2007, Ext JS, LLC.
43012 * Originally Released Under LGPL - original licence link has changed is not relivant.
43015 * <script type="text/javascript">
43019 * @class Roo.LayoutRegion
43020 * @extends Roo.BasicLayoutRegion
43021 * This class represents a region in a layout manager.
43022 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
43023 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
43024 * @cfg {Boolean} floatable False to disable floating (defaults to true)
43025 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
43026 * @cfg {Object} cmargins Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
43027 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
43028 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
43029 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
43030 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
43031 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
43032 * @cfg {String} title The title for the region (overrides panel titles)
43033 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
43034 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
43035 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
43036 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
43037 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
43038 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
43039 * the space available, similar to FireFox 1.5 tabs (defaults to false)
43040 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
43041 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
43042 * @cfg {Boolean} showPin True to show a pin button
43043 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
43044 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
43045 * @cfg {Boolean} disableTabTips True to disable tab tooltips
43046 * @cfg {Number} width For East/West panels
43047 * @cfg {Number} height For North/South panels
43048 * @cfg {Boolean} split To show the splitter
43050 Roo.LayoutRegion = function(mgr, config, pos){
43051 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
43052 var dh = Roo.DomHelper;
43053 /** This region's container element
43054 * @type Roo.Element */
43055 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
43056 /** This region's title element
43057 * @type Roo.Element */
43059 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
43060 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
43061 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
43063 this.titleEl.enableDisplayMode();
43064 /** This region's title text element
43065 * @type HTMLElement */
43066 this.titleTextEl = this.titleEl.dom.firstChild;
43067 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
43068 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
43069 this.closeBtn.enableDisplayMode();
43070 this.closeBtn.on("click", this.closeClicked, this);
43071 this.closeBtn.hide();
43073 this.createBody(config);
43074 this.visible = true;
43075 this.collapsed = false;
43077 if(config.hideWhenEmpty){
43079 this.on("paneladded", this.validateVisibility, this);
43080 this.on("panelremoved", this.validateVisibility, this);
43082 this.applyConfig(config);
43085 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
43087 createBody : function(){
43088 /** This region's body element
43089 * @type Roo.Element */
43090 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
43093 applyConfig : function(c){
43094 if(c.collapsible && this.position != "center" && !this.collapsedEl){
43095 var dh = Roo.DomHelper;
43096 if(c.titlebar !== false){
43097 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
43098 this.collapseBtn.on("click", this.collapse, this);
43099 this.collapseBtn.enableDisplayMode();
43101 if(c.showPin === true || this.showPin){
43102 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
43103 this.stickBtn.enableDisplayMode();
43104 this.stickBtn.on("click", this.expand, this);
43105 this.stickBtn.hide();
43108 /** This region's collapsed element
43109 * @type Roo.Element */
43110 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
43111 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
43113 if(c.floatable !== false){
43114 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
43115 this.collapsedEl.on("click", this.collapseClick, this);
43118 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
43119 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
43120 id: "message", unselectable: "on", style:{"float":"left"}});
43121 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
43123 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
43124 this.expandBtn.on("click", this.expand, this);
43126 if(this.collapseBtn){
43127 this.collapseBtn.setVisible(c.collapsible == true);
43129 this.cmargins = c.cmargins || this.cmargins ||
43130 (this.position == "west" || this.position == "east" ?
43131 {top: 0, left: 2, right:2, bottom: 0} :
43132 {top: 2, left: 0, right:0, bottom: 2});
43133 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43134 this.bottomTabs = c.tabPosition != "top";
43135 this.autoScroll = c.autoScroll || false;
43136 if(this.autoScroll){
43137 this.bodyEl.setStyle("overflow", "auto");
43139 this.bodyEl.setStyle("overflow", "hidden");
43141 //if(c.titlebar !== false){
43142 if((!c.titlebar && !c.title) || c.titlebar === false){
43143 this.titleEl.hide();
43145 this.titleEl.show();
43147 this.titleTextEl.innerHTML = c.title;
43151 this.duration = c.duration || .30;
43152 this.slideDuration = c.slideDuration || .45;
43155 this.collapse(true);
43162 * Returns true if this region is currently visible.
43163 * @return {Boolean}
43165 isVisible : function(){
43166 return this.visible;
43170 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
43171 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
43173 setCollapsedTitle : function(title){
43174 title = title || " ";
43175 if(this.collapsedTitleTextEl){
43176 this.collapsedTitleTextEl.innerHTML = title;
43180 getBox : function(){
43182 if(!this.collapsed){
43183 b = this.el.getBox(false, true);
43185 b = this.collapsedEl.getBox(false, true);
43190 getMargins : function(){
43191 return this.collapsed ? this.cmargins : this.margins;
43194 highlight : function(){
43195 this.el.addClass("x-layout-panel-dragover");
43198 unhighlight : function(){
43199 this.el.removeClass("x-layout-panel-dragover");
43202 updateBox : function(box){
43204 if(!this.collapsed){
43205 this.el.dom.style.left = box.x + "px";
43206 this.el.dom.style.top = box.y + "px";
43207 this.updateBody(box.width, box.height);
43209 this.collapsedEl.dom.style.left = box.x + "px";
43210 this.collapsedEl.dom.style.top = box.y + "px";
43211 this.collapsedEl.setSize(box.width, box.height);
43214 this.tabs.autoSizeTabs();
43218 updateBody : function(w, h){
43220 this.el.setWidth(w);
43221 w -= this.el.getBorderWidth("rl");
43222 if(this.config.adjustments){
43223 w += this.config.adjustments[0];
43227 this.el.setHeight(h);
43228 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
43229 h -= this.el.getBorderWidth("tb");
43230 if(this.config.adjustments){
43231 h += this.config.adjustments[1];
43233 this.bodyEl.setHeight(h);
43235 h = this.tabs.syncHeight(h);
43238 if(this.panelSize){
43239 w = w !== null ? w : this.panelSize.width;
43240 h = h !== null ? h : this.panelSize.height;
43242 if(this.activePanel){
43243 var el = this.activePanel.getEl();
43244 w = w !== null ? w : el.getWidth();
43245 h = h !== null ? h : el.getHeight();
43246 this.panelSize = {width: w, height: h};
43247 this.activePanel.setSize(w, h);
43249 if(Roo.isIE && this.tabs){
43250 this.tabs.el.repaint();
43255 * Returns the container element for this region.
43256 * @return {Roo.Element}
43258 getEl : function(){
43263 * Hides this region.
43266 if(!this.collapsed){
43267 this.el.dom.style.left = "-2000px";
43270 this.collapsedEl.dom.style.left = "-2000px";
43271 this.collapsedEl.hide();
43273 this.visible = false;
43274 this.fireEvent("visibilitychange", this, false);
43278 * Shows this region if it was previously hidden.
43281 if(!this.collapsed){
43284 this.collapsedEl.show();
43286 this.visible = true;
43287 this.fireEvent("visibilitychange", this, true);
43290 closeClicked : function(){
43291 if(this.activePanel){
43292 this.remove(this.activePanel);
43296 collapseClick : function(e){
43298 e.stopPropagation();
43301 e.stopPropagation();
43307 * Collapses this region.
43308 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
43310 collapse : function(skipAnim){
43311 if(this.collapsed) return;
43312 this.collapsed = true;
43314 this.split.el.hide();
43316 if(this.config.animate && skipAnim !== true){
43317 this.fireEvent("invalidated", this);
43318 this.animateCollapse();
43320 this.el.setLocation(-20000,-20000);
43322 this.collapsedEl.show();
43323 this.fireEvent("collapsed", this);
43324 this.fireEvent("invalidated", this);
43328 animateCollapse : function(){
43333 * Expands this region if it was previously collapsed.
43334 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
43335 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
43337 expand : function(e, skipAnim){
43338 if(e) e.stopPropagation();
43339 if(!this.collapsed || this.el.hasActiveFx()) return;
43341 this.afterSlideIn();
43344 this.collapsed = false;
43345 if(this.config.animate && skipAnim !== true){
43346 this.animateExpand();
43350 this.split.el.show();
43352 this.collapsedEl.setLocation(-2000,-2000);
43353 this.collapsedEl.hide();
43354 this.fireEvent("invalidated", this);
43355 this.fireEvent("expanded", this);
43359 animateExpand : function(){
43363 initTabs : function(){
43364 this.bodyEl.setStyle("overflow", "hidden");
43365 var ts = new Roo.TabPanel(this.bodyEl.dom, {
43366 tabPosition: this.bottomTabs ? 'bottom' : 'top',
43367 disableTooltips: this.config.disableTabTips
43369 if(this.config.hideTabs){
43370 ts.stripWrap.setDisplayed(false);
43373 ts.resizeTabs = this.config.resizeTabs === true;
43374 ts.minTabWidth = this.config.minTabWidth || 40;
43375 ts.maxTabWidth = this.config.maxTabWidth || 250;
43376 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
43377 ts.monitorResize = false;
43378 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43379 ts.bodyEl.addClass('x-layout-tabs-body');
43380 this.panels.each(this.initPanelAsTab, this);
43383 initPanelAsTab : function(panel){
43384 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
43385 this.config.closeOnTab && panel.isClosable());
43386 if(panel.tabTip !== undefined){
43387 ti.setTooltip(panel.tabTip);
43389 ti.on("activate", function(){
43390 this.setActivePanel(panel);
43392 if(this.config.closeOnTab){
43393 ti.on("beforeclose", function(t, e){
43395 this.remove(panel);
43401 updatePanelTitle : function(panel, title){
43402 if(this.activePanel == panel){
43403 this.updateTitle(title);
43406 var ti = this.tabs.getTab(panel.getEl().id);
43408 if(panel.tabTip !== undefined){
43409 ti.setTooltip(panel.tabTip);
43414 updateTitle : function(title){
43415 if(this.titleTextEl && !this.config.title){
43416 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
43420 setActivePanel : function(panel){
43421 panel = this.getPanel(panel);
43422 if(this.activePanel && this.activePanel != panel){
43423 this.activePanel.setActiveState(false);
43425 this.activePanel = panel;
43426 panel.setActiveState(true);
43427 if(this.panelSize){
43428 panel.setSize(this.panelSize.width, this.panelSize.height);
43431 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
43433 this.updateTitle(panel.getTitle());
43435 this.fireEvent("invalidated", this);
43437 this.fireEvent("panelactivated", this, panel);
43441 * Shows the specified panel.
43442 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
43443 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
43445 showPanel : function(panel){
43446 if(panel = this.getPanel(panel)){
43448 var tab = this.tabs.getTab(panel.getEl().id);
43449 if(tab.isHidden()){
43450 this.tabs.unhideTab(tab.id);
43454 this.setActivePanel(panel);
43461 * Get the active panel for this region.
43462 * @return {Roo.ContentPanel} The active panel or null
43464 getActivePanel : function(){
43465 return this.activePanel;
43468 validateVisibility : function(){
43469 if(this.panels.getCount() < 1){
43470 this.updateTitle(" ");
43471 this.closeBtn.hide();
43474 if(!this.isVisible()){
43481 * Adds the passed ContentPanel(s) to this region.
43482 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43483 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
43485 add : function(panel){
43486 if(arguments.length > 1){
43487 for(var i = 0, len = arguments.length; i < len; i++) {
43488 this.add(arguments[i]);
43492 if(this.hasPanel(panel)){
43493 this.showPanel(panel);
43496 panel.setRegion(this);
43497 this.panels.add(panel);
43498 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
43499 this.bodyEl.dom.appendChild(panel.getEl().dom);
43500 if(panel.background !== true){
43501 this.setActivePanel(panel);
43503 this.fireEvent("paneladded", this, panel);
43509 this.initPanelAsTab(panel);
43511 if(panel.background !== true){
43512 this.tabs.activate(panel.getEl().id);
43514 this.fireEvent("paneladded", this, panel);
43519 * Hides the tab for the specified panel.
43520 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43522 hidePanel : function(panel){
43523 if(this.tabs && (panel = this.getPanel(panel))){
43524 this.tabs.hideTab(panel.getEl().id);
43529 * Unhides the tab for a previously hidden panel.
43530 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43532 unhidePanel : function(panel){
43533 if(this.tabs && (panel = this.getPanel(panel))){
43534 this.tabs.unhideTab(panel.getEl().id);
43538 clearPanels : function(){
43539 while(this.panels.getCount() > 0){
43540 this.remove(this.panels.first());
43545 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
43546 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43547 * @param {Boolean} preservePanel Overrides the config preservePanel option
43548 * @return {Roo.ContentPanel} The panel that was removed
43550 remove : function(panel, preservePanel){
43551 panel = this.getPanel(panel);
43556 this.fireEvent("beforeremove", this, panel, e);
43557 if(e.cancel === true){
43560 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
43561 var panelId = panel.getId();
43562 this.panels.removeKey(panelId);
43564 document.body.appendChild(panel.getEl().dom);
43567 this.tabs.removeTab(panel.getEl().id);
43568 }else if (!preservePanel){
43569 this.bodyEl.dom.removeChild(panel.getEl().dom);
43571 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
43572 var p = this.panels.first();
43573 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
43574 tempEl.appendChild(p.getEl().dom);
43575 this.bodyEl.update("");
43576 this.bodyEl.dom.appendChild(p.getEl().dom);
43578 this.updateTitle(p.getTitle());
43580 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43581 this.setActivePanel(p);
43583 panel.setRegion(null);
43584 if(this.activePanel == panel){
43585 this.activePanel = null;
43587 if(this.config.autoDestroy !== false && preservePanel !== true){
43588 try{panel.destroy();}catch(e){}
43590 this.fireEvent("panelremoved", this, panel);
43595 * Returns the TabPanel component used by this region
43596 * @return {Roo.TabPanel}
43598 getTabs : function(){
43602 createTool : function(parentEl, className){
43603 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
43604 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
43605 btn.addClassOnOver("x-layout-tools-button-over");
43610 * Ext JS Library 1.1.1
43611 * Copyright(c) 2006-2007, Ext JS, LLC.
43613 * Originally Released Under LGPL - original licence link has changed is not relivant.
43616 * <script type="text/javascript">
43622 * @class Roo.SplitLayoutRegion
43623 * @extends Roo.LayoutRegion
43624 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
43626 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
43627 this.cursor = cursor;
43628 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
43631 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
43632 splitTip : "Drag to resize.",
43633 collapsibleSplitTip : "Drag to resize. Double click to hide.",
43634 useSplitTips : false,
43636 applyConfig : function(config){
43637 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
43640 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
43641 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
43642 /** The SplitBar for this region
43643 * @type Roo.SplitBar */
43644 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
43645 this.split.on("moved", this.onSplitMove, this);
43646 this.split.useShim = config.useShim === true;
43647 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
43648 if(this.useSplitTips){
43649 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
43651 if(config.collapsible){
43652 this.split.el.on("dblclick", this.collapse, this);
43655 if(typeof config.minSize != "undefined"){
43656 this.split.minSize = config.minSize;
43658 if(typeof config.maxSize != "undefined"){
43659 this.split.maxSize = config.maxSize;
43661 if(config.hideWhenEmpty || config.hidden || config.collapsed){
43662 this.hideSplitter();
43667 getHMaxSize : function(){
43668 var cmax = this.config.maxSize || 10000;
43669 var center = this.mgr.getRegion("center");
43670 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
43673 getVMaxSize : function(){
43674 var cmax = this.config.maxSize || 10000;
43675 var center = this.mgr.getRegion("center");
43676 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
43679 onSplitMove : function(split, newSize){
43680 this.fireEvent("resized", this, newSize);
43684 * Returns the {@link Roo.SplitBar} for this region.
43685 * @return {Roo.SplitBar}
43687 getSplitBar : function(){
43692 this.hideSplitter();
43693 Roo.SplitLayoutRegion.superclass.hide.call(this);
43696 hideSplitter : function(){
43698 this.split.el.setLocation(-2000,-2000);
43699 this.split.el.hide();
43705 this.split.el.show();
43707 Roo.SplitLayoutRegion.superclass.show.call(this);
43710 beforeSlide: function(){
43711 if(Roo.isGecko){// firefox overflow auto bug workaround
43712 this.bodyEl.clip();
43713 if(this.tabs) this.tabs.bodyEl.clip();
43714 if(this.activePanel){
43715 this.activePanel.getEl().clip();
43717 if(this.activePanel.beforeSlide){
43718 this.activePanel.beforeSlide();
43724 afterSlide : function(){
43725 if(Roo.isGecko){// firefox overflow auto bug workaround
43726 this.bodyEl.unclip();
43727 if(this.tabs) this.tabs.bodyEl.unclip();
43728 if(this.activePanel){
43729 this.activePanel.getEl().unclip();
43730 if(this.activePanel.afterSlide){
43731 this.activePanel.afterSlide();
43737 initAutoHide : function(){
43738 if(this.autoHide !== false){
43739 if(!this.autoHideHd){
43740 var st = new Roo.util.DelayedTask(this.slideIn, this);
43741 this.autoHideHd = {
43742 "mouseout": function(e){
43743 if(!e.within(this.el, true)){
43747 "mouseover" : function(e){
43753 this.el.on(this.autoHideHd);
43757 clearAutoHide : function(){
43758 if(this.autoHide !== false){
43759 this.el.un("mouseout", this.autoHideHd.mouseout);
43760 this.el.un("mouseover", this.autoHideHd.mouseover);
43764 clearMonitor : function(){
43765 Roo.get(document).un("click", this.slideInIf, this);
43768 // these names are backwards but not changed for compat
43769 slideOut : function(){
43770 if(this.isSlid || this.el.hasActiveFx()){
43773 this.isSlid = true;
43774 if(this.collapseBtn){
43775 this.collapseBtn.hide();
43777 this.closeBtnState = this.closeBtn.getStyle('display');
43778 this.closeBtn.hide();
43780 this.stickBtn.show();
43783 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
43784 this.beforeSlide();
43785 this.el.setStyle("z-index", 10001);
43786 this.el.slideIn(this.getSlideAnchor(), {
43787 callback: function(){
43789 this.initAutoHide();
43790 Roo.get(document).on("click", this.slideInIf, this);
43791 this.fireEvent("slideshow", this);
43798 afterSlideIn : function(){
43799 this.clearAutoHide();
43800 this.isSlid = false;
43801 this.clearMonitor();
43802 this.el.setStyle("z-index", "");
43803 if(this.collapseBtn){
43804 this.collapseBtn.show();
43806 this.closeBtn.setStyle('display', this.closeBtnState);
43808 this.stickBtn.hide();
43810 this.fireEvent("slidehide", this);
43813 slideIn : function(cb){
43814 if(!this.isSlid || this.el.hasActiveFx()){
43818 this.isSlid = false;
43819 this.beforeSlide();
43820 this.el.slideOut(this.getSlideAnchor(), {
43821 callback: function(){
43822 this.el.setLeftTop(-10000, -10000);
43824 this.afterSlideIn();
43832 slideInIf : function(e){
43833 if(!e.within(this.el)){
43838 animateCollapse : function(){
43839 this.beforeSlide();
43840 this.el.setStyle("z-index", 20000);
43841 var anchor = this.getSlideAnchor();
43842 this.el.slideOut(anchor, {
43843 callback : function(){
43844 this.el.setStyle("z-index", "");
43845 this.collapsedEl.slideIn(anchor, {duration:.3});
43847 this.el.setLocation(-10000,-10000);
43849 this.fireEvent("collapsed", this);
43856 animateExpand : function(){
43857 this.beforeSlide();
43858 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
43859 this.el.setStyle("z-index", 20000);
43860 this.collapsedEl.hide({
43863 this.el.slideIn(this.getSlideAnchor(), {
43864 callback : function(){
43865 this.el.setStyle("z-index", "");
43868 this.split.el.show();
43870 this.fireEvent("invalidated", this);
43871 this.fireEvent("expanded", this);
43899 getAnchor : function(){
43900 return this.anchors[this.position];
43903 getCollapseAnchor : function(){
43904 return this.canchors[this.position];
43907 getSlideAnchor : function(){
43908 return this.sanchors[this.position];
43911 getAlignAdj : function(){
43912 var cm = this.cmargins;
43913 switch(this.position){
43929 getExpandAdj : function(){
43930 var c = this.collapsedEl, cm = this.cmargins;
43931 switch(this.position){
43933 return [-(cm.right+c.getWidth()+cm.left), 0];
43936 return [cm.right+c.getWidth()+cm.left, 0];
43939 return [0, -(cm.top+cm.bottom+c.getHeight())];
43942 return [0, cm.top+cm.bottom+c.getHeight()];
43948 * Ext JS Library 1.1.1
43949 * Copyright(c) 2006-2007, Ext JS, LLC.
43951 * Originally Released Under LGPL - original licence link has changed is not relivant.
43954 * <script type="text/javascript">
43957 * These classes are private internal classes
43959 Roo.CenterLayoutRegion = function(mgr, config){
43960 Roo.LayoutRegion.call(this, mgr, config, "center");
43961 this.visible = true;
43962 this.minWidth = config.minWidth || 20;
43963 this.minHeight = config.minHeight || 20;
43966 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
43968 // center panel can't be hidden
43972 // center panel can't be hidden
43975 getMinWidth: function(){
43976 return this.minWidth;
43979 getMinHeight: function(){
43980 return this.minHeight;
43985 Roo.NorthLayoutRegion = function(mgr, config){
43986 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
43988 this.split.placement = Roo.SplitBar.TOP;
43989 this.split.orientation = Roo.SplitBar.VERTICAL;
43990 this.split.el.addClass("x-layout-split-v");
43992 var size = config.initialSize || config.height;
43993 if(typeof size != "undefined"){
43994 this.el.setHeight(size);
43997 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
43998 orientation: Roo.SplitBar.VERTICAL,
43999 getBox : function(){
44000 if(this.collapsed){
44001 return this.collapsedEl.getBox();
44003 var box = this.el.getBox();
44005 box.height += this.split.el.getHeight();
44010 updateBox : function(box){
44011 if(this.split && !this.collapsed){
44012 box.height -= this.split.el.getHeight();
44013 this.split.el.setLeft(box.x);
44014 this.split.el.setTop(box.y+box.height);
44015 this.split.el.setWidth(box.width);
44017 if(this.collapsed){
44018 this.updateBody(box.width, null);
44020 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44024 Roo.SouthLayoutRegion = function(mgr, config){
44025 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
44027 this.split.placement = Roo.SplitBar.BOTTOM;
44028 this.split.orientation = Roo.SplitBar.VERTICAL;
44029 this.split.el.addClass("x-layout-split-v");
44031 var size = config.initialSize || config.height;
44032 if(typeof size != "undefined"){
44033 this.el.setHeight(size);
44036 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
44037 orientation: Roo.SplitBar.VERTICAL,
44038 getBox : function(){
44039 if(this.collapsed){
44040 return this.collapsedEl.getBox();
44042 var box = this.el.getBox();
44044 var sh = this.split.el.getHeight();
44051 updateBox : function(box){
44052 if(this.split && !this.collapsed){
44053 var sh = this.split.el.getHeight();
44056 this.split.el.setLeft(box.x);
44057 this.split.el.setTop(box.y-sh);
44058 this.split.el.setWidth(box.width);
44060 if(this.collapsed){
44061 this.updateBody(box.width, null);
44063 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44067 Roo.EastLayoutRegion = function(mgr, config){
44068 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
44070 this.split.placement = Roo.SplitBar.RIGHT;
44071 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44072 this.split.el.addClass("x-layout-split-h");
44074 var size = config.initialSize || config.width;
44075 if(typeof size != "undefined"){
44076 this.el.setWidth(size);
44079 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
44080 orientation: Roo.SplitBar.HORIZONTAL,
44081 getBox : function(){
44082 if(this.collapsed){
44083 return this.collapsedEl.getBox();
44085 var box = this.el.getBox();
44087 var sw = this.split.el.getWidth();
44094 updateBox : function(box){
44095 if(this.split && !this.collapsed){
44096 var sw = this.split.el.getWidth();
44098 this.split.el.setLeft(box.x);
44099 this.split.el.setTop(box.y);
44100 this.split.el.setHeight(box.height);
44103 if(this.collapsed){
44104 this.updateBody(null, box.height);
44106 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44110 Roo.WestLayoutRegion = function(mgr, config){
44111 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
44113 this.split.placement = Roo.SplitBar.LEFT;
44114 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44115 this.split.el.addClass("x-layout-split-h");
44117 var size = config.initialSize || config.width;
44118 if(typeof size != "undefined"){
44119 this.el.setWidth(size);
44122 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
44123 orientation: Roo.SplitBar.HORIZONTAL,
44124 getBox : function(){
44125 if(this.collapsed){
44126 return this.collapsedEl.getBox();
44128 var box = this.el.getBox();
44130 box.width += this.split.el.getWidth();
44135 updateBox : function(box){
44136 if(this.split && !this.collapsed){
44137 var sw = this.split.el.getWidth();
44139 this.split.el.setLeft(box.x+box.width);
44140 this.split.el.setTop(box.y);
44141 this.split.el.setHeight(box.height);
44143 if(this.collapsed){
44144 this.updateBody(null, box.height);
44146 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44151 * Ext JS Library 1.1.1
44152 * Copyright(c) 2006-2007, Ext JS, LLC.
44154 * Originally Released Under LGPL - original licence link has changed is not relivant.
44157 * <script type="text/javascript">
44162 * Private internal class for reading and applying state
44164 Roo.LayoutStateManager = function(layout){
44165 // default empty state
44174 Roo.LayoutStateManager.prototype = {
44175 init : function(layout, provider){
44176 this.provider = provider;
44177 var state = provider.get(layout.id+"-layout-state");
44179 var wasUpdating = layout.isUpdating();
44181 layout.beginUpdate();
44183 for(var key in state){
44184 if(typeof state[key] != "function"){
44185 var rstate = state[key];
44186 var r = layout.getRegion(key);
44189 r.resizeTo(rstate.size);
44191 if(rstate.collapsed == true){
44194 r.expand(null, true);
44200 layout.endUpdate();
44202 this.state = state;
44204 this.layout = layout;
44205 layout.on("regionresized", this.onRegionResized, this);
44206 layout.on("regioncollapsed", this.onRegionCollapsed, this);
44207 layout.on("regionexpanded", this.onRegionExpanded, this);
44210 storeState : function(){
44211 this.provider.set(this.layout.id+"-layout-state", this.state);
44214 onRegionResized : function(region, newSize){
44215 this.state[region.getPosition()].size = newSize;
44219 onRegionCollapsed : function(region){
44220 this.state[region.getPosition()].collapsed = true;
44224 onRegionExpanded : function(region){
44225 this.state[region.getPosition()].collapsed = false;
44230 * Ext JS Library 1.1.1
44231 * Copyright(c) 2006-2007, Ext JS, LLC.
44233 * Originally Released Under LGPL - original licence link has changed is not relivant.
44236 * <script type="text/javascript">
44239 * @class Roo.ContentPanel
44240 * @extends Roo.util.Observable
44241 * A basic ContentPanel element.
44242 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
44243 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
44244 * @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
44245 * @cfg {Boolean} closable True if the panel can be closed/removed
44246 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
44247 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
44248 * @cfg {Toolbar} toolbar A toolbar for this panel
44249 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
44250 * @cfg {String} title The title for this panel
44251 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
44252 * @cfg {String} url Calls {@link #setUrl} with this value
44253 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
44254 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
44256 * Create a new ContentPanel.
44257 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
44258 * @param {String/Object} config A string to set only the title or a config object
44259 * @param {String} content (optional) Set the HTML content for this panel
44260 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
44262 Roo.ContentPanel = function(el, config, content){
44266 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
44270 if (config && config.parentLayout) {
44271 el = config.parentLayout.el.createChild();
44274 if(el.autoCreate){ // xtype is available if this is called from factory
44278 this.el = Roo.get(el);
44279 if(!this.el && config && config.autoCreate){
44280 if(typeof config.autoCreate == "object"){
44281 if(!config.autoCreate.id){
44282 config.autoCreate.id = config.id||el;
44284 this.el = Roo.DomHelper.append(document.body,
44285 config.autoCreate, true);
44287 this.el = Roo.DomHelper.append(document.body,
44288 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
44291 this.closable = false;
44292 this.loaded = false;
44293 this.active = false;
44294 if(typeof config == "string"){
44295 this.title = config;
44297 Roo.apply(this, config);
44300 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
44301 this.wrapEl = this.el.wrap();
44302 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
44309 this.resizeEl = Roo.get(this.resizeEl, true);
44311 this.resizeEl = this.el;
44316 * Fires when this panel is activated.
44317 * @param {Roo.ContentPanel} this
44321 * @event deactivate
44322 * Fires when this panel is activated.
44323 * @param {Roo.ContentPanel} this
44325 "deactivate" : true,
44329 * Fires when this panel is resized if fitToFrame is true.
44330 * @param {Roo.ContentPanel} this
44331 * @param {Number} width The width after any component adjustments
44332 * @param {Number} height The height after any component adjustments
44336 if(this.autoScroll){
44337 this.resizeEl.setStyle("overflow", "auto");
44339 content = content || this.content;
44341 this.setContent(content);
44343 if(config && config.url){
44344 this.setUrl(this.url, this.params, this.loadOnce);
44349 Roo.ContentPanel.superclass.constructor.call(this);
44352 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
44354 setRegion : function(region){
44355 this.region = region;
44357 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
44359 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
44364 * Returns the toolbar for this Panel if one was configured.
44365 * @return {Roo.Toolbar}
44367 getToolbar : function(){
44368 return this.toolbar;
44371 setActiveState : function(active){
44372 this.active = active;
44374 this.fireEvent("deactivate", this);
44376 this.fireEvent("activate", this);
44380 * Updates this panel's element
44381 * @param {String} content The new content
44382 * @param {Boolean} loadScripts (optional) true to look for and process scripts
44384 setContent : function(content, loadScripts){
44385 this.el.update(content, loadScripts);
44388 ignoreResize : function(w, h){
44389 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
44392 this.lastSize = {width: w, height: h};
44397 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
44398 * @return {Roo.UpdateManager} The UpdateManager
44400 getUpdateManager : function(){
44401 return this.el.getUpdateManager();
44404 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
44405 * @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:
44408 url: "your-url.php",
44409 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
44410 callback: yourFunction,
44411 scope: yourObject, //(optional scope)
44414 text: "Loading...",
44419 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
44420 * are shorthand for <i>disableCaching</i>, <i>indicatorText</i> and <i>loadScripts</i> and are used to set their associated property on this panel UpdateManager instance.
44421 * @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}
44422 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
44423 * @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.
44424 * @return {Roo.ContentPanel} this
44427 var um = this.el.getUpdateManager();
44428 um.update.apply(um, arguments);
44434 * Set a URL to be used to load the content for this panel. When this panel is activated, the content will be loaded from that URL.
44435 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
44436 * @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)
44437 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
44438 * @return {Roo.UpdateManager} The UpdateManager
44440 setUrl : function(url, params, loadOnce){
44441 if(this.refreshDelegate){
44442 this.removeListener("activate", this.refreshDelegate);
44444 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
44445 this.on("activate", this.refreshDelegate);
44446 return this.el.getUpdateManager();
44449 _handleRefresh : function(url, params, loadOnce){
44450 if(!loadOnce || !this.loaded){
44451 var updater = this.el.getUpdateManager();
44452 updater.update(url, params, this._setLoaded.createDelegate(this));
44456 _setLoaded : function(){
44457 this.loaded = true;
44461 * Returns this panel's id
44464 getId : function(){
44469 * Returns this panel's element - used by regiosn to add.
44470 * @return {Roo.Element}
44472 getEl : function(){
44473 return this.wrapEl || this.el;
44476 adjustForComponents : function(width, height){
44477 if(this.resizeEl != this.el){
44478 width -= this.el.getFrameWidth('lr');
44479 height -= this.el.getFrameWidth('tb');
44482 var te = this.toolbar.getEl();
44483 height -= te.getHeight();
44484 te.setWidth(width);
44486 if(this.adjustments){
44487 width += this.adjustments[0];
44488 height += this.adjustments[1];
44490 return {"width": width, "height": height};
44493 setSize : function(width, height){
44494 if(this.fitToFrame && !this.ignoreResize(width, height)){
44495 if(this.fitContainer && this.resizeEl != this.el){
44496 this.el.setSize(width, height);
44498 var size = this.adjustForComponents(width, height);
44499 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
44500 this.fireEvent('resize', this, size.width, size.height);
44505 * Returns this panel's title
44508 getTitle : function(){
44513 * Set this panel's title
44514 * @param {String} title
44516 setTitle : function(title){
44517 this.title = title;
44519 this.region.updatePanelTitle(this, title);
44524 * Returns true is this panel was configured to be closable
44525 * @return {Boolean}
44527 isClosable : function(){
44528 return this.closable;
44531 beforeSlide : function(){
44533 this.resizeEl.clip();
44536 afterSlide : function(){
44538 this.resizeEl.unclip();
44542 * Force a content refresh from the URL specified in the {@link #setUrl} method.
44543 * Will fail silently if the {@link #setUrl} method has not been called.
44544 * This does not activate the panel, just updates its content.
44546 refresh : function(){
44547 if(this.refreshDelegate){
44548 this.loaded = false;
44549 this.refreshDelegate();
44554 * Destroys this panel
44556 destroy : function(){
44557 this.el.removeAllListeners();
44558 var tempEl = document.createElement("span");
44559 tempEl.appendChild(this.el.dom);
44560 tempEl.innerHTML = "";
44566 * Adds a xtype elements to the panel - currently only supports Forms.
44576 * @param {Object} cfg Xtype definition of item to add.
44579 addxtype : function(cfg) {
44581 if (!cfg.xtype.match(/^Form$/)) {
44584 var el = this.el.createChild();
44586 this.form = new Roo.form.Form(cfg);
44589 if ( this.form.allItems.length) this.form.render(el.dom);
44596 * @class Roo.GridPanel
44597 * @extends Roo.ContentPanel
44599 * Create a new GridPanel.
44600 * @param {Roo.grid.Grid} grid The grid for this panel
44601 * @param {String/Object} config A string to set only the panel's title, or a config object
44603 Roo.GridPanel = function(grid, config){
44606 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
44607 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
44609 this.wrapper.dom.appendChild(grid.getGridEl().dom);
44611 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
44614 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
44616 // xtype created footer. - not sure if will work as we normally have to render first..
44617 if (this.footer && !this.footer.el && this.footer.xtype) {
44619 this.footer.container = this.grid.getView().getFooterPanel(true);
44620 this.footer.dataSource = this.grid.dataSource;
44621 this.footer = Roo.factory(this.footer, Roo);
44625 grid.monitorWindowResize = false; // turn off autosizing
44626 grid.autoHeight = false;
44627 grid.autoWidth = false;
44629 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
44632 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
44633 getId : function(){
44634 return this.grid.id;
44638 * Returns the grid for this panel
44639 * @return {Roo.grid.Grid}
44641 getGrid : function(){
44645 setSize : function(width, height){
44646 if(!this.ignoreResize(width, height)){
44647 var grid = this.grid;
44648 var size = this.adjustForComponents(width, height);
44649 grid.getGridEl().setSize(size.width, size.height);
44654 beforeSlide : function(){
44655 this.grid.getView().scroller.clip();
44658 afterSlide : function(){
44659 this.grid.getView().scroller.unclip();
44662 destroy : function(){
44663 this.grid.destroy();
44665 Roo.GridPanel.superclass.destroy.call(this);
44671 * @class Roo.NestedLayoutPanel
44672 * @extends Roo.ContentPanel
44674 * Create a new NestedLayoutPanel.
44677 * @param {Roo.BorderLayout} layout The layout for this panel
44678 * @param {String/Object} config A string to set only the title or a config object
44680 Roo.NestedLayoutPanel = function(layout, config)
44682 // construct with only one argument..
44683 /* FIXME - implement nicer consturctors
44684 if (layout.layout) {
44686 layout = config.layout;
44687 delete config.layout;
44689 if (layout.xtype && !layout.getEl) {
44690 // then layout needs constructing..
44691 layout = Roo.factory(layout, Roo);
44695 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
44697 layout.monitorWindowResize = false; // turn off autosizing
44698 this.layout = layout;
44699 this.layout.getEl().addClass("x-layout-nested-layout");
44705 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
44707 setSize : function(width, height){
44708 if(!this.ignoreResize(width, height)){
44709 var size = this.adjustForComponents(width, height);
44710 var el = this.layout.getEl();
44711 el.setSize(size.width, size.height);
44712 var touch = el.dom.offsetWidth;
44713 this.layout.layout();
44714 // ie requires a double layout on the first pass
44715 if(Roo.isIE && !this.initialized){
44716 this.initialized = true;
44717 this.layout.layout();
44722 // activate all subpanels if not currently active..
44724 setActiveState : function(active){
44725 this.active = active;
44727 this.fireEvent("deactivate", this);
44731 this.fireEvent("activate", this);
44732 // not sure if this should happen before or after..
44733 if (!this.layout) {
44734 return; // should not happen..
44737 for (var r in this.layout.regions) {
44738 reg = this.layout.getRegion(r);
44739 if (reg.getActivePanel()) {
44740 //reg.showPanel(reg.getActivePanel()); // force it to activate..
44741 reg.setActivePanel(reg.getActivePanel());
44744 if (!reg.panels.length) {
44747 reg.showPanel(reg.getPanel(0));
44756 * Returns the nested BorderLayout for this panel
44757 * @return {Roo.BorderLayout}
44759 getLayout : function(){
44760 return this.layout;
44764 * Adds a xtype elements to the layout of the nested panel
44768 xtype : 'ContentPanel',
44775 xtype : 'NestedLayoutPanel',
44781 items : [ ... list of content panels or nested layout panels.. ]
44785 * @param {Object} cfg Xtype definition of item to add.
44787 addxtype : function(cfg) {
44788 return this.layout.addxtype(cfg);
44793 Roo.ScrollPanel = function(el, config, content){
44794 config = config || {};
44795 config.fitToFrame = true;
44796 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
44798 this.el.dom.style.overflow = "hidden";
44799 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
44800 this.el.removeClass("x-layout-inactive-content");
44801 this.el.on("mousewheel", this.onWheel, this);
44803 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
44804 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
44805 up.unselectable(); down.unselectable();
44806 up.on("click", this.scrollUp, this);
44807 down.on("click", this.scrollDown, this);
44808 up.addClassOnOver("x-scroller-btn-over");
44809 down.addClassOnOver("x-scroller-btn-over");
44810 up.addClassOnClick("x-scroller-btn-click");
44811 down.addClassOnClick("x-scroller-btn-click");
44812 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
44814 this.resizeEl = this.el;
44815 this.el = wrap; this.up = up; this.down = down;
44818 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
44820 wheelIncrement : 5,
44821 scrollUp : function(){
44822 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
44825 scrollDown : function(){
44826 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
44829 afterScroll : function(){
44830 var el = this.resizeEl;
44831 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
44832 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44833 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44836 setSize : function(){
44837 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
44838 this.afterScroll();
44841 onWheel : function(e){
44842 var d = e.getWheelDelta();
44843 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
44844 this.afterScroll();
44848 setContent : function(content, loadScripts){
44849 this.resizeEl.update(content, loadScripts);
44863 * @class Roo.TreePanel
44864 * @extends Roo.ContentPanel
44866 * Create a new TreePanel.
44867 * @param {String/Object} config A string to set only the panel's title, or a config object
44868 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
44870 Roo.TreePanel = function(config){
44871 var el = config.el;
44872 var tree = config.tree;
44873 delete config.tree;
44874 delete config.el; // hopefull!
44875 Roo.TreePanel.superclass.constructor.call(this, el, config);
44876 var treeEl = el.createChild();
44877 this.tree = new Roo.tree.TreePanel(treeEl , tree);
44878 //console.log(tree);
44879 this.on('activate', function()
44881 if (this.tree.rendered) {
44884 //console.log('render tree');
44885 this.tree.render();
44888 this.on('resize', function (cp, w, h) {
44889 this.tree.innerCt.setWidth(w);
44890 this.tree.innerCt.setHeight(h);
44891 this.tree.innerCt.setStyle('overflow-y', 'auto');
44898 Roo.extend(Roo.TreePanel, Roo.ContentPanel);
44912 * Ext JS Library 1.1.1
44913 * Copyright(c) 2006-2007, Ext JS, LLC.
44915 * Originally Released Under LGPL - original licence link has changed is not relivant.
44918 * <script type="text/javascript">
44923 * @class Roo.ReaderLayout
44924 * @extends Roo.BorderLayout
44925 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
44926 * center region containing two nested regions (a top one for a list view and one for item preview below),
44927 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
44928 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
44929 * expedites the setup of the overall layout and regions for this common application style.
44932 var reader = new Roo.ReaderLayout();
44933 var CP = Roo.ContentPanel; // shortcut for adding
44935 reader.beginUpdate();
44936 reader.add("north", new CP("north", "North"));
44937 reader.add("west", new CP("west", {title: "West"}));
44938 reader.add("east", new CP("east", {title: "East"}));
44940 reader.regions.listView.add(new CP("listView", "List"));
44941 reader.regions.preview.add(new CP("preview", "Preview"));
44942 reader.endUpdate();
44945 * Create a new ReaderLayout
44946 * @param {Object} config Configuration options
44947 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
44948 * document.body if omitted)
44950 Roo.ReaderLayout = function(config, renderTo){
44951 var c = config || {size:{}};
44952 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
44953 north: c.north !== false ? Roo.apply({
44957 }, c.north) : false,
44958 west: c.west !== false ? Roo.apply({
44966 margins:{left:5,right:0,bottom:5,top:5},
44967 cmargins:{left:5,right:5,bottom:5,top:5}
44968 }, c.west) : false,
44969 east: c.east !== false ? Roo.apply({
44977 margins:{left:0,right:5,bottom:5,top:5},
44978 cmargins:{left:5,right:5,bottom:5,top:5}
44979 }, c.east) : false,
44980 center: Roo.apply({
44981 tabPosition: 'top',
44985 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
44989 this.el.addClass('x-reader');
44991 this.beginUpdate();
44993 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
44994 south: c.preview !== false ? Roo.apply({
45001 cmargins:{top:5,left:0, right:0, bottom:0}
45002 }, c.preview) : false,
45003 center: Roo.apply({
45009 this.add('center', new Roo.NestedLayoutPanel(inner,
45010 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
45014 this.regions.preview = inner.getRegion('south');
45015 this.regions.listView = inner.getRegion('center');
45018 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
45020 * Ext JS Library 1.1.1
45021 * Copyright(c) 2006-2007, Ext JS, LLC.
45023 * Originally Released Under LGPL - original licence link has changed is not relivant.
45026 * <script type="text/javascript">
45030 * @class Roo.grid.Grid
45031 * @extends Roo.util.Observable
45032 * This class represents the primary interface of a component based grid control.
45033 * <br><br>Usage:<pre><code>
45034 var grid = new Roo.grid.Grid("my-container-id", {
45037 selModel: mySelectionModel,
45038 autoSizeColumns: true,
45039 monitorWindowResize: false,
45040 trackMouseOver: true
45045 * <b>Common Problems:</b><br/>
45046 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
45047 * element will correct this<br/>
45048 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
45049 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
45050 * are unpredictable.<br/>
45051 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
45052 * grid to calculate dimensions/offsets.<br/>
45054 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
45055 * The container MUST have some type of size defined for the grid to fill. The container will be
45056 * automatically set to position relative if it isn't already.
45057 * @param {Object} config A config object that sets properties on this grid.
45059 Roo.grid.Grid = function(container, config){
45060 // initialize the container
45061 this.container = Roo.get(container);
45062 this.container.update("");
45063 this.container.setStyle("overflow", "hidden");
45064 this.container.addClass('x-grid-container');
45066 this.id = this.container.id;
45068 Roo.apply(this, config);
45069 // check and correct shorthanded configs
45071 this.dataSource = this.ds;
45075 this.colModel = this.cm;
45079 this.selModel = this.sm;
45083 if (this.selModel) {
45084 this.selModel = Roo.factory(this.selModel, Roo.grid);
45085 this.sm = this.selModel;
45086 this.sm.xmodule = this.xmodule || false;
45088 if (typeof(this.colModel.config) == 'undefined') {
45089 this.colModel = new Roo.grid.ColumnModel(this.colModel);
45090 this.cm = this.colModel;
45091 this.cm.xmodule = this.xmodule || false;
45093 if (this.dataSource) {
45094 this.dataSource= Roo.factory(this.dataSource, Roo.data);
45095 this.ds = this.dataSource;
45096 this.ds.xmodule = this.xmodule || false;
45103 this.container.setWidth(this.width);
45107 this.container.setHeight(this.height);
45114 * The raw click event for the entire grid.
45115 * @param {Roo.EventObject} e
45120 * The raw dblclick event for the entire grid.
45121 * @param {Roo.EventObject} e
45125 * @event contextmenu
45126 * The raw contextmenu event for the entire grid.
45127 * @param {Roo.EventObject} e
45129 "contextmenu" : true,
45132 * The raw mousedown event for the entire grid.
45133 * @param {Roo.EventObject} e
45135 "mousedown" : true,
45138 * The raw mouseup event for the entire grid.
45139 * @param {Roo.EventObject} e
45144 * The raw mouseover event for the entire grid.
45145 * @param {Roo.EventObject} e
45147 "mouseover" : true,
45150 * The raw mouseout event for the entire grid.
45151 * @param {Roo.EventObject} e
45156 * The raw keypress event for the entire grid.
45157 * @param {Roo.EventObject} e
45162 * The raw keydown event for the entire grid.
45163 * @param {Roo.EventObject} e
45171 * Fires when a cell is clicked
45172 * @param {Grid} this
45173 * @param {Number} rowIndex
45174 * @param {Number} columnIndex
45175 * @param {Roo.EventObject} e
45177 "cellclick" : true,
45179 * @event celldblclick
45180 * Fires when a cell is double clicked
45181 * @param {Grid} this
45182 * @param {Number} rowIndex
45183 * @param {Number} columnIndex
45184 * @param {Roo.EventObject} e
45186 "celldblclick" : true,
45189 * Fires when a row is clicked
45190 * @param {Grid} this
45191 * @param {Number} rowIndex
45192 * @param {Roo.EventObject} e
45196 * @event rowdblclick
45197 * Fires when a row is double clicked
45198 * @param {Grid} this
45199 * @param {Number} rowIndex
45200 * @param {Roo.EventObject} e
45202 "rowdblclick" : true,
45204 * @event headerclick
45205 * Fires when a header is clicked
45206 * @param {Grid} this
45207 * @param {Number} columnIndex
45208 * @param {Roo.EventObject} e
45210 "headerclick" : true,
45212 * @event headerdblclick
45213 * Fires when a header cell is double clicked
45214 * @param {Grid} this
45215 * @param {Number} columnIndex
45216 * @param {Roo.EventObject} e
45218 "headerdblclick" : true,
45220 * @event rowcontextmenu
45221 * Fires when a row is right clicked
45222 * @param {Grid} this
45223 * @param {Number} rowIndex
45224 * @param {Roo.EventObject} e
45226 "rowcontextmenu" : true,
45228 * @event cellcontextmenu
45229 * Fires when a cell is right clicked
45230 * @param {Grid} this
45231 * @param {Number} rowIndex
45232 * @param {Number} cellIndex
45233 * @param {Roo.EventObject} e
45235 "cellcontextmenu" : true,
45237 * @event headercontextmenu
45238 * Fires when a header is right clicked
45239 * @param {Grid} this
45240 * @param {Number} columnIndex
45241 * @param {Roo.EventObject} e
45243 "headercontextmenu" : true,
45245 * @event bodyscroll
45246 * Fires when the body element is scrolled
45247 * @param {Number} scrollLeft
45248 * @param {Number} scrollTop
45250 "bodyscroll" : true,
45252 * @event columnresize
45253 * Fires when the user resizes a column
45254 * @param {Number} columnIndex
45255 * @param {Number} newSize
45257 "columnresize" : true,
45259 * @event columnmove
45260 * Fires when the user moves a column
45261 * @param {Number} oldIndex
45262 * @param {Number} newIndex
45264 "columnmove" : true,
45267 * Fires when row(s) start being dragged
45268 * @param {Grid} this
45269 * @param {Roo.GridDD} dd The drag drop object
45270 * @param {event} e The raw browser event
45272 "startdrag" : true,
45275 * Fires when a drag operation is complete
45276 * @param {Grid} this
45277 * @param {Roo.GridDD} dd The drag drop object
45278 * @param {event} e The raw browser event
45283 * Fires when dragged row(s) are dropped on a valid DD target
45284 * @param {Grid} this
45285 * @param {Roo.GridDD} dd The drag drop object
45286 * @param {String} targetId The target drag drop object
45287 * @param {event} e The raw browser event
45292 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
45293 * @param {Grid} this
45294 * @param {Roo.GridDD} dd The drag drop object
45295 * @param {String} targetId The target drag drop object
45296 * @param {event} e The raw browser event
45301 * Fires when the dragged row(s) first cross another DD target while being dragged
45302 * @param {Grid} this
45303 * @param {Roo.GridDD} dd The drag drop object
45304 * @param {String} targetId The target drag drop object
45305 * @param {event} e The raw browser event
45307 "dragenter" : true,
45310 * Fires when the dragged row(s) leave another DD target while being dragged
45311 * @param {Grid} this
45312 * @param {Roo.GridDD} dd The drag drop object
45313 * @param {String} targetId The target drag drop object
45314 * @param {event} e The raw browser event
45319 * Fires when the grid is rendered
45320 * @param {Grid} grid
45325 Roo.grid.Grid.superclass.constructor.call(this);
45327 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
45329 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
45331 minColumnWidth : 25,
45334 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
45335 * <b>on initial render.</b> It is more efficient to explicitly size the columns
45336 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
45338 autoSizeColumns : false,
45341 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
45343 autoSizeHeaders : true,
45346 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
45348 monitorWindowResize : true,
45351 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
45352 * rows measured to get a columns size. Default is 0 (all rows).
45354 maxRowsToMeasure : 0,
45357 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
45359 trackMouseOver : true,
45362 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
45364 enableDragDrop : false,
45367 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
45369 enableColumnMove : true,
45372 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
45374 enableColumnHide : true,
45377 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
45379 enableRowHeightSync : false,
45382 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
45387 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
45389 autoHeight : false,
45392 * @cfg {String} autoExpandColumn The id (or dataIndex) of a column in this grid that should expand to fill unused space. This id can not be 0. Default is false.
45394 autoExpandColumn : false,
45397 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
45400 autoExpandMin : 50,
45403 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
45405 autoExpandMax : 1000,
45408 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
45413 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
45421 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
45422 * of a fixed width. Default is false.
45425 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
45428 * Called once after all setup has been completed and the grid is ready to be rendered.
45429 * @return {Roo.grid.Grid} this
45431 render : function(){
45432 var c = this.container;
45433 // try to detect autoHeight/width mode
45434 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
45435 this.autoHeight = true;
45437 var view = this.getView();
45440 c.on("click", this.onClick, this);
45441 c.on("dblclick", this.onDblClick, this);
45442 c.on("contextmenu", this.onContextMenu, this);
45443 c.on("keydown", this.onKeyDown, this);
45445 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
45447 this.getSelectionModel().init(this);
45452 this.loadMask = new Roo.LoadMask(this.container,
45453 Roo.apply({store:this.dataSource}, this.loadMask));
45457 if (this.toolbar && this.toolbar.xtype) {
45458 this.toolbar.container = this.getView().getHeaderPanel(true);
45459 this.toolbar = new Ext.Toolbar(this.toolbar);
45461 if (this.footer && this.footer.xtype) {
45462 this.footer.dataSource = this.getDataSource();
45463 this.footer.container = this.getView().getFooterPanel(true);
45464 this.footer = Roo.factory(this.footer, Roo);
45466 this.rendered = true;
45467 this.fireEvent('render', this);
45472 * Reconfigures the grid to use a different Store and Column Model.
45473 * The View will be bound to the new objects and refreshed.
45474 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
45475 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
45477 reconfigure : function(dataSource, colModel){
45479 this.loadMask.destroy();
45480 this.loadMask = new Roo.LoadMask(this.container,
45481 Roo.apply({store:dataSource}, this.loadMask));
45483 this.view.bind(dataSource, colModel);
45484 this.dataSource = dataSource;
45485 this.colModel = colModel;
45486 this.view.refresh(true);
45490 onKeyDown : function(e){
45491 this.fireEvent("keydown", e);
45495 * Destroy this grid.
45496 * @param {Boolean} removeEl True to remove the element
45498 destroy : function(removeEl, keepListeners){
45500 this.loadMask.destroy();
45502 var c = this.container;
45503 c.removeAllListeners();
45504 this.view.destroy();
45505 this.colModel.purgeListeners();
45506 if(!keepListeners){
45507 this.purgeListeners();
45510 if(removeEl === true){
45516 processEvent : function(name, e){
45517 this.fireEvent(name, e);
45518 var t = e.getTarget();
45520 var header = v.findHeaderIndex(t);
45521 if(header !== false){
45522 this.fireEvent("header" + name, this, header, e);
45524 var row = v.findRowIndex(t);
45525 var cell = v.findCellIndex(t);
45527 this.fireEvent("row" + name, this, row, e);
45528 if(cell !== false){
45529 this.fireEvent("cell" + name, this, row, cell, e);
45536 onClick : function(e){
45537 this.processEvent("click", e);
45541 onContextMenu : function(e, t){
45542 this.processEvent("contextmenu", e);
45546 onDblClick : function(e){
45547 this.processEvent("dblclick", e);
45551 walkCells : function(row, col, step, fn, scope){
45552 var cm = this.colModel, clen = cm.getColumnCount();
45553 var ds = this.dataSource, rlen = ds.getCount(), first = true;
45565 if(fn.call(scope || this, row, col, cm) === true){
45583 if(fn.call(scope || this, row, col, cm) === true){
45595 getSelections : function(){
45596 return this.selModel.getSelections();
45600 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
45601 * but if manual update is required this method will initiate it.
45603 autoSize : function(){
45605 this.view.layout();
45606 if(this.view.adjustForScroll){
45607 this.view.adjustForScroll();
45613 * Returns the grid's underlying element.
45614 * @return {Element} The element
45616 getGridEl : function(){
45617 return this.container;
45620 // private for compatibility, overridden by editor grid
45621 stopEditing : function(){},
45624 * Returns the grid's SelectionModel.
45625 * @return {SelectionModel}
45627 getSelectionModel : function(){
45628 if(!this.selModel){
45629 this.selModel = new Roo.grid.RowSelectionModel();
45631 return this.selModel;
45635 * Returns the grid's DataSource.
45636 * @return {DataSource}
45638 getDataSource : function(){
45639 return this.dataSource;
45643 * Returns the grid's ColumnModel.
45644 * @return {ColumnModel}
45646 getColumnModel : function(){
45647 return this.colModel;
45651 * Returns the grid's GridView object.
45652 * @return {GridView}
45654 getView : function(){
45656 this.view = new Roo.grid.GridView(this.viewConfig);
45661 * Called to get grid's drag proxy text, by default returns this.ddText.
45664 getDragDropText : function(){
45665 var count = this.selModel.getCount();
45666 return String.format(this.ddText, count, count == 1 ? '' : 's');
45670 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
45671 * %0 is replaced with the number of selected rows.
45674 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
45676 * Ext JS Library 1.1.1
45677 * Copyright(c) 2006-2007, Ext JS, LLC.
45679 * Originally Released Under LGPL - original licence link has changed is not relivant.
45682 * <script type="text/javascript">
45685 Roo.grid.AbstractGridView = function(){
45689 "beforerowremoved" : true,
45690 "beforerowsinserted" : true,
45691 "beforerefresh" : true,
45692 "rowremoved" : true,
45693 "rowsinserted" : true,
45694 "rowupdated" : true,
45697 Roo.grid.AbstractGridView.superclass.constructor.call(this);
45700 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
45701 rowClass : "x-grid-row",
45702 cellClass : "x-grid-cell",
45703 tdClass : "x-grid-td",
45704 hdClass : "x-grid-hd",
45705 splitClass : "x-grid-hd-split",
45707 init: function(grid){
45709 var cid = this.grid.getGridEl().id;
45710 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
45711 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
45712 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
45713 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
45716 getColumnRenderers : function(){
45717 var renderers = [];
45718 var cm = this.grid.colModel;
45719 var colCount = cm.getColumnCount();
45720 for(var i = 0; i < colCount; i++){
45721 renderers[i] = cm.getRenderer(i);
45726 getColumnIds : function(){
45728 var cm = this.grid.colModel;
45729 var colCount = cm.getColumnCount();
45730 for(var i = 0; i < colCount; i++){
45731 ids[i] = cm.getColumnId(i);
45736 getDataIndexes : function(){
45737 if(!this.indexMap){
45738 this.indexMap = this.buildIndexMap();
45740 return this.indexMap.colToData;
45743 getColumnIndexByDataIndex : function(dataIndex){
45744 if(!this.indexMap){
45745 this.indexMap = this.buildIndexMap();
45747 return this.indexMap.dataToCol[dataIndex];
45751 * Set a css style for a column dynamically.
45752 * @param {Number} colIndex The index of the column
45753 * @param {String} name The css property name
45754 * @param {String} value The css value
45756 setCSSStyle : function(colIndex, name, value){
45757 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
45758 Roo.util.CSS.updateRule(selector, name, value);
45761 generateRules : function(cm){
45762 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
45763 Roo.util.CSS.removeStyleSheet(rulesId);
45764 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
45765 var cid = cm.getColumnId(i);
45766 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
45767 this.tdSelector, cid, " {\n}\n",
45768 this.hdSelector, cid, " {\n}\n",
45769 this.splitSelector, cid, " {\n}\n");
45771 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
45775 * Ext JS Library 1.1.1
45776 * Copyright(c) 2006-2007, Ext JS, LLC.
45778 * Originally Released Under LGPL - original licence link has changed is not relivant.
45781 * <script type="text/javascript">
45785 // This is a support class used internally by the Grid components
45786 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
45788 this.view = grid.getView();
45789 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45790 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
45792 this.setHandleElId(Roo.id(hd));
45793 this.setOuterHandleElId(Roo.id(hd2));
45795 this.scroll = false;
45797 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
45799 getDragData : function(e){
45800 var t = Roo.lib.Event.getTarget(e);
45801 var h = this.view.findHeaderCell(t);
45803 return {ddel: h.firstChild, header:h};
45808 onInitDrag : function(e){
45809 this.view.headersDisabled = true;
45810 var clone = this.dragData.ddel.cloneNode(true);
45811 clone.id = Roo.id();
45812 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
45813 this.proxy.update(clone);
45817 afterValidDrop : function(){
45819 setTimeout(function(){
45820 v.headersDisabled = false;
45824 afterInvalidDrop : function(){
45826 setTimeout(function(){
45827 v.headersDisabled = false;
45833 * Ext JS Library 1.1.1
45834 * Copyright(c) 2006-2007, Ext JS, LLC.
45836 * Originally Released Under LGPL - original licence link has changed is not relivant.
45839 * <script type="text/javascript">
45842 // This is a support class used internally by the Grid components
45843 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
45845 this.view = grid.getView();
45846 // split the proxies so they don't interfere with mouse events
45847 this.proxyTop = Roo.DomHelper.append(document.body, {
45848 cls:"col-move-top", html:" "
45850 this.proxyBottom = Roo.DomHelper.append(document.body, {
45851 cls:"col-move-bottom", html:" "
45853 this.proxyTop.hide = this.proxyBottom.hide = function(){
45854 this.setLeftTop(-100,-100);
45855 this.setStyle("visibility", "hidden");
45857 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45858 // temporarily disabled
45859 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
45860 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
45862 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
45863 proxyOffsets : [-4, -9],
45864 fly: Roo.Element.fly,
45866 getTargetFromEvent : function(e){
45867 var t = Roo.lib.Event.getTarget(e);
45868 var cindex = this.view.findCellIndex(t);
45869 if(cindex !== false){
45870 return this.view.getHeaderCell(cindex);
45874 nextVisible : function(h){
45875 var v = this.view, cm = this.grid.colModel;
45878 if(!cm.isHidden(v.getCellIndex(h))){
45886 prevVisible : function(h){
45887 var v = this.view, cm = this.grid.colModel;
45890 if(!cm.isHidden(v.getCellIndex(h))){
45898 positionIndicator : function(h, n, e){
45899 var x = Roo.lib.Event.getPageX(e);
45900 var r = Roo.lib.Dom.getRegion(n.firstChild);
45901 var px, pt, py = r.top + this.proxyOffsets[1];
45902 if((r.right - x) <= (r.right-r.left)/2){
45903 px = r.right+this.view.borderWidth;
45909 var oldIndex = this.view.getCellIndex(h);
45910 var newIndex = this.view.getCellIndex(n);
45912 if(this.grid.colModel.isFixed(newIndex)){
45916 var locked = this.grid.colModel.isLocked(newIndex);
45921 if(oldIndex < newIndex){
45924 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
45927 px += this.proxyOffsets[0];
45928 this.proxyTop.setLeftTop(px, py);
45929 this.proxyTop.show();
45930 if(!this.bottomOffset){
45931 this.bottomOffset = this.view.mainHd.getHeight();
45933 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
45934 this.proxyBottom.show();
45938 onNodeEnter : function(n, dd, e, data){
45939 if(data.header != n){
45940 this.positionIndicator(data.header, n, e);
45944 onNodeOver : function(n, dd, e, data){
45945 var result = false;
45946 if(data.header != n){
45947 result = this.positionIndicator(data.header, n, e);
45950 this.proxyTop.hide();
45951 this.proxyBottom.hide();
45953 return result ? this.dropAllowed : this.dropNotAllowed;
45956 onNodeOut : function(n, dd, e, data){
45957 this.proxyTop.hide();
45958 this.proxyBottom.hide();
45961 onNodeDrop : function(n, dd, e, data){
45962 var h = data.header;
45964 var cm = this.grid.colModel;
45965 var x = Roo.lib.Event.getPageX(e);
45966 var r = Roo.lib.Dom.getRegion(n.firstChild);
45967 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
45968 var oldIndex = this.view.getCellIndex(h);
45969 var newIndex = this.view.getCellIndex(n);
45970 var locked = cm.isLocked(newIndex);
45974 if(oldIndex < newIndex){
45977 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
45980 cm.setLocked(oldIndex, locked, true);
45981 cm.moveColumn(oldIndex, newIndex);
45982 this.grid.fireEvent("columnmove", oldIndex, newIndex);
45990 * Ext JS Library 1.1.1
45991 * Copyright(c) 2006-2007, Ext JS, LLC.
45993 * Originally Released Under LGPL - original licence link has changed is not relivant.
45996 * <script type="text/javascript">
46000 * @class Roo.grid.GridView
46001 * @extends Roo.util.Observable
46004 * @param {Object} config
46006 Roo.grid.GridView = function(config){
46007 Roo.grid.GridView.superclass.constructor.call(this);
46010 Roo.apply(this, config);
46013 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
46016 * Override this function to apply custom css classes to rows during rendering
46017 * @param {Record} record The record
46018 * @param {Number} index
46019 * @method getRowClass
46021 rowClass : "x-grid-row",
46023 cellClass : "x-grid-col",
46025 tdClass : "x-grid-td",
46027 hdClass : "x-grid-hd",
46029 splitClass : "x-grid-split",
46031 sortClasses : ["sort-asc", "sort-desc"],
46033 enableMoveAnim : false,
46037 dh : Roo.DomHelper,
46039 fly : Roo.Element.fly,
46041 css : Roo.util.CSS,
46047 scrollIncrement : 22,
46049 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
46051 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
46053 bind : function(ds, cm){
46055 this.ds.un("load", this.onLoad, this);
46056 this.ds.un("datachanged", this.onDataChange, this);
46057 this.ds.un("add", this.onAdd, this);
46058 this.ds.un("remove", this.onRemove, this);
46059 this.ds.un("update", this.onUpdate, this);
46060 this.ds.un("clear", this.onClear, this);
46063 ds.on("load", this.onLoad, this);
46064 ds.on("datachanged", this.onDataChange, this);
46065 ds.on("add", this.onAdd, this);
46066 ds.on("remove", this.onRemove, this);
46067 ds.on("update", this.onUpdate, this);
46068 ds.on("clear", this.onClear, this);
46073 this.cm.un("widthchange", this.onColWidthChange, this);
46074 this.cm.un("headerchange", this.onHeaderChange, this);
46075 this.cm.un("hiddenchange", this.onHiddenChange, this);
46076 this.cm.un("columnmoved", this.onColumnMove, this);
46077 this.cm.un("columnlockchange", this.onColumnLock, this);
46080 this.generateRules(cm);
46081 cm.on("widthchange", this.onColWidthChange, this);
46082 cm.on("headerchange", this.onHeaderChange, this);
46083 cm.on("hiddenchange", this.onHiddenChange, this);
46084 cm.on("columnmoved", this.onColumnMove, this);
46085 cm.on("columnlockchange", this.onColumnLock, this);
46090 init: function(grid){
46091 Roo.grid.GridView.superclass.init.call(this, grid);
46093 this.bind(grid.dataSource, grid.colModel);
46095 grid.on("headerclick", this.handleHeaderClick, this);
46097 if(grid.trackMouseOver){
46098 grid.on("mouseover", this.onRowOver, this);
46099 grid.on("mouseout", this.onRowOut, this);
46101 grid.cancelTextSelection = function(){};
46102 this.gridId = grid.id;
46104 var tpls = this.templates || {};
46107 tpls.master = new Roo.Template(
46108 '<div class="x-grid" hidefocus="true">',
46109 '<div class="x-grid-topbar"></div>',
46110 '<div class="x-grid-scroller"><div></div></div>',
46111 '<div class="x-grid-locked">',
46112 '<div class="x-grid-header">{lockedHeader}</div>',
46113 '<div class="x-grid-body">{lockedBody}</div>',
46115 '<div class="x-grid-viewport">',
46116 '<div class="x-grid-header">{header}</div>',
46117 '<div class="x-grid-body">{body}</div>',
46119 '<div class="x-grid-bottombar"></div>',
46120 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
46121 '<div class="x-grid-resize-proxy"> </div>',
46124 tpls.master.disableformats = true;
46128 tpls.header = new Roo.Template(
46129 '<table border="0" cellspacing="0" cellpadding="0">',
46130 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
46133 tpls.header.disableformats = true;
46135 tpls.header.compile();
46138 tpls.hcell = new Roo.Template(
46139 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
46140 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
46143 tpls.hcell.disableFormats = true;
46145 tpls.hcell.compile();
46148 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
46149 tpls.hsplit.disableFormats = true;
46151 tpls.hsplit.compile();
46154 tpls.body = new Roo.Template(
46155 '<table border="0" cellspacing="0" cellpadding="0">',
46156 "<tbody>{rows}</tbody>",
46159 tpls.body.disableFormats = true;
46161 tpls.body.compile();
46164 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
46165 tpls.row.disableFormats = true;
46167 tpls.row.compile();
46170 tpls.cell = new Roo.Template(
46171 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
46172 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
46175 tpls.cell.disableFormats = true;
46177 tpls.cell.compile();
46179 this.templates = tpls;
46182 // remap these for backwards compat
46183 onColWidthChange : function(){
46184 this.updateColumns.apply(this, arguments);
46186 onHeaderChange : function(){
46187 this.updateHeaders.apply(this, arguments);
46189 onHiddenChange : function(){
46190 this.handleHiddenChange.apply(this, arguments);
46192 onColumnMove : function(){
46193 this.handleColumnMove.apply(this, arguments);
46195 onColumnLock : function(){
46196 this.handleLockChange.apply(this, arguments);
46199 onDataChange : function(){
46201 this.updateHeaderSortState();
46204 onClear : function(){
46208 onUpdate : function(ds, record){
46209 this.refreshRow(record);
46212 refreshRow : function(record){
46213 var ds = this.ds, index;
46214 if(typeof record == 'number'){
46216 record = ds.getAt(index);
46218 index = ds.indexOf(record);
46220 this.insertRows(ds, index, index, true);
46221 this.onRemove(ds, record, index+1, true);
46222 this.syncRowHeights(index, index);
46224 this.fireEvent("rowupdated", this, index, record);
46227 onAdd : function(ds, records, index){
46228 this.insertRows(ds, index, index + (records.length-1));
46231 onRemove : function(ds, record, index, isUpdate){
46232 if(isUpdate !== true){
46233 this.fireEvent("beforerowremoved", this, index, record);
46235 var bt = this.getBodyTable(), lt = this.getLockedTable();
46236 if(bt.rows[index]){
46237 bt.firstChild.removeChild(bt.rows[index]);
46239 if(lt.rows[index]){
46240 lt.firstChild.removeChild(lt.rows[index]);
46242 if(isUpdate !== true){
46243 this.stripeRows(index);
46244 this.syncRowHeights(index, index);
46246 this.fireEvent("rowremoved", this, index, record);
46250 onLoad : function(){
46251 this.scrollToTop();
46255 * Scrolls the grid to the top
46257 scrollToTop : function(){
46259 this.scroller.dom.scrollTop = 0;
46265 * Gets a panel in the header of the grid that can be used for toolbars etc.
46266 * After modifying the contents of this panel a call to grid.autoSize() may be
46267 * required to register any changes in size.
46268 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
46269 * @return Roo.Element
46271 getHeaderPanel : function(doShow){
46273 this.headerPanel.show();
46275 return this.headerPanel;
46279 * Gets a panel in the footer of the grid that can be used for toolbars etc.
46280 * After modifying the contents of this panel a call to grid.autoSize() may be
46281 * required to register any changes in size.
46282 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
46283 * @return Roo.Element
46285 getFooterPanel : function(doShow){
46287 this.footerPanel.show();
46289 return this.footerPanel;
46292 initElements : function(){
46293 var E = Roo.Element;
46294 var el = this.grid.getGridEl().dom.firstChild;
46295 var cs = el.childNodes;
46297 this.el = new E(el);
46298 this.headerPanel = new E(el.firstChild);
46299 this.headerPanel.enableDisplayMode("block");
46301 this.scroller = new E(cs[1]);
46302 this.scrollSizer = new E(this.scroller.dom.firstChild);
46304 this.lockedWrap = new E(cs[2]);
46305 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
46306 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
46308 this.mainWrap = new E(cs[3]);
46309 this.mainHd = new E(this.mainWrap.dom.firstChild);
46310 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
46312 this.footerPanel = new E(cs[4]);
46313 this.footerPanel.enableDisplayMode("block");
46315 this.focusEl = new E(cs[5]);
46316 this.focusEl.swallowEvent("click", true);
46317 this.resizeProxy = new E(cs[6]);
46319 this.headerSelector = String.format(
46320 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
46321 this.lockedHd.id, this.mainHd.id
46324 this.splitterSelector = String.format(
46325 '#{0} div.x-grid-split, #{1} div.x-grid-split',
46326 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
46329 idToCssName : function(s)
46331 return s.replace(/[^a-z0-9]+/ig, '-');
46334 getHeaderCell : function(index){
46335 return Roo.DomQuery.select(this.headerSelector)[index];
46338 getHeaderCellMeasure : function(index){
46339 return this.getHeaderCell(index).firstChild;
46342 getHeaderCellText : function(index){
46343 return this.getHeaderCell(index).firstChild.firstChild;
46346 getLockedTable : function(){
46347 return this.lockedBody.dom.firstChild;
46350 getBodyTable : function(){
46351 return this.mainBody.dom.firstChild;
46354 getLockedRow : function(index){
46355 return this.getLockedTable().rows[index];
46358 getRow : function(index){
46359 return this.getBodyTable().rows[index];
46362 getRowComposite : function(index){
46364 this.rowEl = new Roo.CompositeElementLite();
46366 var els = [], lrow, mrow;
46367 if(lrow = this.getLockedRow(index)){
46370 if(mrow = this.getRow(index)){
46373 this.rowEl.elements = els;
46377 getCell : function(rowIndex, colIndex){
46378 var locked = this.cm.getLockedCount();
46380 if(colIndex < locked){
46381 source = this.lockedBody.dom.firstChild;
46383 source = this.mainBody.dom.firstChild;
46384 colIndex -= locked;
46386 return source.rows[rowIndex].childNodes[colIndex];
46389 getCellText : function(rowIndex, colIndex){
46390 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
46393 getCellBox : function(cell){
46394 var b = this.fly(cell).getBox();
46395 if(Roo.isOpera){ // opera fails to report the Y
46396 b.y = cell.offsetTop + this.mainBody.getY();
46401 getCellIndex : function(cell){
46402 var id = String(cell.className).match(this.cellRE);
46404 return parseInt(id[1], 10);
46409 findHeaderIndex : function(n){
46410 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46411 return r ? this.getCellIndex(r) : false;
46414 findHeaderCell : function(n){
46415 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46416 return r ? r : false;
46419 findRowIndex : function(n){
46423 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
46424 return r ? r.rowIndex : false;
46427 findCellIndex : function(node){
46428 var stop = this.el.dom;
46429 while(node && node != stop){
46430 if(this.findRE.test(node.className)){
46431 return this.getCellIndex(node);
46433 node = node.parentNode;
46438 getColumnId : function(index){
46439 return this.cm.getColumnId(index);
46442 getSplitters : function(){
46443 if(this.splitterSelector){
46444 return Roo.DomQuery.select(this.splitterSelector);
46450 getSplitter : function(index){
46451 return this.getSplitters()[index];
46454 onRowOver : function(e, t){
46456 if((row = this.findRowIndex(t)) !== false){
46457 this.getRowComposite(row).addClass("x-grid-row-over");
46461 onRowOut : function(e, t){
46463 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
46464 this.getRowComposite(row).removeClass("x-grid-row-over");
46468 renderHeaders : function(){
46470 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
46471 var cb = [], lb = [], sb = [], lsb = [], p = {};
46472 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46473 p.cellId = "x-grid-hd-0-" + i;
46474 p.splitId = "x-grid-csplit-0-" + i;
46475 p.id = cm.getColumnId(i);
46476 p.title = cm.getColumnTooltip(i) || "";
46477 p.value = cm.getColumnHeader(i) || "";
46478 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
46479 if(!cm.isLocked(i)){
46480 cb[cb.length] = ct.apply(p);
46481 sb[sb.length] = st.apply(p);
46483 lb[lb.length] = ct.apply(p);
46484 lsb[lsb.length] = st.apply(p);
46487 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
46488 ht.apply({cells: cb.join(""), splits:sb.join("")})];
46491 updateHeaders : function(){
46492 var html = this.renderHeaders();
46493 this.lockedHd.update(html[0]);
46494 this.mainHd.update(html[1]);
46498 * Focuses the specified row.
46499 * @param {Number} row The row index
46501 focusRow : function(row){
46502 var x = this.scroller.dom.scrollLeft;
46503 this.focusCell(row, 0, false);
46504 this.scroller.dom.scrollLeft = x;
46508 * Focuses the specified cell.
46509 * @param {Number} row The row index
46510 * @param {Number} col The column index
46511 * @param {Boolean} hscroll false to disable horizontal scrolling
46513 focusCell : function(row, col, hscroll){
46514 var el = this.ensureVisible(row, col, hscroll);
46515 this.focusEl.alignTo(el, "tl-tl");
46517 this.focusEl.focus();
46519 this.focusEl.focus.defer(1, this.focusEl);
46524 * Scrolls the specified cell into view
46525 * @param {Number} row The row index
46526 * @param {Number} col The column index
46527 * @param {Boolean} hscroll false to disable horizontal scrolling
46529 ensureVisible : function(row, col, hscroll){
46530 if(typeof row != "number"){
46531 row = row.rowIndex;
46533 if(row < 0 && row >= this.ds.getCount()){
46536 col = (col !== undefined ? col : 0);
46537 var cm = this.grid.colModel;
46538 while(cm.isHidden(col)){
46542 var el = this.getCell(row, col);
46546 var c = this.scroller.dom;
46548 var ctop = parseInt(el.offsetTop, 10);
46549 var cleft = parseInt(el.offsetLeft, 10);
46550 var cbot = ctop + el.offsetHeight;
46551 var cright = cleft + el.offsetWidth;
46553 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
46554 var stop = parseInt(c.scrollTop, 10);
46555 var sleft = parseInt(c.scrollLeft, 10);
46556 var sbot = stop + ch;
46557 var sright = sleft + c.clientWidth;
46560 c.scrollTop = ctop;
46561 }else if(cbot > sbot){
46562 c.scrollTop = cbot-ch;
46565 if(hscroll !== false){
46567 c.scrollLeft = cleft;
46568 }else if(cright > sright){
46569 c.scrollLeft = cright-c.clientWidth;
46575 updateColumns : function(){
46576 this.grid.stopEditing();
46577 var cm = this.grid.colModel, colIds = this.getColumnIds();
46578 //var totalWidth = cm.getTotalWidth();
46580 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46581 //if(cm.isHidden(i)) continue;
46582 var w = cm.getColumnWidth(i);
46583 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46584 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46586 this.updateSplitters();
46589 generateRules : function(cm){
46590 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
46591 Roo.util.CSS.removeStyleSheet(rulesId);
46592 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46593 var cid = cm.getColumnId(i);
46595 if(cm.config[i].align){
46596 align = 'text-align:'+cm.config[i].align+';';
46599 if(cm.isHidden(i)){
46600 hidden = 'display:none;';
46602 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
46604 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
46605 this.hdSelector, cid, " {\n", align, width, "}\n",
46606 this.tdSelector, cid, " {\n",hidden,"\n}\n",
46607 this.splitSelector, cid, " {\n", hidden , "\n}\n");
46609 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46612 updateSplitters : function(){
46613 var cm = this.cm, s = this.getSplitters();
46614 if(s){ // splitters not created yet
46615 var pos = 0, locked = true;
46616 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46617 if(cm.isHidden(i)) continue;
46618 var w = cm.getColumnWidth(i);
46619 if(!cm.isLocked(i) && locked){
46624 s[i].style.left = (pos-this.splitOffset) + "px";
46629 handleHiddenChange : function(colModel, colIndex, hidden){
46631 this.hideColumn(colIndex);
46633 this.unhideColumn(colIndex);
46637 hideColumn : function(colIndex){
46638 var cid = this.getColumnId(colIndex);
46639 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
46640 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
46642 this.updateHeaders();
46644 this.updateSplitters();
46648 unhideColumn : function(colIndex){
46649 var cid = this.getColumnId(colIndex);
46650 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
46651 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
46654 this.updateHeaders();
46656 this.updateSplitters();
46660 insertRows : function(dm, firstRow, lastRow, isUpdate){
46661 if(firstRow == 0 && lastRow == dm.getCount()-1){
46665 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
46667 var s = this.getScrollState();
46668 var markup = this.renderRows(firstRow, lastRow);
46669 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
46670 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
46671 this.restoreScroll(s);
46673 this.fireEvent("rowsinserted", this, firstRow, lastRow);
46674 this.syncRowHeights(firstRow, lastRow);
46675 this.stripeRows(firstRow);
46681 bufferRows : function(markup, target, index){
46682 var before = null, trows = target.rows, tbody = target.tBodies[0];
46683 if(index < trows.length){
46684 before = trows[index];
46686 var b = document.createElement("div");
46687 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
46688 var rows = b.firstChild.rows;
46689 for(var i = 0, len = rows.length; i < len; i++){
46691 tbody.insertBefore(rows[0], before);
46693 tbody.appendChild(rows[0]);
46700 deleteRows : function(dm, firstRow, lastRow){
46701 if(dm.getRowCount()<1){
46702 this.fireEvent("beforerefresh", this);
46703 this.mainBody.update("");
46704 this.lockedBody.update("");
46705 this.fireEvent("refresh", this);
46707 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
46708 var bt = this.getBodyTable();
46709 var tbody = bt.firstChild;
46710 var rows = bt.rows;
46711 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
46712 tbody.removeChild(rows[firstRow]);
46714 this.stripeRows(firstRow);
46715 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
46719 updateRows : function(dataSource, firstRow, lastRow){
46720 var s = this.getScrollState();
46722 this.restoreScroll(s);
46725 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
46729 this.updateHeaderSortState();
46732 getScrollState : function(){
46733 var sb = this.scroller.dom;
46734 return {left: sb.scrollLeft, top: sb.scrollTop};
46737 stripeRows : function(startRow){
46738 if(!this.grid.stripeRows || this.ds.getCount() < 1){
46741 startRow = startRow || 0;
46742 var rows = this.getBodyTable().rows;
46743 var lrows = this.getLockedTable().rows;
46744 var cls = ' x-grid-row-alt ';
46745 for(var i = startRow, len = rows.length; i < len; i++){
46746 var row = rows[i], lrow = lrows[i];
46747 var isAlt = ((i+1) % 2 == 0);
46748 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
46749 if(isAlt == hasAlt){
46753 row.className += " x-grid-row-alt";
46755 row.className = row.className.replace("x-grid-row-alt", "");
46758 lrow.className = row.className;
46763 restoreScroll : function(state){
46764 var sb = this.scroller.dom;
46765 sb.scrollLeft = state.left;
46766 sb.scrollTop = state.top;
46770 syncScroll : function(){
46771 var sb = this.scroller.dom;
46772 var sh = this.mainHd.dom;
46773 var bs = this.mainBody.dom;
46774 var lv = this.lockedBody.dom;
46775 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
46776 lv.scrollTop = bs.scrollTop = sb.scrollTop;
46779 handleScroll : function(e){
46781 var sb = this.scroller.dom;
46782 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
46786 handleWheel : function(e){
46787 var d = e.getWheelDelta();
46788 this.scroller.dom.scrollTop -= d*22;
46789 // set this here to prevent jumpy scrolling on large tables
46790 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
46794 renderRows : function(startRow, endRow){
46795 // pull in all the crap needed to render rows
46796 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
46797 var colCount = cm.getColumnCount();
46799 if(ds.getCount() < 1){
46803 // build a map for all the columns
46805 for(var i = 0; i < colCount; i++){
46806 var name = cm.getDataIndex(i);
46808 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
46809 renderer : cm.getRenderer(i),
46810 id : cm.getColumnId(i),
46811 locked : cm.isLocked(i)
46815 startRow = startRow || 0;
46816 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
46818 // records to render
46819 var rs = ds.getRange(startRow, endRow);
46821 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
46824 // As much as I hate to duplicate code, this was branched because FireFox really hates
46825 // [].join("") on strings. The performance difference was substantial enough to
46826 // branch this function
46827 doRender : Roo.isGecko ?
46828 function(cs, rs, ds, startRow, colCount, stripe){
46829 var ts = this.templates, ct = ts.cell, rt = ts.row;
46831 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
46832 for(var j = 0, len = rs.length; j < len; j++){
46833 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
46834 for(var i = 0; i < colCount; i++){
46836 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
46838 p.css = p.attr = "";
46839 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
46840 if(p.value == undefined || p.value === "") p.value = " ";
46841 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
46842 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
46844 var markup = ct.apply(p);
46852 if(stripe && ((rowIndex+1) % 2 == 0)){
46853 alt[0] = "x-grid-row-alt";
46856 alt[1] = " x-grid-dirty-row";
46859 if(this.getRowClass){
46860 alt[2] = this.getRowClass(r, rowIndex);
46862 rp.alt = alt.join(" ");
46863 lbuf+= rt.apply(rp);
46865 buf+= rt.apply(rp);
46867 return [lbuf, buf];
46869 function(cs, rs, ds, startRow, colCount, stripe){
46870 var ts = this.templates, ct = ts.cell, rt = ts.row;
46872 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
46873 for(var j = 0, len = rs.length; j < len; j++){
46874 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
46875 for(var i = 0; i < colCount; i++){
46877 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
46879 p.css = p.attr = "";
46880 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
46881 if(p.value == undefined || p.value === "") p.value = " ";
46882 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
46883 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
46885 var markup = ct.apply(p);
46887 cb[cb.length] = markup;
46889 lcb[lcb.length] = markup;
46893 if(stripe && ((rowIndex+1) % 2 == 0)){
46894 alt[0] = "x-grid-row-alt";
46897 alt[1] = " x-grid-dirty-row";
46900 if(this.getRowClass){
46901 alt[2] = this.getRowClass(r, rowIndex);
46903 rp.alt = alt.join(" ");
46904 rp.cells = lcb.join("");
46905 lbuf[lbuf.length] = rt.apply(rp);
46906 rp.cells = cb.join("");
46907 buf[buf.length] = rt.apply(rp);
46909 return [lbuf.join(""), buf.join("")];
46912 renderBody : function(){
46913 var markup = this.renderRows();
46914 var bt = this.templates.body;
46915 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
46919 * Refreshes the grid
46920 * @param {Boolean} headersToo
46922 refresh : function(headersToo){
46923 this.fireEvent("beforerefresh", this);
46924 this.grid.stopEditing();
46925 var result = this.renderBody();
46926 this.lockedBody.update(result[0]);
46927 this.mainBody.update(result[1]);
46928 if(headersToo === true){
46929 this.updateHeaders();
46930 this.updateColumns();
46931 this.updateSplitters();
46932 this.updateHeaderSortState();
46934 this.syncRowHeights();
46936 this.fireEvent("refresh", this);
46939 handleColumnMove : function(cm, oldIndex, newIndex){
46940 this.indexMap = null;
46941 var s = this.getScrollState();
46942 this.refresh(true);
46943 this.restoreScroll(s);
46944 this.afterMove(newIndex);
46947 afterMove : function(colIndex){
46948 if(this.enableMoveAnim && Roo.enableFx){
46949 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
46953 updateCell : function(dm, rowIndex, dataIndex){
46954 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
46955 if(typeof colIndex == "undefined"){ // not present in grid
46958 var cm = this.grid.colModel;
46959 var cell = this.getCell(rowIndex, colIndex);
46960 var cellText = this.getCellText(rowIndex, colIndex);
46963 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
46964 id : cm.getColumnId(colIndex),
46965 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
46967 var renderer = cm.getRenderer(colIndex);
46968 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
46969 if(typeof val == "undefined" || val === "") val = " ";
46970 cellText.innerHTML = val;
46971 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
46972 this.syncRowHeights(rowIndex, rowIndex);
46975 calcColumnWidth : function(colIndex, maxRowsToMeasure){
46977 if(this.grid.autoSizeHeaders){
46978 var h = this.getHeaderCellMeasure(colIndex);
46979 maxWidth = Math.max(maxWidth, h.scrollWidth);
46982 if(this.cm.isLocked(colIndex)){
46983 tb = this.getLockedTable();
46986 tb = this.getBodyTable();
46987 index = colIndex - this.cm.getLockedCount();
46990 var rows = tb.rows;
46991 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
46992 for(var i = 0; i < stopIndex; i++){
46993 var cell = rows[i].childNodes[index].firstChild;
46994 maxWidth = Math.max(maxWidth, cell.scrollWidth);
46997 return maxWidth + /*margin for error in IE*/ 5;
47000 * Autofit a column to its content.
47001 * @param {Number} colIndex
47002 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
47004 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
47005 if(this.cm.isHidden(colIndex)){
47006 return; // can't calc a hidden column
47009 var cid = this.cm.getColumnId(colIndex);
47010 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
47011 if(this.grid.autoSizeHeaders){
47012 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
47015 var newWidth = this.calcColumnWidth(colIndex);
47016 this.cm.setColumnWidth(colIndex,
47017 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
47018 if(!suppressEvent){
47019 this.grid.fireEvent("columnresize", colIndex, newWidth);
47024 * Autofits all columns to their content and then expands to fit any extra space in the grid
47026 autoSizeColumns : function(){
47027 var cm = this.grid.colModel;
47028 var colCount = cm.getColumnCount();
47029 for(var i = 0; i < colCount; i++){
47030 this.autoSizeColumn(i, true, true);
47032 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
47035 this.updateColumns();
47041 * Autofits all columns to the grid's width proportionate with their current size
47042 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
47044 fitColumns : function(reserveScrollSpace){
47045 var cm = this.grid.colModel;
47046 var colCount = cm.getColumnCount();
47050 for (i = 0; i < colCount; i++){
47051 if(!cm.isHidden(i) && !cm.isFixed(i)){
47052 w = cm.getColumnWidth(i);
47058 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
47059 if(reserveScrollSpace){
47062 var frac = (avail - cm.getTotalWidth())/width;
47063 while (cols.length){
47066 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
47068 this.updateColumns();
47072 onRowSelect : function(rowIndex){
47073 var row = this.getRowComposite(rowIndex);
47074 row.addClass("x-grid-row-selected");
47077 onRowDeselect : function(rowIndex){
47078 var row = this.getRowComposite(rowIndex);
47079 row.removeClass("x-grid-row-selected");
47082 onCellSelect : function(row, col){
47083 var cell = this.getCell(row, col);
47085 Roo.fly(cell).addClass("x-grid-cell-selected");
47089 onCellDeselect : function(row, col){
47090 var cell = this.getCell(row, col);
47092 Roo.fly(cell).removeClass("x-grid-cell-selected");
47096 updateHeaderSortState : function(){
47097 var state = this.ds.getSortState();
47101 this.sortState = state;
47102 var sortColumn = this.cm.findColumnIndex(state.field);
47103 if(sortColumn != -1){
47104 var sortDir = state.direction;
47105 var sc = this.sortClasses;
47106 var hds = this.el.select(this.headerSelector).removeClass(sc);
47107 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
47111 handleHeaderClick : function(g, index){
47112 if(this.headersDisabled){
47115 var dm = g.dataSource, cm = g.colModel;
47116 if(!cm.isSortable(index)){
47120 dm.sort(cm.getDataIndex(index));
47124 destroy : function(){
47126 this.colMenu.removeAll();
47127 Roo.menu.MenuMgr.unregister(this.colMenu);
47128 this.colMenu.getEl().remove();
47129 delete this.colMenu;
47132 this.hmenu.removeAll();
47133 Roo.menu.MenuMgr.unregister(this.hmenu);
47134 this.hmenu.getEl().remove();
47137 if(this.grid.enableColumnMove){
47138 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47140 for(var dd in dds){
47141 if(!dds[dd].config.isTarget && dds[dd].dragElId){
47142 var elid = dds[dd].dragElId;
47144 Roo.get(elid).remove();
47145 } else if(dds[dd].config.isTarget){
47146 dds[dd].proxyTop.remove();
47147 dds[dd].proxyBottom.remove();
47150 if(Roo.dd.DDM.locationCache[dd]){
47151 delete Roo.dd.DDM.locationCache[dd];
47154 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47157 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
47158 this.bind(null, null);
47159 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
47162 handleLockChange : function(){
47163 this.refresh(true);
47166 onDenyColumnLock : function(){
47170 onDenyColumnHide : function(){
47174 handleHdMenuClick : function(item){
47175 var index = this.hdCtxIndex;
47176 var cm = this.cm, ds = this.ds;
47179 ds.sort(cm.getDataIndex(index), "ASC");
47182 ds.sort(cm.getDataIndex(index), "DESC");
47185 var lc = cm.getLockedCount();
47186 if(cm.getColumnCount(true) <= lc+1){
47187 this.onDenyColumnLock();
47191 cm.setLocked(index, true, true);
47192 cm.moveColumn(index, lc);
47193 this.grid.fireEvent("columnmove", index, lc);
47195 cm.setLocked(index, true);
47199 var lc = cm.getLockedCount();
47200 if((lc-1) != index){
47201 cm.setLocked(index, false, true);
47202 cm.moveColumn(index, lc-1);
47203 this.grid.fireEvent("columnmove", index, lc-1);
47205 cm.setLocked(index, false);
47209 index = cm.getIndexById(item.id.substr(4));
47211 if(item.checked && cm.getColumnCount(true) <= 1){
47212 this.onDenyColumnHide();
47215 cm.setHidden(index, item.checked);
47221 beforeColMenuShow : function(){
47222 var cm = this.cm, colCount = cm.getColumnCount();
47223 this.colMenu.removeAll();
47224 for(var i = 0; i < colCount; i++){
47225 this.colMenu.add(new Roo.menu.CheckItem({
47226 id: "col-"+cm.getColumnId(i),
47227 text: cm.getColumnHeader(i),
47228 checked: !cm.isHidden(i),
47234 handleHdCtx : function(g, index, e){
47236 var hd = this.getHeaderCell(index);
47237 this.hdCtxIndex = index;
47238 var ms = this.hmenu.items, cm = this.cm;
47239 ms.get("asc").setDisabled(!cm.isSortable(index));
47240 ms.get("desc").setDisabled(!cm.isSortable(index));
47241 if(this.grid.enableColLock !== false){
47242 ms.get("lock").setDisabled(cm.isLocked(index));
47243 ms.get("unlock").setDisabled(!cm.isLocked(index));
47245 this.hmenu.show(hd, "tl-bl");
47248 handleHdOver : function(e){
47249 var hd = this.findHeaderCell(e.getTarget());
47250 if(hd && !this.headersDisabled){
47251 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
47252 this.fly(hd).addClass("x-grid-hd-over");
47257 handleHdOut : function(e){
47258 var hd = this.findHeaderCell(e.getTarget());
47260 this.fly(hd).removeClass("x-grid-hd-over");
47264 handleSplitDblClick : function(e, t){
47265 var i = this.getCellIndex(t);
47266 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
47267 this.autoSizeColumn(i, true);
47272 render : function(){
47275 var colCount = cm.getColumnCount();
47277 if(this.grid.monitorWindowResize === true){
47278 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47280 var header = this.renderHeaders();
47281 var body = this.templates.body.apply({rows:""});
47282 var html = this.templates.master.apply({
47285 lockedHeader: header[0],
47289 //this.updateColumns();
47291 this.grid.getGridEl().dom.innerHTML = html;
47293 this.initElements();
47295 this.scroller.on("scroll", this.handleScroll, this);
47296 this.lockedBody.on("mousewheel", this.handleWheel, this);
47297 this.mainBody.on("mousewheel", this.handleWheel, this);
47299 this.mainHd.on("mouseover", this.handleHdOver, this);
47300 this.mainHd.on("mouseout", this.handleHdOut, this);
47301 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
47302 {delegate: "."+this.splitClass});
47304 this.lockedHd.on("mouseover", this.handleHdOver, this);
47305 this.lockedHd.on("mouseout", this.handleHdOut, this);
47306 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
47307 {delegate: "."+this.splitClass});
47309 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
47310 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47313 this.updateSplitters();
47315 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
47316 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47317 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47320 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
47321 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
47323 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
47324 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
47326 if(this.grid.enableColLock !== false){
47327 this.hmenu.add('-',
47328 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
47329 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
47332 if(this.grid.enableColumnHide !== false){
47334 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
47335 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
47336 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
47338 this.hmenu.add('-',
47339 {id:"columns", text: this.columnsText, menu: this.colMenu}
47342 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
47344 this.grid.on("headercontextmenu", this.handleHdCtx, this);
47347 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
47348 this.dd = new Roo.grid.GridDragZone(this.grid, {
47349 ddGroup : this.grid.ddGroup || 'GridDD'
47354 for(var i = 0; i < colCount; i++){
47355 if(cm.isHidden(i)){
47356 this.hideColumn(i);
47358 if(cm.config[i].align){
47359 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
47360 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
47364 this.updateHeaderSortState();
47366 this.beforeInitialResize();
47369 // two part rendering gives faster view to the user
47370 this.renderPhase2.defer(1, this);
47373 renderPhase2 : function(){
47374 // render the rows now
47376 if(this.grid.autoSizeColumns){
47377 this.autoSizeColumns();
47381 beforeInitialResize : function(){
47385 onColumnSplitterMoved : function(i, w){
47386 this.userResized = true;
47387 var cm = this.grid.colModel;
47388 cm.setColumnWidth(i, w, true);
47389 var cid = cm.getColumnId(i);
47390 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47391 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47392 this.updateSplitters();
47394 this.grid.fireEvent("columnresize", i, w);
47397 syncRowHeights : function(startIndex, endIndex){
47398 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
47399 startIndex = startIndex || 0;
47400 var mrows = this.getBodyTable().rows;
47401 var lrows = this.getLockedTable().rows;
47402 var len = mrows.length-1;
47403 endIndex = Math.min(endIndex || len, len);
47404 for(var i = startIndex; i <= endIndex; i++){
47405 var m = mrows[i], l = lrows[i];
47406 var h = Math.max(m.offsetHeight, l.offsetHeight);
47407 m.style.height = l.style.height = h + "px";
47412 layout : function(initialRender, is2ndPass){
47414 var auto = g.autoHeight;
47415 var scrollOffset = 16;
47416 var c = g.getGridEl(), cm = this.cm,
47417 expandCol = g.autoExpandColumn,
47419 //c.beginMeasure();
47421 if(!c.dom.offsetWidth){ // display:none?
47423 this.lockedWrap.show();
47424 this.mainWrap.show();
47429 var hasLock = this.cm.isLocked(0);
47431 var tbh = this.headerPanel.getHeight();
47432 var bbh = this.footerPanel.getHeight();
47435 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
47436 var newHeight = ch + c.getBorderWidth("tb");
47438 newHeight = Math.min(g.maxHeight, newHeight);
47440 c.setHeight(newHeight);
47444 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
47447 var s = this.scroller;
47449 var csize = c.getSize(true);
47451 this.el.setSize(csize.width, csize.height);
47453 this.headerPanel.setWidth(csize.width);
47454 this.footerPanel.setWidth(csize.width);
47456 var hdHeight = this.mainHd.getHeight();
47457 var vw = csize.width;
47458 var vh = csize.height - (tbh + bbh);
47462 var bt = this.getBodyTable();
47463 var ltWidth = hasLock ?
47464 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
47466 var scrollHeight = bt.offsetHeight;
47467 var scrollWidth = ltWidth + bt.offsetWidth;
47468 var vscroll = false, hscroll = false;
47470 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
47472 var lw = this.lockedWrap, mw = this.mainWrap;
47473 var lb = this.lockedBody, mb = this.mainBody;
47475 setTimeout(function(){
47476 var t = s.dom.offsetTop;
47477 var w = s.dom.clientWidth,
47478 h = s.dom.clientHeight;
47481 lw.setSize(ltWidth, h);
47483 mw.setLeftTop(ltWidth, t);
47484 mw.setSize(w-ltWidth, h);
47486 lb.setHeight(h-hdHeight);
47487 mb.setHeight(h-hdHeight);
47489 if(is2ndPass !== true && !gv.userResized && expandCol){
47490 // high speed resize without full column calculation
47492 var ci = cm.getIndexById(expandCol);
47494 ci = cm.findColumnIndex(expandCol);
47496 ci = Math.max(0, ci); // make sure it's got at least the first col.
47497 var expandId = cm.getColumnId(ci);
47498 var tw = cm.getTotalWidth(false);
47499 var currentWidth = cm.getColumnWidth(ci);
47500 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
47501 if(currentWidth != cw){
47502 cm.setColumnWidth(ci, cw, true);
47503 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47504 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47505 gv.updateSplitters();
47506 gv.layout(false, true);
47518 onWindowResize : function(){
47519 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
47525 appendFooter : function(parentEl){
47529 sortAscText : "Sort Ascending",
47530 sortDescText : "Sort Descending",
47531 lockText : "Lock Column",
47532 unlockText : "Unlock Column",
47533 columnsText : "Columns"
47537 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
47538 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
47539 this.proxy.el.addClass('x-grid3-col-dd');
47542 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
47543 handleMouseDown : function(e){
47547 callHandleMouseDown : function(e){
47548 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
47553 * Ext JS Library 1.1.1
47554 * Copyright(c) 2006-2007, Ext JS, LLC.
47556 * Originally Released Under LGPL - original licence link has changed is not relivant.
47559 * <script type="text/javascript">
47563 // This is a support class used internally by the Grid components
47564 Roo.grid.SplitDragZone = function(grid, hd, hd2){
47566 this.view = grid.getView();
47567 this.proxy = this.view.resizeProxy;
47568 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
47569 "gridSplitters" + this.grid.getGridEl().id, {
47570 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
47572 this.setHandleElId(Roo.id(hd));
47573 this.setOuterHandleElId(Roo.id(hd2));
47574 this.scroll = false;
47576 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
47577 fly: Roo.Element.fly,
47579 b4StartDrag : function(x, y){
47580 this.view.headersDisabled = true;
47581 this.proxy.setHeight(this.view.mainWrap.getHeight());
47582 var w = this.cm.getColumnWidth(this.cellIndex);
47583 var minw = Math.max(w-this.grid.minColumnWidth, 0);
47584 this.resetConstraints();
47585 this.setXConstraint(minw, 1000);
47586 this.setYConstraint(0, 0);
47587 this.minX = x - minw;
47588 this.maxX = x + 1000;
47590 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
47594 handleMouseDown : function(e){
47595 ev = Roo.EventObject.setEvent(e);
47596 var t = this.fly(ev.getTarget());
47597 if(t.hasClass("x-grid-split")){
47598 this.cellIndex = this.view.getCellIndex(t.dom);
47599 this.split = t.dom;
47600 this.cm = this.grid.colModel;
47601 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
47602 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
47607 endDrag : function(e){
47608 this.view.headersDisabled = false;
47609 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
47610 var diff = endX - this.startPos;
47611 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
47614 autoOffset : function(){
47615 this.setDelta(0,0);
47619 * Ext JS Library 1.1.1
47620 * Copyright(c) 2006-2007, Ext JS, LLC.
47622 * Originally Released Under LGPL - original licence link has changed is not relivant.
47625 * <script type="text/javascript">
47629 // This is a support class used internally by the Grid components
47630 Roo.grid.GridDragZone = function(grid, config){
47631 this.view = grid.getView();
47632 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
47633 if(this.view.lockedBody){
47634 this.setHandleElId(Roo.id(this.view.mainBody.dom));
47635 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
47637 this.scroll = false;
47639 this.ddel = document.createElement('div');
47640 this.ddel.className = 'x-grid-dd-wrap';
47643 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
47644 ddGroup : "GridDD",
47646 getDragData : function(e){
47647 var t = Roo.lib.Event.getTarget(e);
47648 var rowIndex = this.view.findRowIndex(t);
47649 if(rowIndex !== false){
47650 var sm = this.grid.selModel;
47651 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
47652 // sm.mouseDown(e, t);
47654 if (e.hasModifier()){
47655 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
47657 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
47662 onInitDrag : function(e){
47663 var data = this.dragData;
47664 this.ddel.innerHTML = this.grid.getDragDropText();
47665 this.proxy.update(this.ddel);
47666 // fire start drag?
47669 afterRepair : function(){
47670 this.dragging = false;
47673 getRepairXY : function(e, data){
47677 onEndDrag : function(data, e){
47681 onValidDrop : function(dd, e, id){
47686 beforeInvalidDrop : function(e, id){
47691 * Ext JS Library 1.1.1
47692 * Copyright(c) 2006-2007, Ext JS, LLC.
47694 * Originally Released Under LGPL - original licence link has changed is not relivant.
47697 * <script type="text/javascript">
47702 * @class Roo.grid.ColumnModel
47703 * @extends Roo.util.Observable
47704 * This is the default implementation of a ColumnModel used by the Grid. It defines
47705 * the columns in the grid.
47708 var colModel = new Roo.grid.ColumnModel([
47709 {header: "Ticker", width: 60, sortable: true, locked: true},
47710 {header: "Company Name", width: 150, sortable: true},
47711 {header: "Market Cap.", width: 100, sortable: true},
47712 {header: "$ Sales", width: 100, sortable: true, renderer: money},
47713 {header: "Employees", width: 100, sortable: true, resizable: false}
47718 * The config options listed for this class are options which may appear in each
47719 * individual column definition.
47720 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
47722 * @param {Object} config An Array of column config objects. See this class's
47723 * config objects for details.
47725 Roo.grid.ColumnModel = function(config){
47727 * The config passed into the constructor
47729 this.config = config;
47732 // if no id, create one
47733 // if the column does not have a dataIndex mapping,
47734 // map it to the order it is in the config
47735 for(var i = 0, len = config.length; i < len; i++){
47737 if(typeof c.dataIndex == "undefined"){
47740 if(typeof c.renderer == "string"){
47741 c.renderer = Roo.util.Format[c.renderer];
47743 if(typeof c.id == "undefined"){
47746 if(c.editor && c.editor.xtype){
47747 c.editor = Roo.factory(c.editor, Roo.grid);
47749 if(c.editor && c.editor.isFormField){
47750 c.editor = new Roo.grid.GridEditor(c.editor);
47752 this.lookup[c.id] = c;
47756 * The width of columns which have no width specified (defaults to 100)
47759 this.defaultWidth = 100;
47762 * Default sortable of columns which have no sortable specified (defaults to false)
47765 this.defaultSortable = false;
47769 * @event widthchange
47770 * Fires when the width of a column changes.
47771 * @param {ColumnModel} this
47772 * @param {Number} columnIndex The column index
47773 * @param {Number} newWidth The new width
47775 "widthchange": true,
47777 * @event headerchange
47778 * Fires when the text of a header changes.
47779 * @param {ColumnModel} this
47780 * @param {Number} columnIndex The column index
47781 * @param {Number} newText The new header text
47783 "headerchange": true,
47785 * @event hiddenchange
47786 * Fires when a column is hidden or "unhidden".
47787 * @param {ColumnModel} this
47788 * @param {Number} columnIndex The column index
47789 * @param {Boolean} hidden true if hidden, false otherwise
47791 "hiddenchange": true,
47793 * @event columnmoved
47794 * Fires when a column is moved.
47795 * @param {ColumnModel} this
47796 * @param {Number} oldIndex
47797 * @param {Number} newIndex
47799 "columnmoved" : true,
47801 * @event columlockchange
47802 * Fires when a column's locked state is changed
47803 * @param {ColumnModel} this
47804 * @param {Number} colIndex
47805 * @param {Boolean} locked true if locked
47807 "columnlockchange" : true
47809 Roo.grid.ColumnModel.superclass.constructor.call(this);
47811 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
47813 * @cfg {String} header The header text to display in the Grid view.
47816 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
47817 * {@link Roo.data.Record} definition from which to draw the column's value. If not
47818 * specified, the column's index is used as an index into the Record's data Array.
47821 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
47822 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
47825 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
47826 * Defaults to the value of the {@link #defaultSortable} property.
47827 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
47830 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
47833 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
47836 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
47839 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
47842 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
47843 * given the cell's data value. See {@link #setRenderer}. If not specified, the
47844 * default renderer uses the raw data value.
47847 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
47850 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
47854 * Returns the id of the column at the specified index.
47855 * @param {Number} index The column index
47856 * @return {String} the id
47858 getColumnId : function(index){
47859 return this.config[index].id;
47863 * Returns the column for a specified id.
47864 * @param {String} id The column id
47865 * @return {Object} the column
47867 getColumnById : function(id){
47868 return this.lookup[id];
47872 * Returns the index for a specified column id.
47873 * @param {String} id The column id
47874 * @return {Number} the index, or -1 if not found
47876 getIndexById : function(id){
47877 for(var i = 0, len = this.config.length; i < len; i++){
47878 if(this.config[i].id == id){
47885 * Returns the index for a specified column dataIndex.
47886 * @param {String} dataIndex The column dataIndex
47887 * @return {Number} the index, or -1 if not found
47890 findColumnIndex : function(dataIndex){
47891 for(var i = 0, len = this.config.length; i < len; i++){
47892 if(this.config[i].dataIndex == dataIndex){
47900 moveColumn : function(oldIndex, newIndex){
47901 var c = this.config[oldIndex];
47902 this.config.splice(oldIndex, 1);
47903 this.config.splice(newIndex, 0, c);
47904 this.dataMap = null;
47905 this.fireEvent("columnmoved", this, oldIndex, newIndex);
47908 isLocked : function(colIndex){
47909 return this.config[colIndex].locked === true;
47912 setLocked : function(colIndex, value, suppressEvent){
47913 if(this.isLocked(colIndex) == value){
47916 this.config[colIndex].locked = value;
47917 if(!suppressEvent){
47918 this.fireEvent("columnlockchange", this, colIndex, value);
47922 getTotalLockedWidth : function(){
47923 var totalWidth = 0;
47924 for(var i = 0; i < this.config.length; i++){
47925 if(this.isLocked(i) && !this.isHidden(i)){
47926 this.totalWidth += this.getColumnWidth(i);
47932 getLockedCount : function(){
47933 for(var i = 0, len = this.config.length; i < len; i++){
47934 if(!this.isLocked(i)){
47941 * Returns the number of columns.
47944 getColumnCount : function(visibleOnly){
47945 if(visibleOnly === true){
47947 for(var i = 0, len = this.config.length; i < len; i++){
47948 if(!this.isHidden(i)){
47954 return this.config.length;
47958 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
47959 * @param {Function} fn
47960 * @param {Object} scope (optional)
47961 * @return {Array} result
47963 getColumnsBy : function(fn, scope){
47965 for(var i = 0, len = this.config.length; i < len; i++){
47966 var c = this.config[i];
47967 if(fn.call(scope||this, c, i) === true){
47975 * Returns true if the specified column is sortable.
47976 * @param {Number} col The column index
47977 * @return {Boolean}
47979 isSortable : function(col){
47980 if(typeof this.config[col].sortable == "undefined"){
47981 return this.defaultSortable;
47983 return this.config[col].sortable;
47987 * Returns the rendering (formatting) function defined for the column.
47988 * @param {Number} col The column index.
47989 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
47991 getRenderer : function(col){
47992 if(!this.config[col].renderer){
47993 return Roo.grid.ColumnModel.defaultRenderer;
47995 return this.config[col].renderer;
47999 * Sets the rendering (formatting) function for a column.
48000 * @param {Number} col The column index
48001 * @param {Function} fn The function to use to process the cell's raw data
48002 * to return HTML markup for the grid view. The render function is called with
48003 * the following parameters:<ul>
48004 * <li>Data value.</li>
48005 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
48006 * <li>css A CSS style string to apply to the table cell.</li>
48007 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
48008 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
48009 * <li>Row index</li>
48010 * <li>Column index</li>
48011 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
48013 setRenderer : function(col, fn){
48014 this.config[col].renderer = fn;
48018 * Returns the width for the specified column.
48019 * @param {Number} col The column index
48022 getColumnWidth : function(col){
48023 return this.config[col].width || this.defaultWidth;
48027 * Sets the width for a column.
48028 * @param {Number} col The column index
48029 * @param {Number} width The new width
48031 setColumnWidth : function(col, width, suppressEvent){
48032 this.config[col].width = width;
48033 this.totalWidth = null;
48034 if(!suppressEvent){
48035 this.fireEvent("widthchange", this, col, width);
48040 * Returns the total width of all columns.
48041 * @param {Boolean} includeHidden True to include hidden column widths
48044 getTotalWidth : function(includeHidden){
48045 if(!this.totalWidth){
48046 this.totalWidth = 0;
48047 for(var i = 0, len = this.config.length; i < len; i++){
48048 if(includeHidden || !this.isHidden(i)){
48049 this.totalWidth += this.getColumnWidth(i);
48053 return this.totalWidth;
48057 * Returns the header for the specified column.
48058 * @param {Number} col The column index
48061 getColumnHeader : function(col){
48062 return this.config[col].header;
48066 * Sets the header for a column.
48067 * @param {Number} col The column index
48068 * @param {String} header The new header
48070 setColumnHeader : function(col, header){
48071 this.config[col].header = header;
48072 this.fireEvent("headerchange", this, col, header);
48076 * Returns the tooltip for the specified column.
48077 * @param {Number} col The column index
48080 getColumnTooltip : function(col){
48081 return this.config[col].tooltip;
48084 * Sets the tooltip for a column.
48085 * @param {Number} col The column index
48086 * @param {String} tooltip The new tooltip
48088 setColumnTooltip : function(col, tooltip){
48089 this.config[col].tooltip = tooltip;
48093 * Returns the dataIndex for the specified column.
48094 * @param {Number} col The column index
48097 getDataIndex : function(col){
48098 return this.config[col].dataIndex;
48102 * Sets the dataIndex for a column.
48103 * @param {Number} col The column index
48104 * @param {Number} dataIndex The new dataIndex
48106 setDataIndex : function(col, dataIndex){
48107 this.config[col].dataIndex = dataIndex;
48113 * Returns true if the cell is editable.
48114 * @param {Number} colIndex The column index
48115 * @param {Number} rowIndex The row index
48116 * @return {Boolean}
48118 isCellEditable : function(colIndex, rowIndex){
48119 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
48123 * Returns the editor defined for the cell/column.
48124 * return false or null to disable editing.
48125 * @param {Number} colIndex The column index
48126 * @param {Number} rowIndex The row index
48129 getCellEditor : function(colIndex, rowIndex){
48130 return this.config[colIndex].editor;
48134 * Sets if a column is editable.
48135 * @param {Number} col The column index
48136 * @param {Boolean} editable True if the column is editable
48138 setEditable : function(col, editable){
48139 this.config[col].editable = editable;
48144 * Returns true if the column is hidden.
48145 * @param {Number} colIndex The column index
48146 * @return {Boolean}
48148 isHidden : function(colIndex){
48149 return this.config[colIndex].hidden;
48154 * Returns true if the column width cannot be changed
48156 isFixed : function(colIndex){
48157 return this.config[colIndex].fixed;
48161 * Returns true if the column can be resized
48162 * @return {Boolean}
48164 isResizable : function(colIndex){
48165 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
48168 * Sets if a column is hidden.
48169 * @param {Number} colIndex The column index
48170 * @param {Boolean} hidden True if the column is hidden
48172 setHidden : function(colIndex, hidden){
48173 this.config[colIndex].hidden = hidden;
48174 this.totalWidth = null;
48175 this.fireEvent("hiddenchange", this, colIndex, hidden);
48179 * Sets the editor for a column.
48180 * @param {Number} col The column index
48181 * @param {Object} editor The editor object
48183 setEditor : function(col, editor){
48184 this.config[col].editor = editor;
48188 Roo.grid.ColumnModel.defaultRenderer = function(value){
48189 if(typeof value == "string" && value.length < 1){
48195 // Alias for backwards compatibility
48196 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
48199 * Ext JS Library 1.1.1
48200 * Copyright(c) 2006-2007, Ext JS, LLC.
48202 * Originally Released Under LGPL - original licence link has changed is not relivant.
48205 * <script type="text/javascript">
48209 * @class Roo.grid.AbstractSelectionModel
48210 * @extends Roo.util.Observable
48211 * Abstract base class for grid SelectionModels. It provides the interface that should be
48212 * implemented by descendant classes. This class should not be directly instantiated.
48215 Roo.grid.AbstractSelectionModel = function(){
48216 this.locked = false;
48217 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
48220 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
48221 /** @ignore Called by the grid automatically. Do not call directly. */
48222 init : function(grid){
48228 * Locks the selections.
48231 this.locked = true;
48235 * Unlocks the selections.
48237 unlock : function(){
48238 this.locked = false;
48242 * Returns true if the selections are locked.
48243 * @return {Boolean}
48245 isLocked : function(){
48246 return this.locked;
48250 * Ext JS Library 1.1.1
48251 * Copyright(c) 2006-2007, Ext JS, LLC.
48253 * Originally Released Under LGPL - original licence link has changed is not relivant.
48256 * <script type="text/javascript">
48259 * @extends Roo.grid.AbstractSelectionModel
48260 * @class Roo.grid.RowSelectionModel
48261 * The default SelectionModel used by {@link Roo.grid.Grid}.
48262 * It supports multiple selections and keyboard selection/navigation.
48264 * @param {Object} config
48266 Roo.grid.RowSelectionModel = function(config){
48267 Roo.apply(this, config);
48268 this.selections = new Roo.util.MixedCollection(false, function(o){
48273 this.lastActive = false;
48277 * @event selectionchange
48278 * Fires when the selection changes
48279 * @param {SelectionModel} this
48281 "selectionchange" : true,
48283 * @event afterselectionchange
48284 * Fires after the selection changes (eg. by key press or clicking)
48285 * @param {SelectionModel} this
48287 "afterselectionchange" : true,
48289 * @event beforerowselect
48290 * Fires when a row is selected being selected, return false to cancel.
48291 * @param {SelectionModel} this
48292 * @param {Number} rowIndex The selected index
48293 * @param {Boolean} keepExisting False if other selections will be cleared
48295 "beforerowselect" : true,
48298 * Fires when a row is selected.
48299 * @param {SelectionModel} this
48300 * @param {Number} rowIndex The selected index
48301 * @param {Roo.data.Record} r The record
48303 "rowselect" : true,
48305 * @event rowdeselect
48306 * Fires when a row is deselected.
48307 * @param {SelectionModel} this
48308 * @param {Number} rowIndex The selected index
48310 "rowdeselect" : true
48312 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
48313 this.locked = false;
48316 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
48318 * @cfg {Boolean} singleSelect
48319 * True to allow selection of only one row at a time (defaults to false)
48321 singleSelect : false,
48324 initEvents : function(){
48326 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
48327 this.grid.on("mousedown", this.handleMouseDown, this);
48328 }else{ // allow click to work like normal
48329 this.grid.on("rowclick", this.handleDragableRowClick, this);
48332 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
48333 "up" : function(e){
48335 this.selectPrevious(e.shiftKey);
48336 }else if(this.last !== false && this.lastActive !== false){
48337 var last = this.last;
48338 this.selectRange(this.last, this.lastActive-1);
48339 this.grid.getView().focusRow(this.lastActive);
48340 if(last !== false){
48344 this.selectFirstRow();
48346 this.fireEvent("afterselectionchange", this);
48348 "down" : function(e){
48350 this.selectNext(e.shiftKey);
48351 }else if(this.last !== false && this.lastActive !== false){
48352 var last = this.last;
48353 this.selectRange(this.last, this.lastActive+1);
48354 this.grid.getView().focusRow(this.lastActive);
48355 if(last !== false){
48359 this.selectFirstRow();
48361 this.fireEvent("afterselectionchange", this);
48366 var view = this.grid.view;
48367 view.on("refresh", this.onRefresh, this);
48368 view.on("rowupdated", this.onRowUpdated, this);
48369 view.on("rowremoved", this.onRemove, this);
48373 onRefresh : function(){
48374 var ds = this.grid.dataSource, i, v = this.grid.view;
48375 var s = this.selections;
48376 s.each(function(r){
48377 if((i = ds.indexOfId(r.id)) != -1){
48386 onRemove : function(v, index, r){
48387 this.selections.remove(r);
48391 onRowUpdated : function(v, index, r){
48392 if(this.isSelected(r)){
48393 v.onRowSelect(index);
48399 * @param {Array} records The records to select
48400 * @param {Boolean} keepExisting (optional) True to keep existing selections
48402 selectRecords : function(records, keepExisting){
48404 this.clearSelections();
48406 var ds = this.grid.dataSource;
48407 for(var i = 0, len = records.length; i < len; i++){
48408 this.selectRow(ds.indexOf(records[i]), true);
48413 * Gets the number of selected rows.
48416 getCount : function(){
48417 return this.selections.length;
48421 * Selects the first row in the grid.
48423 selectFirstRow : function(){
48428 * Select the last row.
48429 * @param {Boolean} keepExisting (optional) True to keep existing selections
48431 selectLastRow : function(keepExisting){
48432 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
48436 * Selects the row immediately following the last selected row.
48437 * @param {Boolean} keepExisting (optional) True to keep existing selections
48439 selectNext : function(keepExisting){
48440 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
48441 this.selectRow(this.last+1, keepExisting);
48442 this.grid.getView().focusRow(this.last);
48447 * Selects the row that precedes the last selected row.
48448 * @param {Boolean} keepExisting (optional) True to keep existing selections
48450 selectPrevious : function(keepExisting){
48452 this.selectRow(this.last-1, keepExisting);
48453 this.grid.getView().focusRow(this.last);
48458 * Returns the selected records
48459 * @return {Array} Array of selected records
48461 getSelections : function(){
48462 return [].concat(this.selections.items);
48466 * Returns the first selected record.
48469 getSelected : function(){
48470 return this.selections.itemAt(0);
48475 * Clears all selections.
48477 clearSelections : function(fast){
48478 if(this.locked) return;
48480 var ds = this.grid.dataSource;
48481 var s = this.selections;
48482 s.each(function(r){
48483 this.deselectRow(ds.indexOfId(r.id));
48487 this.selections.clear();
48494 * Selects all rows.
48496 selectAll : function(){
48497 if(this.locked) return;
48498 this.selections.clear();
48499 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
48500 this.selectRow(i, true);
48505 * Returns True if there is a selection.
48506 * @return {Boolean}
48508 hasSelection : function(){
48509 return this.selections.length > 0;
48513 * Returns True if the specified row is selected.
48514 * @param {Number/Record} record The record or index of the record to check
48515 * @return {Boolean}
48517 isSelected : function(index){
48518 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
48519 return (r && this.selections.key(r.id) ? true : false);
48523 * Returns True if the specified record id is selected.
48524 * @param {String} id The id of record to check
48525 * @return {Boolean}
48527 isIdSelected : function(id){
48528 return (this.selections.key(id) ? true : false);
48532 handleMouseDown : function(e, t){
48533 var view = this.grid.getView(), rowIndex;
48534 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
48537 if(e.shiftKey && this.last !== false){
48538 var last = this.last;
48539 this.selectRange(last, rowIndex, e.ctrlKey);
48540 this.last = last; // reset the last
48541 view.focusRow(rowIndex);
48543 var isSelected = this.isSelected(rowIndex);
48544 if(e.button !== 0 && isSelected){
48545 view.focusRow(rowIndex);
48546 }else if(e.ctrlKey && isSelected){
48547 this.deselectRow(rowIndex);
48548 }else if(!isSelected){
48549 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
48550 view.focusRow(rowIndex);
48553 this.fireEvent("afterselectionchange", this);
48556 handleDragableRowClick : function(grid, rowIndex, e)
48558 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
48559 this.selectRow(rowIndex, false);
48560 grid.view.focusRow(rowIndex);
48561 this.fireEvent("afterselectionchange", this);
48566 * Selects multiple rows.
48567 * @param {Array} rows Array of the indexes of the row to select
48568 * @param {Boolean} keepExisting (optional) True to keep existing selections
48570 selectRows : function(rows, keepExisting){
48572 this.clearSelections();
48574 for(var i = 0, len = rows.length; i < len; i++){
48575 this.selectRow(rows[i], true);
48580 * Selects a range of rows. All rows in between startRow and endRow are also selected.
48581 * @param {Number} startRow The index of the first row in the range
48582 * @param {Number} endRow The index of the last row in the range
48583 * @param {Boolean} keepExisting (optional) True to retain existing selections
48585 selectRange : function(startRow, endRow, keepExisting){
48586 if(this.locked) return;
48588 this.clearSelections();
48590 if(startRow <= endRow){
48591 for(var i = startRow; i <= endRow; i++){
48592 this.selectRow(i, true);
48595 for(var i = startRow; i >= endRow; i--){
48596 this.selectRow(i, true);
48602 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
48603 * @param {Number} startRow The index of the first row in the range
48604 * @param {Number} endRow The index of the last row in the range
48606 deselectRange : function(startRow, endRow, preventViewNotify){
48607 if(this.locked) return;
48608 for(var i = startRow; i <= endRow; i++){
48609 this.deselectRow(i, preventViewNotify);
48615 * @param {Number} row The index of the row to select
48616 * @param {Boolean} keepExisting (optional) True to keep existing selections
48618 selectRow : function(index, keepExisting, preventViewNotify){
48619 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
48620 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
48621 if(!keepExisting || this.singleSelect){
48622 this.clearSelections();
48624 var r = this.grid.dataSource.getAt(index);
48625 this.selections.add(r);
48626 this.last = this.lastActive = index;
48627 if(!preventViewNotify){
48628 this.grid.getView().onRowSelect(index);
48630 this.fireEvent("rowselect", this, index, r);
48631 this.fireEvent("selectionchange", this);
48637 * @param {Number} row The index of the row to deselect
48639 deselectRow : function(index, preventViewNotify){
48640 if(this.locked) return;
48641 if(this.last == index){
48644 if(this.lastActive == index){
48645 this.lastActive = false;
48647 var r = this.grid.dataSource.getAt(index);
48648 this.selections.remove(r);
48649 if(!preventViewNotify){
48650 this.grid.getView().onRowDeselect(index);
48652 this.fireEvent("rowdeselect", this, index);
48653 this.fireEvent("selectionchange", this);
48657 restoreLast : function(){
48659 this.last = this._last;
48664 acceptsNav : function(row, col, cm){
48665 return !cm.isHidden(col) && cm.isCellEditable(col, row);
48669 onEditorKey : function(field, e){
48670 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
48675 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
48677 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
48679 }else if(k == e.ENTER && !e.ctrlKey){
48683 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
48685 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
48687 }else if(k == e.ESC){
48691 g.startEditing(newCell[0], newCell[1]);
48696 * Ext JS Library 1.1.1
48697 * Copyright(c) 2006-2007, Ext JS, LLC.
48699 * Originally Released Under LGPL - original licence link has changed is not relivant.
48702 * <script type="text/javascript">
48705 * @class Roo.grid.CellSelectionModel
48706 * @extends Roo.grid.AbstractSelectionModel
48707 * This class provides the basic implementation for cell selection in a grid.
48709 * @param {Object} config The object containing the configuration of this model.
48711 Roo.grid.CellSelectionModel = function(config){
48712 Roo.apply(this, config);
48714 this.selection = null;
48718 * @event beforerowselect
48719 * Fires before a cell is selected.
48720 * @param {SelectionModel} this
48721 * @param {Number} rowIndex The selected row index
48722 * @param {Number} colIndex The selected cell index
48724 "beforecellselect" : true,
48726 * @event cellselect
48727 * Fires when a cell is selected.
48728 * @param {SelectionModel} this
48729 * @param {Number} rowIndex The selected row index
48730 * @param {Number} colIndex The selected cell index
48732 "cellselect" : true,
48734 * @event selectionchange
48735 * Fires when the active selection changes.
48736 * @param {SelectionModel} this
48737 * @param {Object} selection null for no selection or an object (o) with two properties
48739 <li>o.record: the record object for the row the selection is in</li>
48740 <li>o.cell: An array of [rowIndex, columnIndex]</li>
48743 "selectionchange" : true
48745 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
48748 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
48751 initEvents : function(){
48752 this.grid.on("mousedown", this.handleMouseDown, this);
48753 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
48754 var view = this.grid.view;
48755 view.on("refresh", this.onViewChange, this);
48756 view.on("rowupdated", this.onRowUpdated, this);
48757 view.on("beforerowremoved", this.clearSelections, this);
48758 view.on("beforerowsinserted", this.clearSelections, this);
48759 if(this.grid.isEditor){
48760 this.grid.on("beforeedit", this.beforeEdit, this);
48765 beforeEdit : function(e){
48766 this.select(e.row, e.column, false, true, e.record);
48770 onRowUpdated : function(v, index, r){
48771 if(this.selection && this.selection.record == r){
48772 v.onCellSelect(index, this.selection.cell[1]);
48777 onViewChange : function(){
48778 this.clearSelections(true);
48782 * Returns the currently selected cell,.
48783 * @return {Array} The selected cell (row, column) or null if none selected.
48785 getSelectedCell : function(){
48786 return this.selection ? this.selection.cell : null;
48790 * Clears all selections.
48791 * @param {Boolean} true to prevent the gridview from being notified about the change.
48793 clearSelections : function(preventNotify){
48794 var s = this.selection;
48796 if(preventNotify !== true){
48797 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
48799 this.selection = null;
48800 this.fireEvent("selectionchange", this, null);
48805 * Returns true if there is a selection.
48806 * @return {Boolean}
48808 hasSelection : function(){
48809 return this.selection ? true : false;
48813 handleMouseDown : function(e, t){
48814 var v = this.grid.getView();
48815 if(this.isLocked()){
48818 var row = v.findRowIndex(t);
48819 var cell = v.findCellIndex(t);
48820 if(row !== false && cell !== false){
48821 this.select(row, cell);
48827 * @param {Number} rowIndex
48828 * @param {Number} collIndex
48830 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
48831 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
48832 this.clearSelections();
48833 r = r || this.grid.dataSource.getAt(rowIndex);
48836 cell : [rowIndex, colIndex]
48838 if(!preventViewNotify){
48839 var v = this.grid.getView();
48840 v.onCellSelect(rowIndex, colIndex);
48841 if(preventFocus !== true){
48842 v.focusCell(rowIndex, colIndex);
48845 this.fireEvent("cellselect", this, rowIndex, colIndex);
48846 this.fireEvent("selectionchange", this, this.selection);
48851 isSelectable : function(rowIndex, colIndex, cm){
48852 return !cm.isHidden(colIndex);
48856 handleKeyDown : function(e){
48857 if(!e.isNavKeyPress()){
48860 var g = this.grid, s = this.selection;
48863 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
48865 this.select(cell[0], cell[1]);
48870 var walk = function(row, col, step){
48871 return g.walkCells(row, col, step, sm.isSelectable, sm);
48873 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
48879 newCell = walk(r, c-1, -1);
48881 newCell = walk(r, c+1, 1);
48885 newCell = walk(r+1, c, 1);
48888 newCell = walk(r-1, c, -1);
48891 newCell = walk(r, c+1, 1);
48894 newCell = walk(r, c-1, -1);
48897 if(g.isEditor && !g.editing){
48898 g.startEditing(r, c);
48905 this.select(newCell[0], newCell[1]);
48910 acceptsNav : function(row, col, cm){
48911 return !cm.isHidden(col) && cm.isCellEditable(col, row);
48914 onEditorKey : function(field, e){
48915 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
48918 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
48920 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
48923 }else if(k == e.ENTER && !e.ctrlKey){
48926 }else if(k == e.ESC){
48930 g.startEditing(newCell[0], newCell[1]);
48935 * Ext JS Library 1.1.1
48936 * Copyright(c) 2006-2007, Ext JS, LLC.
48938 * Originally Released Under LGPL - original licence link has changed is not relivant.
48941 * <script type="text/javascript">
48945 * @class Roo.grid.EditorGrid
48946 * @extends Roo.grid.Grid
48947 * Class for creating and editable grid.
48948 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
48949 * The container MUST have some type of size defined for the grid to fill. The container will be
48950 * automatically set to position relative if it isn't already.
48951 * @param {Object} dataSource The data model to bind to
48952 * @param {Object} colModel The column model with info about this grid's columns
48954 Roo.grid.EditorGrid = function(container, config){
48955 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
48956 this.getGridEl().addClass("xedit-grid");
48958 if(!this.selModel){
48959 this.selModel = new Roo.grid.CellSelectionModel();
48962 this.activeEditor = null;
48966 * @event beforeedit
48967 * Fires before cell editing is triggered. The edit event object has the following properties <br />
48968 * <ul style="padding:5px;padding-left:16px;">
48969 * <li>grid - This grid</li>
48970 * <li>record - The record being edited</li>
48971 * <li>field - The field name being edited</li>
48972 * <li>value - The value for the field being edited.</li>
48973 * <li>row - The grid row index</li>
48974 * <li>column - The grid column index</li>
48975 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
48977 * @param {Object} e An edit event (see above for description)
48979 "beforeedit" : true,
48982 * Fires after a cell is edited. <br />
48983 * <ul style="padding:5px;padding-left:16px;">
48984 * <li>grid - This grid</li>
48985 * <li>record - The record being edited</li>
48986 * <li>field - The field name being edited</li>
48987 * <li>value - The value being set</li>
48988 * <li>originalValue - The original value for the field, before the edit.</li>
48989 * <li>row - The grid row index</li>
48990 * <li>column - The grid column index</li>
48992 * @param {Object} e An edit event (see above for description)
48994 "afteredit" : true,
48996 * @event validateedit
48997 * Fires after a cell is edited, but before the value is set in the record.
48998 * You can use this to modify the value being set in the field, Return false
48999 * to cancel the change. The edit event object has the following properties <br />
49000 * <ul style="padding:5px;padding-left:16px;">
49001 * <li>editor - This editor</li>
49002 * <li>grid - This grid</li>
49003 * <li>record - The record being edited</li>
49004 * <li>field - The field name being edited</li>
49005 * <li>value - The value being set</li>
49006 * <li>originalValue - The original value for the field, before the edit.</li>
49007 * <li>row - The grid row index</li>
49008 * <li>column - The grid column index</li>
49009 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
49011 * @param {Object} e An edit event (see above for description)
49013 "validateedit" : true
49015 this.on("bodyscroll", this.stopEditing, this);
49016 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
49019 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
49021 * @cfg {Number} clicksToEdit
49022 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
49029 trackMouseOver: false, // causes very odd FF errors
49031 onCellDblClick : function(g, row, col){
49032 this.startEditing(row, col);
49035 onEditComplete : function(ed, value, startValue){
49036 this.editing = false;
49037 this.activeEditor = null;
49038 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
49040 var field = this.colModel.getDataIndex(ed.col);
49045 originalValue: startValue,
49052 if(String(value) !== String(startValue)){
49054 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
49055 r.set(field, e.value);
49056 delete e.cancel; //?? why!!!
49057 this.fireEvent("afteredit", e);
49060 this.fireEvent("afteredit", e); // always fir it!
49062 this.view.focusCell(ed.row, ed.col);
49066 * Starts editing the specified for the specified row/column
49067 * @param {Number} rowIndex
49068 * @param {Number} colIndex
49070 startEditing : function(row, col){
49071 this.stopEditing();
49072 if(this.colModel.isCellEditable(col, row)){
49073 this.view.ensureVisible(row, col, true);
49074 var r = this.dataSource.getAt(row);
49075 var field = this.colModel.getDataIndex(col);
49080 value: r.data[field],
49085 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
49086 this.editing = true;
49087 var ed = this.colModel.getCellEditor(col, row);
49093 ed.render(ed.parentEl || document.body);
49096 (function(){ // complex but required for focus issues in safari, ie and opera
49100 ed.on("complete", this.onEditComplete, this, {single: true});
49101 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
49102 this.activeEditor = ed;
49103 var v = r.data[field];
49104 ed.startEdit(this.view.getCell(row, col), v);
49105 }).defer(50, this);
49111 * Stops any active editing
49113 stopEditing : function(){
49114 if(this.activeEditor){
49115 this.activeEditor.completeEdit();
49117 this.activeEditor = null;
49121 * Ext JS Library 1.1.1
49122 * Copyright(c) 2006-2007, Ext JS, LLC.
49124 * Originally Released Under LGPL - original licence link has changed is not relivant.
49127 * <script type="text/javascript">
49130 // private - not really -- you end up using it !
49131 // This is a support class used internally by the Grid components
49134 * @class Roo.grid.GridEditor
49135 * @extends Roo.Editor
49136 * Class for creating and editable grid elements.
49137 * @param {Object} config any settings (must include field)
49139 Roo.grid.GridEditor = function(field, config){
49140 if (!config && field.field) {
49142 field = Roo.factory(config.field, Roo.form);
49144 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
49145 field.monitorTab = false;
49148 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
49151 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
49154 alignment: "tl-tl",
49157 cls: "x-small-editor x-grid-editor",
49162 * Ext JS Library 1.1.1
49163 * Copyright(c) 2006-2007, Ext JS, LLC.
49165 * Originally Released Under LGPL - original licence link has changed is not relivant.
49168 * <script type="text/javascript">
49173 Roo.grid.PropertyRecord = Roo.data.Record.create([
49174 {name:'name',type:'string'}, 'value'
49178 Roo.grid.PropertyStore = function(grid, source){
49180 this.store = new Roo.data.Store({
49181 recordType : Roo.grid.PropertyRecord
49183 this.store.on('update', this.onUpdate, this);
49185 this.setSource(source);
49187 Roo.grid.PropertyStore.superclass.constructor.call(this);
49192 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
49193 setSource : function(o){
49195 this.store.removeAll();
49198 if(this.isEditableValue(o[k])){
49199 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
49202 this.store.loadRecords({records: data}, {}, true);
49205 onUpdate : function(ds, record, type){
49206 if(type == Roo.data.Record.EDIT){
49207 var v = record.data['value'];
49208 var oldValue = record.modified['value'];
49209 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
49210 this.source[record.id] = v;
49212 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
49219 getProperty : function(row){
49220 return this.store.getAt(row);
49223 isEditableValue: function(val){
49224 if(val && val instanceof Date){
49226 }else if(typeof val == 'object' || typeof val == 'function'){
49232 setValue : function(prop, value){
49233 this.source[prop] = value;
49234 this.store.getById(prop).set('value', value);
49237 getSource : function(){
49238 return this.source;
49242 Roo.grid.PropertyColumnModel = function(grid, store){
49245 g.PropertyColumnModel.superclass.constructor.call(this, [
49246 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
49247 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
49249 this.store = store;
49250 this.bselect = Roo.DomHelper.append(document.body, {
49251 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
49252 {tag: 'option', value: 'true', html: 'true'},
49253 {tag: 'option', value: 'false', html: 'false'}
49256 Roo.id(this.bselect);
49259 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
49260 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
49261 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
49262 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
49263 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
49265 this.renderCellDelegate = this.renderCell.createDelegate(this);
49266 this.renderPropDelegate = this.renderProp.createDelegate(this);
49269 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
49273 valueText : 'Value',
49275 dateFormat : 'm/j/Y',
49278 renderDate : function(dateVal){
49279 return dateVal.dateFormat(this.dateFormat);
49282 renderBool : function(bVal){
49283 return bVal ? 'true' : 'false';
49286 isCellEditable : function(colIndex, rowIndex){
49287 return colIndex == 1;
49290 getRenderer : function(col){
49292 this.renderCellDelegate : this.renderPropDelegate;
49295 renderProp : function(v){
49296 return this.getPropertyName(v);
49299 renderCell : function(val){
49301 if(val instanceof Date){
49302 rv = this.renderDate(val);
49303 }else if(typeof val == 'boolean'){
49304 rv = this.renderBool(val);
49306 return Roo.util.Format.htmlEncode(rv);
49309 getPropertyName : function(name){
49310 var pn = this.grid.propertyNames;
49311 return pn && pn[name] ? pn[name] : name;
49314 getCellEditor : function(colIndex, rowIndex){
49315 var p = this.store.getProperty(rowIndex);
49316 var n = p.data['name'], val = p.data['value'];
49318 if(typeof(this.grid.customEditors[n]) == 'string'){
49319 return this.editors[this.grid.customEditors[n]];
49321 if(typeof(this.grid.customEditors[n]) != 'undefined'){
49322 return this.grid.customEditors[n];
49324 if(val instanceof Date){
49325 return this.editors['date'];
49326 }else if(typeof val == 'number'){
49327 return this.editors['number'];
49328 }else if(typeof val == 'boolean'){
49329 return this.editors['boolean'];
49331 return this.editors['string'];
49337 * @class Roo.grid.PropertyGrid
49338 * @extends Roo.grid.EditorGrid
49339 * This class represents the interface of a component based property grid control.
49340 * <br><br>Usage:<pre><code>
49341 var grid = new Roo.grid.PropertyGrid("my-container-id", {
49349 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49350 * The container MUST have some type of size defined for the grid to fill. The container will be
49351 * automatically set to position relative if it isn't already.
49352 * @param {Object} config A config object that sets properties on this grid.
49354 Roo.grid.PropertyGrid = function(container, config){
49355 config = config || {};
49356 var store = new Roo.grid.PropertyStore(this);
49357 this.store = store;
49358 var cm = new Roo.grid.PropertyColumnModel(this, store);
49359 store.store.sort('name', 'ASC');
49360 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
49363 enableColLock:false,
49364 enableColumnMove:false,
49366 trackMouseOver: false,
49369 this.getGridEl().addClass('x-props-grid');
49370 this.lastEditRow = null;
49371 this.on('columnresize', this.onColumnResize, this);
49374 * @event beforepropertychange
49375 * Fires before a property changes (return false to stop?)
49376 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
49377 * @param {String} id Record Id
49378 * @param {String} newval New Value
49379 * @param {String} oldval Old Value
49381 "beforepropertychange": true,
49383 * @event propertychange
49384 * Fires after a property changes
49385 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
49386 * @param {String} id Record Id
49387 * @param {String} newval New Value
49388 * @param {String} oldval Old Value
49390 "propertychange": true
49392 this.customEditors = this.customEditors || {};
49394 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
49397 * @cfg {Object} customEditors map of colnames=> custom editors.
49398 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
49399 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
49400 * false disables editing of the field.
49404 * @cfg {Object} propertyNames map of property Names to their displayed value
49407 render : function(){
49408 Roo.grid.PropertyGrid.superclass.render.call(this);
49409 this.autoSize.defer(100, this);
49412 autoSize : function(){
49413 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
49415 this.view.fitColumns();
49419 onColumnResize : function(){
49420 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
49424 * Sets the data for the Grid
49425 * accepts a Key => Value object of all the elements avaiable.
49426 * @param {Object} data to appear in grid.
49428 setSource : function(source){
49429 this.store.setSource(source);
49433 * Gets all the data from the grid.
49434 * @return {Object} data data stored in grid
49436 getSource : function(){
49437 return this.store.getSource();
49441 * Ext JS Library 1.1.1
49442 * Copyright(c) 2006-2007, Ext JS, LLC.
49444 * Originally Released Under LGPL - original licence link has changed is not relivant.
49447 * <script type="text/javascript">
49451 * @class Roo.LoadMask
49452 * A simple utility class for generically masking elements while loading data. If the element being masked has
49453 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
49454 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
49455 * element's UpdateManager load indicator and will be destroyed after the initial load.
49457 * Create a new LoadMask
49458 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
49459 * @param {Object} config The config object
49461 Roo.LoadMask = function(el, config){
49462 this.el = Roo.get(el);
49463 Roo.apply(this, config);
49465 this.store.on('beforeload', this.onBeforeLoad, this);
49466 this.store.on('load', this.onLoad, this);
49467 this.store.on('loadexception', this.onLoad, this);
49468 this.removeMask = false;
49470 var um = this.el.getUpdateManager();
49471 um.showLoadIndicator = false; // disable the default indicator
49472 um.on('beforeupdate', this.onBeforeLoad, this);
49473 um.on('update', this.onLoad, this);
49474 um.on('failure', this.onLoad, this);
49475 this.removeMask = true;
49479 Roo.LoadMask.prototype = {
49481 * @cfg {Boolean} removeMask
49482 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
49483 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
49486 * @cfg {String} msg
49487 * The text to display in a centered loading message box (defaults to 'Loading...')
49489 msg : 'Loading...',
49491 * @cfg {String} msgCls
49492 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
49494 msgCls : 'x-mask-loading',
49497 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
49503 * Disables the mask to prevent it from being displayed
49505 disable : function(){
49506 this.disabled = true;
49510 * Enables the mask so that it can be displayed
49512 enable : function(){
49513 this.disabled = false;
49517 onLoad : function(){
49518 this.el.unmask(this.removeMask);
49522 onBeforeLoad : function(){
49523 if(!this.disabled){
49524 this.el.mask(this.msg, this.msgCls);
49529 destroy : function(){
49531 this.store.un('beforeload', this.onBeforeLoad, this);
49532 this.store.un('load', this.onLoad, this);
49533 this.store.un('loadexception', this.onLoad, this);
49535 var um = this.el.getUpdateManager();
49536 um.un('beforeupdate', this.onBeforeLoad, this);
49537 um.un('update', this.onLoad, this);
49538 um.un('failure', this.onLoad, this);
49543 * Ext JS Library 1.1.1
49544 * Copyright(c) 2006-2007, Ext JS, LLC.
49546 * Originally Released Under LGPL - original licence link has changed is not relivant.
49549 * <script type="text/javascript">
49551 Roo.XTemplate = function(){
49552 Roo.XTemplate.superclass.constructor.apply(this, arguments);
49555 s = ['<tpl>', s, '</tpl>'].join('');
49557 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
49559 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
49560 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
49561 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
49565 while(m = s.match(re)){
49566 var m2 = m[0].match(nameRe);
49567 var m3 = m[0].match(ifRe);
49568 var m4 = m[0].match(execRe);
49569 var exp = null, fn = null, exec = null;
49570 var name = m2 && m2[1] ? m2[1] : '';
49572 exp = m3 && m3[1] ? m3[1] : null;
49574 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
49578 exp = m4 && m4[1] ? m4[1] : null;
49580 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
49585 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
49586 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
49587 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
49597 s = s.replace(m[0], '{xtpl'+ id + '}');
49600 for(var i = tpls.length-1; i >= 0; --i){
49601 this.compileTpl(tpls[i]);
49603 this.master = tpls[tpls.length-1];
49606 Roo.extend(Roo.XTemplate, Roo.Template, {
49608 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
49610 applySubTemplate : function(id, values, parent){
49611 var t = this.tpls[id];
49612 if(t.test && !t.test.call(this, values, parent)){
49615 if(t.exec && t.exec.call(this, values, parent)){
49618 var vs = t.target ? t.target.call(this, values, parent) : values;
49619 parent = t.target ? values : parent;
49620 if(t.target && vs instanceof Array){
49622 for(var i = 0, len = vs.length; i < len; i++){
49623 buf[buf.length] = t.compiled.call(this, vs[i], parent);
49625 return buf.join('');
49627 return t.compiled.call(this, vs, parent);
49630 compileTpl : function(tpl){
49631 var fm = Roo.util.Format;
49632 var useF = this.disableFormats !== true;
49633 var sep = Roo.isGecko ? "+" : ",";
49634 var fn = function(m, name, format, args){
49635 if(name.substr(0, 4) == 'xtpl'){
49636 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
49639 if(name.indexOf('.') != -1){
49642 v = "values['" + name + "']";
49644 if(format && useF){
49645 args = args ? ',' + args : "";
49646 if(format.substr(0, 5) != "this."){
49647 format = "fm." + format + '(';
49649 format = 'this.call("'+ format.substr(5) + '", ';
49653 args= ''; format = "("+v+" === undefined ? '' : ";
49655 return "'"+ sep + format + v + args + ")"+sep+"'";
49658 // branched to use + in gecko and [].join() in others
49660 body = "tpl.compiled = function(values, parent){ return '" +
49661 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
49664 body = ["tpl.compiled = function(values, parent){ return ['"];
49665 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
49666 body.push("'].join('');};");
49667 body = body.join('');
49669 /** eval:var:zzzzzzz */
49674 applyTemplate : function(values){
49675 return this.master.compiled.call(this, values, {});
49679 apply : function(){
49680 return this.applyTemplate.apply(this, arguments);
49683 compile : function(){return this;}
49686 Roo.XTemplate.from = function(el){
49687 el = Roo.getDom(el);
49688 return new Roo.XTemplate(el.value || el.innerHTML);
49690 * Original code for Roojs - LGPL
49691 * <script type="text/javascript">
49695 * @class Roo.XComponent
49696 * A delayed Element creator...
49698 * Mypart.xyx = new Roo.XComponent({
49700 parent : 'Mypart.xyz', // empty == document.element.!!
49704 disabled : function() {}
49706 tree : function() { // return an tree of xtype declared components
49710 xtype : 'NestedLayoutPanel',
49715 * @extends Roo.util.Observable
49717 * @param cfg {Object} configuration of component
49720 Roo.XComponent = function(cfg) {
49721 Roo.apply(this, cfg);
49725 * Fires when this the componnt is built
49726 * @param {Roo.XComponent} c the component
49730 * @event buildcomplete
49731 * Fires on the top level element when all elements have been built
49732 * @param {Roo.XComponent} c the top level component.
49734 'buildcomplete' : true,
49738 Roo.XComponent.register(this);
49739 this.modules = false;
49740 this.el = false; // where the layout goes..
49744 Roo.extend(Roo.XComponent, Roo.util.Observable, {
49747 * The created element (with Roo.factory())
49748 * @type {Roo.Layout}
49754 * for BC - use el in new code
49755 * @type {Roo.Layout}
49761 * for BC - use el in new code
49762 * @type {Roo.Layout}
49767 * @cfg {Function|boolean} disabled
49768 * If this module is disabled by some rule, return true from the funtion
49773 * @cfg {String} parent
49774 * Name of parent element which it get xtype added to..
49779 * @cfg {String} order
49780 * Used to set the order in which elements are created (usefull for multiple tabs)
49785 * @cfg {String} name
49786 * String to display while loading.
49790 * @cfg {Array} items
49791 * A single item array - the first element is the root of the tree..
49792 * It's done this way to stay compatible with the Xtype system...
49800 Roo.apply(Roo.XComponent, {
49803 * @property buildCompleted
49804 * True when the builder has completed building the interface.
49807 buildCompleted : false,
49810 * @property topModule
49811 * the upper most module - uses document.element as it's constructor.
49818 * @property modules
49819 * array of modules to be created by registration system.
49820 * @type Roo.XComponent
49827 * Register components to be built later.
49829 * This solves the following issues
49830 * - Building is not done on page load, but after an authentication process has occured.
49831 * - Interface elements are registered on page load
49832 * - Parent Interface elements may not be loaded before child, so this handles that..
49839 module : 'Pman.Tab.projectMgr',
49841 parent : 'Pman.layout',
49842 disabled : false, // or use a function..
49845 * * @param {Object} details about module
49847 register : function(obj) {
49848 this.modules.push(obj);
49852 * convert a string to an object..
49856 toObject : function(str)
49858 if (!str || typeof(str) == 'object') {
49861 var ar = str.split('.');
49865 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
49867 throw "Module not found : " + str;
49869 Roo.each(ar, function(e) {
49870 if (typeof(o[e]) == 'undefined') {
49871 throw "Module not found : " + str;
49881 * move modules into their correct place in the tree..
49884 preBuild : function ()
49887 Roo.each(this.modules , function (obj)
49889 obj.parent = this.toObject(obj.parent);
49892 this.topModule = obj;
49896 if (!obj.parent.modules) {
49897 obj.parent.modules = new Roo.util.MixedCollection(false,
49898 function(o) { return o.order + '' }
49902 obj.parent.modules.add(obj);
49907 * make a list of modules to build.
49908 * @return {Array} list of modules.
49911 buildOrder : function()
49914 var cmp = function(a,b) {
49915 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
49918 if (!this.topModule || !this.topModule.modules) {
49919 throw "No top level modules to build";
49922 // make a flat list in order of modules to build.
49923 var mods = [ this.topModule ];
49926 // add modules to their parents..
49927 var addMod = function(m) {
49928 // console.log(m.modKey);
49932 m.modules.keySort('ASC', cmp );
49933 m.modules.each(addMod);
49935 // not sure if this is used any more..
49937 m.finalize.name = m.name + " (clean up) ";
49938 mods.push(m.finalize);
49942 this.topModule.modules.keySort('ASC', cmp );
49943 this.topModule.modules.each(addMod);
49948 * Build the registered modules.
49949 * @param {Object} parent element.
49950 * @param {Function} optional method to call after module has been added.
49958 var mods = this.buildOrder();
49960 //this.allmods = mods;
49961 //console.log(mods);
49963 if (!mods.length) { // should not happen
49964 throw "NO modules!!!";
49969 // flash it up as modal - so we store the mask!?
49970 Roo.MessageBox.show({ title: 'loading' });
49971 Roo.MessageBox.show({
49972 title: "Please wait...",
49973 msg: "Building Interface...",
49980 var total = mods.length;
49983 var progressRun = function() {
49984 if (!mods.length) {
49985 console.log('hide?');
49986 Roo.MessageBox.hide();
49987 _this.topModule.fireEvent('buildcomplete', _this.topModule);
49991 var m = mods.shift();
49993 if (typeof(m) == 'function') { // not sure if this is supported any more..
49995 return progressRun.defer(10, _this);
49998 Roo.MessageBox.updateProgress(
49999 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
50001 (m.name ? (' - ' + m.name) : '')
50006 var disabled = (typeof(m.disabled) == 'function') ?
50007 m.disabled.call(m.module.disabled) : m.disabled;
50011 return progressRun(); // we do not update the display!
50015 // it's a top level one..
50016 var layoutbase = new Ext.BorderLayout(document.body, {
50022 tabPosition: 'top',
50023 //resizeTabs: true,
50024 alwaysShowTabs: true,
50028 var tree = m.tree();
50029 tree.region = 'center';
50030 m.el = layoutbase.addxtype(tree);
50032 m.layout = m.panel.layout;
50033 return progressRun.defer(10, _this);
50036 var tree = m.tree();
50037 tree.region = tree.region || m.region;
50038 m.el = m.parent.el.addxtype(tree);
50039 m.fireEvent('built', m);
50041 m.layout = m.panel.layout;
50042 progressRun.defer(10, _this);
50045 progressRun.defer(1, _this);
50055 //<script type="text/javascript">
50060 * @extends Roo.LayoutDialog
50061 * A generic Login Dialog..... - only one needed in theory!?!?
50063 * Fires XComponent builder on success...
50066 * username,password, lang = for login actions.
50067 * check = 1 for periodic checking that sesion is valid.
50068 * passwordRequest = email request password
50069 * logout = 1 = to logout
50071 * Affects: (this id="????" elements)
50072 * loading (removed) (used to indicate application is loading)
50073 * loading-mask (hides) (used to hide application when it's building loading)
50079 * Myapp.login = Roo.Login({
50095 Roo.Login = function(cfg)
50098 'refreshed' : true,
50101 Roo.apply(this,cfg);
50103 Roo.onReady(function() {
50109 Roo.Login.superclass.constructor.call(this, this);
50110 //this.addxtype(this.items[0]);
50116 Roo.extend(Roo.Login, Roo.LayoutDialog, {
50119 * @cfg {String} method
50120 * Method used to query for login details.
50125 * @cfg {String} url
50126 * URL to query login data. - eg. baseURL + '/Login.php'
50132 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
50137 * @property checkFails
50138 * Number of times we have attempted to get authentication check, and failed.
50143 * @property intervalID
50144 * The window interval that does the constant login checking.
50150 onLoad : function() // called on page load...
50154 if (Roo.get('loading')) { // clear any loading indicator..
50155 Roo.get('loading').remove();
50158 //this.switchLang('en'); // set the language to english..
50161 success: function(response, opts) { // check successfull...
50163 var res = this.processResponse(response);
50164 this.checkFails =0;
50165 if (!res.success) { // error!
50166 this.checkFails = 5;
50167 //console.log('call failure');
50168 return this.failure(response,opts);
50171 if (!res.data.id) { // id=0 == login failure.
50172 return this.show();
50176 //console.log(success);
50177 this.fillAuth(res.data);
50178 this.checkFails =0;
50179 Roo.XComponent.build();
50181 failure : this.show
50187 check: function(cfg) // called every so often to refresh cookie etc..
50189 if (cfg.again) { // could be undefined..
50192 this.checkFails = 0;
50195 if (this.sending) {
50196 if ( this.checkFails > 4) {
50197 Roo.MessageBox.alert("Error",
50198 "Error getting authentication status. - try reloading, or wait a while", function() {
50199 _this.sending = false;
50204 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
50207 this.sending = true;
50214 method: this.method,
50215 success: cfg.success || this.success,
50216 failure : cfg.failure || this.failure,
50226 window.onbeforeunload = function() { }; // false does not work for IE..
50236 failure : function() {
50237 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
50238 document.location = document.location.toString() + '?ts=' + Math.random();
50242 success : function() {
50243 _this.user = false;
50244 this.checkFails =0;
50246 document.location = document.location.toString() + '?ts=' + Math.random();
50253 processResponse : function (response)
50257 res = Roo.decode(response.responseText);
50259 if (typeof(res) != 'object') {
50260 res = { success : false, errorMsg : res, errors : true };
50262 if (typeof(res.success) == 'undefined') {
50263 res.success = false;
50267 res = { success : false, errorMsg : response.responseText, errors : true };
50272 success : function(response, opts) // check successfull...
50274 this.sending = false;
50275 var res = this.processResponse(response);
50276 if (!res.success) {
50277 return this.failure(response, opts);
50279 if (!res.data || !res.data.id) {
50280 return this.failure(response,opts);
50282 //console.log(res);
50283 this.fillAuth(res.data);
50285 this.checkFails =0;
50290 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
50292 this.authUser = -1;
50293 this.sending = false;
50294 var res = this.processResponse(response);
50295 //console.log(res);
50296 if ( this.checkFails > 2) {
50298 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
50299 "Error getting authentication status. - try reloading");
50302 opts.callCfg.again = true;
50303 this.check.defer(1000, this, [ opts.callCfg ]);
50309 fillAuth: function(au) {
50310 this.startAuthCheck();
50311 this.authUserId = au.id;
50312 this.authUser = au;
50313 this.lastChecked = new Date();
50314 this.fireEvent('refreshed', au);
50315 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
50316 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
50317 au.lang = au.lang || 'en';
50318 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
50319 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
50320 this.switchLang(au.lang );
50323 // open system... - -on setyp..
50324 if (this.authUserId < 0) {
50325 Roo.MessageBox.alert("Warning",
50326 "This is an open system - please set up a admin user with a password.");
50329 //Pman.onload(); // which should do nothing if it's a re-auth result...
50334 startAuthCheck : function() // starter for timeout checking..
50336 if (this.intervalID) { // timer already in place...
50340 this.intervalID = window.setInterval(function() {
50341 _this.check(false);
50342 }, 120000); // every 120 secs = 2mins..
50348 switchLang : function (lang)
50350 _T = typeof(_T) == 'undefined' ? false : _T;
50351 if (!_T || !lang.length) {
50355 if (!_T && lang != 'en') {
50356 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
50360 if (typeof(_T.en) == 'undefined') {
50362 Roo.apply(_T.en, _T);
50365 if (typeof(_T[lang]) == 'undefined') {
50366 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
50371 Roo.apply(_T, _T[lang]);
50372 // just need to set the text values for everything...
50374 /* this will not work ...
50378 function formLabel(name, val) {
50379 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
50382 formLabel('password', "Password"+':');
50383 formLabel('username', "Email Address"+':');
50384 formLabel('lang', "Language"+':');
50385 this.dialog.setTitle("Login");
50386 this.dialog.buttons[0].setText("Forgot Password");
50387 this.dialog.buttons[1].setText("Login");
50406 collapsible: false,
50408 center: { // needed??
50411 // tabPosition: 'top',
50414 alwaysShowTabs: false
50418 show : function(dlg)
50420 //console.log(this);
50421 this.form = this.layout.getRegion('center').activePanel.form;
50422 this.form.dialog = dlg;
50423 this.buttons[0].form = this.form;
50424 this.buttons[0].dialog = dlg
50425 this.buttons[1].form = this.form;
50426 this.buttons[1].dialog = dlg;
50428 //this.resizeToLogo.defer(1000,this);
50429 // this is all related to resizing for logos..
50430 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
50432 // this.resizeToLogo.defer(1000,this);
50435 //var w = Ext.lib.Dom.getViewWidth() - 100;
50436 //var h = Ext.lib.Dom.getViewHeight() - 100;
50437 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
50439 if (this.disabled) {
50444 if (this.user.id < 0) { // used for inital setup situations.
50448 if (this.intervalID) {
50449 // remove the timer
50450 window.clearInterval(this.intervalID);
50451 this.intervalID = false;
50455 if (Roo.get('loading')) {
50456 Roo.get('loading').remove();
50458 if (Roo.get('loading-mask')) {
50459 Roo.get('loading-mask').hide();
50462 //incomming._node = tnode;
50464 //this.dialog.modal = !modal;
50465 //this.dialog.show();
50469 this.form.setValues({
50470 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
50471 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
50474 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
50475 if (this.form.findField('username').getValue().length > 0 ){
50476 this.form.findField('password').focus();
50478 this.form.findField('username').focus();
50486 xtype : 'ContentPanel',
50498 style : 'margin: 10px;',
50501 actionfailed : function(f, act) {
50502 // form can return { errors: .... }
50504 //act.result.errors // invalid form element list...
50505 //act.result.errorMsg// invalid form element list...
50507 this.dialog.el.unmask();
50508 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
50509 "Login failed - communication error - try again.");
50512 actioncomplete: function(re, act) {
50514 Roo.state.Manager.set(
50515 this.dialog.realm + '.username',
50516 this.findField('username').getValue()
50518 Roo.state.Manager.set(
50519 this.dialog.realm + '.lang',
50520 this.findField('lang').getValue()
50523 this.dialog.fillAuth(act.result.data);
50525 this.dialog.hide();
50527 if (Roo.get('loading-mask')) {
50528 Roo.get('loading-mask').show();
50530 Roo.XComponent.build();
50538 xtype : 'TextField',
50540 fieldLabel: "Email Address",
50543 autoCreate : {tag: "input", type: "text", size: "20"}
50546 xtype : 'TextField',
50548 fieldLabel: "Password",
50549 inputType: 'password',
50552 autoCreate : {tag: "input", type: "text", size: "20"},
50554 specialkey : function(e,ev) {
50555 if (ev.keyCode == 13) {
50556 this.form.dialog.el.mask("Logging in");
50557 this.form.doAction('submit', {
50558 url: this.form.dialog.url,
50559 method: this.form.dialog.method,
50566 xtype : 'ComboBox',
50568 fieldLabel: "Language",
50571 xtype : 'SimpleStore',
50572 fields: ['lang', 'ldisp'],
50574 [ 'en', 'English' ],
50575 [ 'zh_HK' , '\u7E41\u4E2D' ],
50576 [ 'zh_CN', '\u7C21\u4E2D' ]
50580 valueField : 'lang',
50581 hiddenName: 'lang',
50583 displayField:'ldisp',
50587 triggerAction: 'all',
50588 emptyText:'Select a Language...',
50589 selectOnFocus:true,
50591 select : function(cb, rec, ix) {
50592 this.form.switchLang(rec.data.lang);
50608 text : "Forgot Password",
50610 click : function() {
50611 //console.log(this);
50612 var n = this.form.findField('username').getValue();
50614 Roo.MessageBox.alert("Error", "Fill in your email address");
50618 url: this.dialog.url,
50622 method: this.dialog.method,
50623 success: function(response, opts) { // check successfull...
50625 var res = this.dialog.processResponse(response);
50626 if (!res.success) { // error!
50627 Roo.MessageBox.alert("Error" ,
50628 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
50631 Roo.MessageBox.alert("Notice" ,
50632 "Please check you email for the Password Reset message");
50634 failure : function() {
50635 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
50648 click : function () {
50650 this.dialog.el.mask("Logging in");
50651 this.form.doAction('submit', {
50652 url: this.dialog.url,
50653 method: this.dialog.method