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
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);
873 * Ext JS Library 1.1.1
874 * Copyright(c) 2006-2007, Ext JS, LLC.
876 * Originally Released Under LGPL - original licence link has changed is not relivant.
879 * <script type="text/javascript">
885 * The date parsing and format syntax is a subset of
886 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
887 * supported will provide results equivalent to their PHP versions.
889 * Following is the list of all currently supported formats:
892 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
894 Format Output Description
895 ------ ---------- --------------------------------------------------------------
896 d 10 Day of the month, 2 digits with leading zeros
897 D Wed A textual representation of a day, three letters
898 j 10 Day of the month without leading zeros
899 l Wednesday A full textual representation of the day of the week
900 S th English ordinal day of month suffix, 2 chars (use with j)
901 w 3 Numeric representation of the day of the week
902 z 9 The julian date, or day of the year (0-365)
903 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
904 F January A full textual representation of the month
905 m 01 Numeric representation of a month, with leading zeros
906 M Jan Month name abbreviation, three letters
907 n 1 Numeric representation of a month, without leading zeros
908 t 31 Number of days in the given month
909 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
910 Y 2007 A full numeric representation of a year, 4 digits
911 y 07 A two digit representation of a year
912 a pm Lowercase Ante meridiem and Post meridiem
913 A PM Uppercase Ante meridiem and Post meridiem
914 g 3 12-hour format of an hour without leading zeros
915 G 15 24-hour format of an hour without leading zeros
916 h 03 12-hour format of an hour with leading zeros
917 H 15 24-hour format of an hour with leading zeros
918 i 05 Minutes with leading zeros
919 s 01 Seconds, with leading zeros
920 O -0600 Difference to Greenwich time (GMT) in hours
921 T CST Timezone setting of the machine running the code
922 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
925 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
927 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
928 document.write(dt.format('Y-m-d')); //2007-01-10
929 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
930 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
933 * Here are some standard date/time patterns that you might find helpful. They
934 * are not part of the source of Date.js, but to use them you can simply copy this
935 * block of code into any script that is included after Date.js and they will also become
936 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
939 ISO8601Long:"Y-m-d H:i:s",
940 ISO8601Short:"Y-m-d",
942 LongDate: "l, F d, Y",
943 FullDateTime: "l, F d, Y g:i:s A",
947 SortableDateTime: "Y-m-d\\TH:i:s",
948 UniversalSortableDateTime: "Y-m-d H:i:sO",
956 document.write(dt.format(Date.patterns.ShortDate));
961 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
962 * They generate precompiled functions from date formats instead of parsing and
963 * processing the pattern every time you format a date. These functions are available
964 * on every Date object (any javascript function).
966 * The original article and download are here:
967 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
974 Returns the number of milliseconds between this date and date
975 @param {Date} date (optional) Defaults to now
976 @return {Number} The diff in milliseconds
977 @member Date getElapsed
979 Date.prototype.getElapsed = function(date) {
980 return Math.abs((date || new Date()).getTime()-this.getTime());
982 // was in date file..
986 Date.parseFunctions = {count:0};
988 Date.parseRegexes = [];
990 Date.formatFunctions = {count:0};
993 Date.prototype.dateFormat = function(format) {
994 if (Date.formatFunctions[format] == null) {
995 Date.createNewFormat(format);
997 var func = Date.formatFunctions[format];
1003 * Formats a date given the supplied format string
1004 * @param {String} format The format string
1005 * @return {String} The formatted date
1008 Date.prototype.format = Date.prototype.dateFormat;
1011 Date.createNewFormat = function(format) {
1012 var funcName = "format" + Date.formatFunctions.count++;
1013 Date.formatFunctions[format] = funcName;
1014 var code = "Date.prototype." + funcName + " = function(){return ";
1015 var special = false;
1017 for (var i = 0; i < format.length; ++i) {
1018 ch = format.charAt(i);
1019 if (!special && ch == "\\") {
1024 code += "'" + String.escape(ch) + "' + ";
1027 code += Date.getFormatCode(ch);
1030 /** eval:var:zzzzzzzzzzzzz */
1031 eval(code.substring(0, code.length - 3) + ";}");
1035 Date.getFormatCode = function(character) {
1036 switch (character) {
1038 return "String.leftPad(this.getDate(), 2, '0') + ";
1040 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1042 return "this.getDate() + ";
1044 return "Date.dayNames[this.getDay()] + ";
1046 return "this.getSuffix() + ";
1048 return "this.getDay() + ";
1050 return "this.getDayOfYear() + ";
1052 return "this.getWeekOfYear() + ";
1054 return "Date.monthNames[this.getMonth()] + ";
1056 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1058 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1060 return "(this.getMonth() + 1) + ";
1062 return "this.getDaysInMonth() + ";
1064 return "(this.isLeapYear() ? 1 : 0) + ";
1066 return "this.getFullYear() + ";
1068 return "('' + this.getFullYear()).substring(2, 4) + ";
1070 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1072 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1074 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1076 return "this.getHours() + ";
1078 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1080 return "String.leftPad(this.getHours(), 2, '0') + ";
1082 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1084 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1086 return "this.getGMTOffset() + ";
1088 return "this.getTimezone() + ";
1090 return "(this.getTimezoneOffset() * -60) + ";
1092 return "'" + String.escape(character) + "' + ";
1097 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1098 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1099 * the date format that is not specified will default to the current date value for that part. Time parts can also
1100 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1101 * string or the parse operation will fail.
1104 //dt = Fri May 25 2007 (current date)
1105 var dt = new Date();
1107 //dt = Thu May 25 2006 (today's month/day in 2006)
1108 dt = Date.parseDate("2006", "Y");
1110 //dt = Sun Jan 15 2006 (all date parts specified)
1111 dt = Date.parseDate("2006-1-15", "Y-m-d");
1113 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1114 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1116 * @param {String} input The unparsed date as a string
1117 * @param {String} format The format the date is in
1118 * @return {Date} The parsed date
1121 Date.parseDate = function(input, format) {
1122 if (Date.parseFunctions[format] == null) {
1123 Date.createParser(format);
1125 var func = Date.parseFunctions[format];
1126 return Date[func](input);
1131 Date.createParser = function(format) {
1132 var funcName = "parse" + Date.parseFunctions.count++;
1133 var regexNum = Date.parseRegexes.length;
1134 var currentGroup = 1;
1135 Date.parseFunctions[format] = funcName;
1137 var code = "Date." + funcName + " = function(input){\n"
1138 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1139 + "var d = new Date();\n"
1140 + "y = d.getFullYear();\n"
1141 + "m = d.getMonth();\n"
1142 + "d = d.getDate();\n"
1143 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1144 + "if (results && results.length > 0) {";
1147 var special = false;
1149 for (var i = 0; i < format.length; ++i) {
1150 ch = format.charAt(i);
1151 if (!special && ch == "\\") {
1156 regex += String.escape(ch);
1159 var obj = Date.formatCodeToRegex(ch, currentGroup);
1160 currentGroup += obj.g;
1162 if (obj.g && obj.c) {
1168 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1169 + "{v = new Date(y, m, d, h, i, s);}\n"
1170 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1171 + "{v = new Date(y, m, d, h, i);}\n"
1172 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1173 + "{v = new Date(y, m, d, h);}\n"
1174 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1175 + "{v = new Date(y, m, d);}\n"
1176 + "else if (y >= 0 && m >= 0)\n"
1177 + "{v = new Date(y, m);}\n"
1178 + "else if (y >= 0)\n"
1179 + "{v = new Date(y);}\n"
1180 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1181 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1182 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1185 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1186 /** eval:var:zzzzzzzzzzzzz */
1191 Date.formatCodeToRegex = function(character, currentGroup) {
1192 switch (character) {
1196 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1199 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1200 s:"(\\d{1,2})"}; // day of month without leading zeroes
1203 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1204 s:"(\\d{2})"}; // day of month with leading zeroes
1208 s:"(?:" + Date.dayNames.join("|") + ")"};
1212 s:"(?:st|nd|rd|th)"};
1227 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1228 s:"(" + Date.monthNames.join("|") + ")"};
1231 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1232 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1235 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1236 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1239 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1240 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1251 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1255 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1256 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1260 c:"if (results[" + currentGroup + "] == 'am') {\n"
1261 + "if (h == 12) { h = 0; }\n"
1262 + "} else { if (h < 12) { h += 12; }}",
1266 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1267 + "if (h == 12) { h = 0; }\n"
1268 + "} else { if (h < 12) { h += 12; }}",
1273 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1274 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1278 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1279 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1282 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1286 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1291 "o = results[", currentGroup, "];\n",
1292 "var sn = o.substring(0,1);\n", // get + / - sign
1293 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1294 "var mn = o.substring(3,5) % 60;\n", // get minutes
1295 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1296 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1302 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1305 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1306 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1307 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1311 s:String.escape(character)};
1316 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1317 * @return {String} The abbreviated timezone name (e.g. 'CST')
1319 Date.prototype.getTimezone = function() {
1320 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1324 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1325 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1327 Date.prototype.getGMTOffset = function() {
1328 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1329 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1330 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1334 * Get the numeric day number of the year, adjusted for leap year.
1335 * @return {Number} 0 through 364 (365 in leap years)
1337 Date.prototype.getDayOfYear = function() {
1339 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1340 for (var i = 0; i < this.getMonth(); ++i) {
1341 num += Date.daysInMonth[i];
1343 return num + this.getDate() - 1;
1347 * Get the string representation of the numeric week number of the year
1348 * (equivalent to the format specifier 'W').
1349 * @return {String} '00' through '52'
1351 Date.prototype.getWeekOfYear = function() {
1352 // Skip to Thursday of this week
1353 var now = this.getDayOfYear() + (4 - this.getDay());
1354 // Find the first Thursday of the year
1355 var jan1 = new Date(this.getFullYear(), 0, 1);
1356 var then = (7 - jan1.getDay() + 4);
1357 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1361 * Whether or not the current date is in a leap year.
1362 * @return {Boolean} True if the current date is in a leap year, else false
1364 Date.prototype.isLeapYear = function() {
1365 var year = this.getFullYear();
1366 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1370 * Get the first day of the current month, adjusted for leap year. The returned value
1371 * is the numeric day index within the week (0-6) which can be used in conjunction with
1372 * the {@link #monthNames} array to retrieve the textual day name.
1375 var dt = new Date('1/10/2007');
1376 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1378 * @return {Number} The day number (0-6)
1380 Date.prototype.getFirstDayOfMonth = function() {
1381 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1382 return (day < 0) ? (day + 7) : day;
1386 * Get the last day of the current month, adjusted for leap year. The returned value
1387 * is the numeric day index within the week (0-6) which can be used in conjunction with
1388 * the {@link #monthNames} array to retrieve the textual day name.
1391 var dt = new Date('1/10/2007');
1392 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1394 * @return {Number} The day number (0-6)
1396 Date.prototype.getLastDayOfMonth = function() {
1397 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1398 return (day < 0) ? (day + 7) : day;
1403 * Get the first date of this date's month
1406 Date.prototype.getFirstDateOfMonth = function() {
1407 return new Date(this.getFullYear(), this.getMonth(), 1);
1411 * Get the last date of this date's month
1414 Date.prototype.getLastDateOfMonth = function() {
1415 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1418 * Get the number of days in the current month, adjusted for leap year.
1419 * @return {Number} The number of days in the month
1421 Date.prototype.getDaysInMonth = function() {
1422 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1423 return Date.daysInMonth[this.getMonth()];
1427 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1428 * @return {String} 'st, 'nd', 'rd' or 'th'
1430 Date.prototype.getSuffix = function() {
1431 switch (this.getDate()) {
1448 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1451 * An array of textual month names.
1452 * Override these values for international dates, for example...
1453 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1472 * An array of textual day names.
1473 * Override these values for international dates, for example...
1474 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1490 Date.monthNumbers = {
1505 * Creates and returns a new Date instance with the exact same date value as the called instance.
1506 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1507 * variable will also be changed. When the intention is to create a new variable that will not
1508 * modify the original instance, you should create a clone.
1510 * Example of correctly cloning a date:
1513 var orig = new Date('10/1/2006');
1516 document.write(orig); //returns 'Thu Oct 05 2006'!
1519 var orig = new Date('10/1/2006');
1520 var copy = orig.clone();
1522 document.write(orig); //returns 'Thu Oct 01 2006'
1524 * @return {Date} The new Date instance
1526 Date.prototype.clone = function() {
1527 return new Date(this.getTime());
1531 * Clears any time information from this date
1532 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1533 @return {Date} this or the clone
1535 Date.prototype.clearTime = function(clone){
1537 return this.clone().clearTime();
1542 this.setMilliseconds(0);
1547 // safari setMonth is broken
1549 Date.brokenSetMonth = Date.prototype.setMonth;
1550 Date.prototype.setMonth = function(num){
1552 var n = Math.ceil(-num);
1553 var back_year = Math.ceil(n/12);
1554 var month = (n % 12) ? 12 - n % 12 : 0 ;
1555 this.setFullYear(this.getFullYear() - back_year);
1556 return Date.brokenSetMonth.call(this, month);
1558 return Date.brokenSetMonth.apply(this, arguments);
1563 /** Date interval constant
1567 /** Date interval constant
1571 /** Date interval constant
1575 /** Date interval constant
1579 /** Date interval constant
1583 /** Date interval constant
1587 /** Date interval constant
1593 * Provides a convenient method of performing basic date arithmetic. This method
1594 * does not modify the Date instance being called - it creates and returns
1595 * a new Date instance containing the resulting date value.
1600 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1601 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1603 //Negative values will subtract correctly:
1604 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1605 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1607 //You can even chain several calls together in one line!
1608 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1609 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1612 * @param {String} interval A valid date interval enum value
1613 * @param {Number} value The amount to add to the current date
1614 * @return {Date} The new Date instance
1616 Date.prototype.add = function(interval, value){
1617 var d = this.clone();
1618 if (!interval || value === 0) return d;
1619 switch(interval.toLowerCase()){
1621 d.setMilliseconds(this.getMilliseconds() + value);
1624 d.setSeconds(this.getSeconds() + value);
1627 d.setMinutes(this.getMinutes() + value);
1630 d.setHours(this.getHours() + value);
1633 d.setDate(this.getDate() + value);
1636 var day = this.getDate();
1638 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1641 d.setMonth(this.getMonth() + value);
1644 d.setFullYear(this.getFullYear() + value);
1650 * Ext JS Library 1.1.1
1651 * Copyright(c) 2006-2007, Ext JS, LLC.
1653 * Originally Released Under LGPL - original licence link has changed is not relivant.
1656 * <script type="text/javascript">
1660 getViewWidth : function(full) {
1661 return full ? this.getDocumentWidth() : this.getViewportWidth();
1664 getViewHeight : function(full) {
1665 return full ? this.getDocumentHeight() : this.getViewportHeight();
1668 getDocumentHeight: function() {
1669 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1670 return Math.max(scrollHeight, this.getViewportHeight());
1673 getDocumentWidth: function() {
1674 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1675 return Math.max(scrollWidth, this.getViewportWidth());
1678 getViewportHeight: function() {
1679 var height = self.innerHeight;
1680 var mode = document.compatMode;
1682 if ((mode || Roo.isIE) && !Roo.isOpera) {
1683 height = (mode == "CSS1Compat") ?
1684 document.documentElement.clientHeight :
1685 document.body.clientHeight;
1691 getViewportWidth: function() {
1692 var width = self.innerWidth;
1693 var mode = document.compatMode;
1695 if (mode || Roo.isIE) {
1696 width = (mode == "CSS1Compat") ?
1697 document.documentElement.clientWidth :
1698 document.body.clientWidth;
1703 isAncestor : function(p, c) {
1710 if (p.contains && !Roo.isSafari) {
1711 return p.contains(c);
1712 } else if (p.compareDocumentPosition) {
1713 return !!(p.compareDocumentPosition(c) & 16);
1715 var parent = c.parentNode;
1720 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1723 parent = parent.parentNode;
1729 getRegion : function(el) {
1730 return Roo.lib.Region.getRegion(el);
1733 getY : function(el) {
1734 return this.getXY(el)[1];
1737 getX : function(el) {
1738 return this.getXY(el)[0];
1741 getXY : function(el) {
1742 var p, pe, b, scroll, bd = document.body;
1743 el = Roo.getDom(el);
1744 var fly = Roo.lib.AnimBase.fly;
1745 if (el.getBoundingClientRect) {
1746 b = el.getBoundingClientRect();
1747 scroll = fly(document).getScroll();
1748 return [b.left + scroll.left, b.top + scroll.top];
1754 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1761 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1768 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1769 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1776 if (p != el && pe.getStyle('overflow') != 'visible') {
1784 if (Roo.isSafari && hasAbsolute) {
1789 if (Roo.isGecko && !hasAbsolute) {
1791 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1792 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1796 while (p && p != bd) {
1797 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1809 setXY : function(el, xy) {
1810 el = Roo.fly(el, '_setXY');
1812 var pts = el.translatePoints(xy);
1813 if (xy[0] !== false) {
1814 el.dom.style.left = pts.left + "px";
1816 if (xy[1] !== false) {
1817 el.dom.style.top = pts.top + "px";
1821 setX : function(el, x) {
1822 this.setXY(el, [x, false]);
1825 setY : function(el, y) {
1826 this.setXY(el, [false, y]);
1830 * Portions of this file are based on pieces of Yahoo User Interface Library
1831 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1832 * YUI licensed under the BSD License:
1833 * http://developer.yahoo.net/yui/license.txt
1834 * <script type="text/javascript">
1838 Roo.lib.Event = function() {
1839 var loadComplete = false;
1841 var unloadListeners = [];
1843 var onAvailStack = [];
1845 var lastError = null;
1858 startInterval: function() {
1859 if (!this._interval) {
1861 var callback = function() {
1862 self._tryPreloadAttach();
1864 this._interval = setInterval(callback, this.POLL_INTERVAL);
1869 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1870 onAvailStack.push({ id: p_id,
1873 override: p_override,
1874 checkReady: false });
1876 retryCount = this.POLL_RETRYS;
1877 this.startInterval();
1881 addListener: function(el, eventName, fn) {
1882 el = Roo.getDom(el);
1887 if ("unload" == eventName) {
1888 unloadListeners[unloadListeners.length] =
1889 [el, eventName, fn];
1893 var wrappedFn = function(e) {
1894 return fn(Roo.lib.Event.getEvent(e));
1897 var li = [el, eventName, fn, wrappedFn];
1899 var index = listeners.length;
1900 listeners[index] = li;
1902 this.doAdd(el, eventName, wrappedFn, false);
1908 removeListener: function(el, eventName, fn) {
1911 el = Roo.getDom(el);
1914 return this.purgeElement(el, false, eventName);
1918 if ("unload" == eventName) {
1920 for (i = 0,len = unloadListeners.length; i < len; i++) {
1921 var li = unloadListeners[i];
1924 li[1] == eventName &&
1926 unloadListeners.splice(i, 1);
1934 var cacheItem = null;
1937 var index = arguments[3];
1939 if ("undefined" == typeof index) {
1940 index = this._getCacheIndex(el, eventName, fn);
1944 cacheItem = listeners[index];
1947 if (!el || !cacheItem) {
1951 this.doRemove(el, eventName, cacheItem[this.WFN], false);
1953 delete listeners[index][this.WFN];
1954 delete listeners[index][this.FN];
1955 listeners.splice(index, 1);
1962 getTarget: function(ev, resolveTextNode) {
1963 ev = ev.browserEvent || ev;
1964 var t = ev.target || ev.srcElement;
1965 return this.resolveTextNode(t);
1969 resolveTextNode: function(node) {
1970 if (Roo.isSafari && node && 3 == node.nodeType) {
1971 return node.parentNode;
1978 getPageX: function(ev) {
1979 ev = ev.browserEvent || ev;
1981 if (!x && 0 !== x) {
1982 x = ev.clientX || 0;
1985 x += this.getScroll()[1];
1993 getPageY: function(ev) {
1994 ev = ev.browserEvent || ev;
1996 if (!y && 0 !== y) {
1997 y = ev.clientY || 0;
2000 y += this.getScroll()[0];
2009 getXY: function(ev) {
2010 ev = ev.browserEvent || ev;
2011 return [this.getPageX(ev), this.getPageY(ev)];
2015 getRelatedTarget: function(ev) {
2016 ev = ev.browserEvent || ev;
2017 var t = ev.relatedTarget;
2019 if (ev.type == "mouseout") {
2021 } else if (ev.type == "mouseover") {
2026 return this.resolveTextNode(t);
2030 getTime: function(ev) {
2031 ev = ev.browserEvent || ev;
2033 var t = new Date().getTime();
2037 this.lastError = ex;
2046 stopEvent: function(ev) {
2047 this.stopPropagation(ev);
2048 this.preventDefault(ev);
2052 stopPropagation: function(ev) {
2053 ev = ev.browserEvent || ev;
2054 if (ev.stopPropagation) {
2055 ev.stopPropagation();
2057 ev.cancelBubble = true;
2062 preventDefault: function(ev) {
2063 ev = ev.browserEvent || ev;
2064 if(ev.preventDefault) {
2065 ev.preventDefault();
2067 ev.returnValue = false;
2072 getEvent: function(e) {
2073 var ev = e || window.event;
2075 var c = this.getEvent.caller;
2077 ev = c.arguments[0];
2078 if (ev && Event == ev.constructor) {
2088 getCharCode: function(ev) {
2089 ev = ev.browserEvent || ev;
2090 return ev.charCode || ev.keyCode || 0;
2094 _getCacheIndex: function(el, eventName, fn) {
2095 for (var i = 0,len = listeners.length; i < len; ++i) {
2096 var li = listeners[i];
2098 li[this.FN] == fn &&
2099 li[this.EL] == el &&
2100 li[this.TYPE] == eventName) {
2112 getEl: function(id) {
2113 return document.getElementById(id);
2117 clearCache: function() {
2121 _load: function(e) {
2122 loadComplete = true;
2123 var EU = Roo.lib.Event;
2127 EU.doRemove(window, "load", EU._load);
2132 _tryPreloadAttach: function() {
2141 var tryAgain = !loadComplete;
2143 tryAgain = (retryCount > 0);
2148 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2149 var item = onAvailStack[i];
2151 var el = this.getEl(item.id);
2154 if (!item.checkReady ||
2157 (document && document.body)) {
2160 if (item.override) {
2161 if (item.override === true) {
2164 scope = item.override;
2167 item.fn.call(scope, item.obj);
2168 onAvailStack[i] = null;
2171 notAvail.push(item);
2176 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2180 this.startInterval();
2182 clearInterval(this._interval);
2183 this._interval = null;
2186 this.locked = false;
2193 purgeElement: function(el, recurse, eventName) {
2194 var elListeners = this.getListeners(el, eventName);
2196 for (var i = 0,len = elListeners.length; i < len; ++i) {
2197 var l = elListeners[i];
2198 this.removeListener(el, l.type, l.fn);
2202 if (recurse && el && el.childNodes) {
2203 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2204 this.purgeElement(el.childNodes[i], recurse, eventName);
2210 getListeners: function(el, eventName) {
2211 var results = [], searchLists;
2213 searchLists = [listeners, unloadListeners];
2214 } else if (eventName == "unload") {
2215 searchLists = [unloadListeners];
2217 searchLists = [listeners];
2220 for (var j = 0; j < searchLists.length; ++j) {
2221 var searchList = searchLists[j];
2222 if (searchList && searchList.length > 0) {
2223 for (var i = 0,len = searchList.length; i < len; ++i) {
2224 var l = searchList[i];
2225 if (l && l[this.EL] === el &&
2226 (!eventName || eventName === l[this.TYPE])) {
2231 adjust: l[this.ADJ_SCOPE],
2239 return (results.length) ? results : null;
2243 _unload: function(e) {
2245 var EU = Roo.lib.Event, i, j, l, len, index;
2247 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2248 l = unloadListeners[i];
2251 if (l[EU.ADJ_SCOPE]) {
2252 if (l[EU.ADJ_SCOPE] === true) {
2255 scope = l[EU.ADJ_SCOPE];
2258 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2259 unloadListeners[i] = null;
2265 unloadListeners = null;
2267 if (listeners && listeners.length > 0) {
2268 j = listeners.length;
2271 l = listeners[index];
2273 EU.removeListener(l[EU.EL], l[EU.TYPE],
2283 EU.doRemove(window, "unload", EU._unload);
2288 getScroll: function() {
2289 var dd = document.documentElement, db = document.body;
2290 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2291 return [dd.scrollTop, dd.scrollLeft];
2293 return [db.scrollTop, db.scrollLeft];
2300 doAdd: function () {
2301 if (window.addEventListener) {
2302 return function(el, eventName, fn, capture) {
2303 el.addEventListener(eventName, fn, (capture));
2305 } else if (window.attachEvent) {
2306 return function(el, eventName, fn, capture) {
2307 el.attachEvent("on" + eventName, fn);
2316 doRemove: function() {
2317 if (window.removeEventListener) {
2318 return function (el, eventName, fn, capture) {
2319 el.removeEventListener(eventName, fn, (capture));
2321 } else if (window.detachEvent) {
2322 return function (el, eventName, fn) {
2323 el.detachEvent("on" + eventName, fn);
2335 var E = Roo.lib.Event;
2336 E.on = E.addListener;
2337 E.un = E.removeListener;
2339 if (document && document.body) {
2342 E.doAdd(window, "load", E._load);
2344 E.doAdd(window, "unload", E._unload);
2345 E._tryPreloadAttach();
2349 * Portions of this file are based on pieces of Yahoo User Interface Library
2350 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2351 * YUI licensed under the BSD License:
2352 * http://developer.yahoo.net/yui/license.txt
2353 * <script type="text/javascript">
2360 request : function(method, uri, cb, data, options) {
2362 var hs = options.headers;
2365 if(hs.hasOwnProperty(h)){
2366 this.initHeader(h, hs[h], false);
2370 if(options.xmlData){
2371 this.initHeader('Content-Type', 'text/xml', false);
2373 data = options.xmlData;
2377 return this.asyncRequest(method, uri, cb, data);
2380 serializeForm : function(form) {
2381 if(typeof form == 'string') {
2382 form = (document.getElementById(form) || document.forms[form]);
2385 var el, name, val, disabled, data = '', hasSubmit = false;
2386 for (var i = 0; i < form.elements.length; i++) {
2387 el = form.elements[i];
2388 disabled = form.elements[i].disabled;
2389 name = form.elements[i].name;
2390 val = form.elements[i].value;
2392 if (!disabled && name){
2396 case 'select-multiple':
2397 for (var j = 0; j < el.options.length; j++) {
2398 if (el.options[j].selected) {
2400 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2403 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2411 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2424 if(hasSubmit == false) {
2425 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2430 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2435 data = data.substr(0, data.length - 1);
2443 useDefaultHeader:true,
2445 defaultPostHeader:'application/x-www-form-urlencoded',
2447 useDefaultXhrHeader:true,
2449 defaultXhrHeader:'XMLHttpRequest',
2451 hasDefaultHeaders:true,
2463 setProgId:function(id)
2465 this.activeX.unshift(id);
2468 setDefaultPostHeader:function(b)
2470 this.useDefaultHeader = b;
2473 setDefaultXhrHeader:function(b)
2475 this.useDefaultXhrHeader = b;
2478 setPollingInterval:function(i)
2480 if (typeof i == 'number' && isFinite(i)) {
2481 this.pollInterval = i;
2485 createXhrObject:function(transactionId)
2491 http = new XMLHttpRequest();
2493 obj = { conn:http, tId:transactionId };
2497 for (var i = 0; i < this.activeX.length; ++i) {
2501 http = new ActiveXObject(this.activeX[i]);
2503 obj = { conn:http, tId:transactionId };
2516 getConnectionObject:function()
2519 var tId = this.transactionId;
2523 o = this.createXhrObject(tId);
2525 this.transactionId++;
2536 asyncRequest:function(method, uri, callback, postData)
2538 var o = this.getConnectionObject();
2544 o.conn.open(method, uri, true);
2546 if (this.useDefaultXhrHeader) {
2547 if (!this.defaultHeaders['X-Requested-With']) {
2548 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2552 if(postData && this.useDefaultHeader){
2553 this.initHeader('Content-Type', this.defaultPostHeader);
2556 if (this.hasDefaultHeaders || this.hasHeaders) {
2560 this.handleReadyState(o, callback);
2561 o.conn.send(postData || null);
2567 handleReadyState:function(o, callback)
2571 if (callback && callback.timeout) {
2572 this.timeout[o.tId] = window.setTimeout(function() {
2573 oConn.abort(o, callback, true);
2574 }, callback.timeout);
2577 this.poll[o.tId] = window.setInterval(
2579 if (o.conn && o.conn.readyState == 4) {
2580 window.clearInterval(oConn.poll[o.tId]);
2581 delete oConn.poll[o.tId];
2583 if(callback && callback.timeout) {
2584 window.clearTimeout(oConn.timeout[o.tId]);
2585 delete oConn.timeout[o.tId];
2588 oConn.handleTransactionResponse(o, callback);
2591 , this.pollInterval);
2594 handleTransactionResponse:function(o, callback, isAbort)
2598 this.releaseObject(o);
2602 var httpStatus, responseObject;
2606 if (o.conn.status !== undefined && o.conn.status != 0) {
2607 httpStatus = o.conn.status;
2619 if (httpStatus >= 200 && httpStatus < 300) {
2620 responseObject = this.createResponseObject(o, callback.argument);
2621 if (callback.success) {
2622 if (!callback.scope) {
2623 callback.success(responseObject);
2628 callback.success.apply(callback.scope, [responseObject]);
2633 switch (httpStatus) {
2641 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2642 if (callback.failure) {
2643 if (!callback.scope) {
2644 callback.failure(responseObject);
2647 callback.failure.apply(callback.scope, [responseObject]);
2652 responseObject = this.createResponseObject(o, callback.argument);
2653 if (callback.failure) {
2654 if (!callback.scope) {
2655 callback.failure(responseObject);
2658 callback.failure.apply(callback.scope, [responseObject]);
2664 this.releaseObject(o);
2665 responseObject = null;
2668 createResponseObject:function(o, callbackArg)
2675 var headerStr = o.conn.getAllResponseHeaders();
2676 var header = headerStr.split('\n');
2677 for (var i = 0; i < header.length; i++) {
2678 var delimitPos = header[i].indexOf(':');
2679 if (delimitPos != -1) {
2680 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2688 obj.status = o.conn.status;
2689 obj.statusText = o.conn.statusText;
2690 obj.getResponseHeader = headerObj;
2691 obj.getAllResponseHeaders = headerStr;
2692 obj.responseText = o.conn.responseText;
2693 obj.responseXML = o.conn.responseXML;
2695 if (typeof callbackArg !== undefined) {
2696 obj.argument = callbackArg;
2702 createExceptionObject:function(tId, callbackArg, isAbort)
2705 var COMM_ERROR = 'communication failure';
2706 var ABORT_CODE = -1;
2707 var ABORT_ERROR = 'transaction aborted';
2713 obj.status = ABORT_CODE;
2714 obj.statusText = ABORT_ERROR;
2717 obj.status = COMM_CODE;
2718 obj.statusText = COMM_ERROR;
2722 obj.argument = callbackArg;
2728 initHeader:function(label, value, isDefault)
2730 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2732 if (headerObj[label] === undefined) {
2733 headerObj[label] = value;
2738 headerObj[label] = value + "," + headerObj[label];
2742 this.hasDefaultHeaders = true;
2745 this.hasHeaders = true;
2750 setHeader:function(o)
2752 if (this.hasDefaultHeaders) {
2753 for (var prop in this.defaultHeaders) {
2754 if (this.defaultHeaders.hasOwnProperty(prop)) {
2755 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2760 if (this.hasHeaders) {
2761 for (var prop in this.headers) {
2762 if (this.headers.hasOwnProperty(prop)) {
2763 o.conn.setRequestHeader(prop, this.headers[prop]);
2767 this.hasHeaders = false;
2771 resetDefaultHeaders:function() {
2772 delete this.defaultHeaders;
2773 this.defaultHeaders = {};
2774 this.hasDefaultHeaders = false;
2777 abort:function(o, callback, isTimeout)
2779 if(this.isCallInProgress(o)) {
2781 window.clearInterval(this.poll[o.tId]);
2782 delete this.poll[o.tId];
2784 delete this.timeout[o.tId];
2787 this.handleTransactionResponse(o, callback, true);
2797 isCallInProgress:function(o)
2800 return o.conn.readyState != 4 && o.conn.readyState != 0;
2809 releaseObject:function(o)
2818 'MSXML2.XMLHTTP.3.0',
2826 * Portions of this file are based on pieces of Yahoo User Interface Library
2827 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2828 * YUI licensed under the BSD License:
2829 * http://developer.yahoo.net/yui/license.txt
2830 * <script type="text/javascript">
2834 Roo.lib.Region = function(t, r, b, l) {
2844 Roo.lib.Region.prototype = {
2845 contains : function(region) {
2846 return ( region.left >= this.left &&
2847 region.right <= this.right &&
2848 region.top >= this.top &&
2849 region.bottom <= this.bottom );
2853 getArea : function() {
2854 return ( (this.bottom - this.top) * (this.right - this.left) );
2857 intersect : function(region) {
2858 var t = Math.max(this.top, region.top);
2859 var r = Math.min(this.right, region.right);
2860 var b = Math.min(this.bottom, region.bottom);
2861 var l = Math.max(this.left, region.left);
2863 if (b >= t && r >= l) {
2864 return new Roo.lib.Region(t, r, b, l);
2869 union : function(region) {
2870 var t = Math.min(this.top, region.top);
2871 var r = Math.max(this.right, region.right);
2872 var b = Math.max(this.bottom, region.bottom);
2873 var l = Math.min(this.left, region.left);
2875 return new Roo.lib.Region(t, r, b, l);
2878 adjust : function(t, l, b, r) {
2887 Roo.lib.Region.getRegion = function(el) {
2888 var p = Roo.lib.Dom.getXY(el);
2891 var r = p[0] + el.offsetWidth;
2892 var b = p[1] + el.offsetHeight;
2895 return new Roo.lib.Region(t, r, b, l);
2898 * Portions of this file are based on pieces of Yahoo User Interface Library
2899 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2900 * YUI licensed under the BSD License:
2901 * http://developer.yahoo.net/yui/license.txt
2902 * <script type="text/javascript">
2905 //@@dep Roo.lib.Region
2908 Roo.lib.Point = function(x, y) {
2909 if (x instanceof Array) {
2913 this.x = this.right = this.left = this[0] = x;
2914 this.y = this.top = this.bottom = this[1] = y;
2917 Roo.lib.Point.prototype = new Roo.lib.Region();
2919 * Portions of this file are based on pieces of Yahoo User Interface Library
2920 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2921 * YUI licensed under the BSD License:
2922 * http://developer.yahoo.net/yui/license.txt
2923 * <script type="text/javascript">
2930 scroll : function(el, args, duration, easing, cb, scope) {
2931 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2934 motion : function(el, args, duration, easing, cb, scope) {
2935 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2938 color : function(el, args, duration, easing, cb, scope) {
2939 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2942 run : function(el, args, duration, easing, cb, scope, type) {
2943 type = type || Roo.lib.AnimBase;
2944 if (typeof easing == "string") {
2945 easing = Roo.lib.Easing[easing];
2947 var anim = new type(el, args, duration, easing);
2948 anim.animateX(function() {
2949 Roo.callback(cb, scope);
2955 * Portions of this file are based on pieces of Yahoo User Interface Library
2956 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2957 * YUI licensed under the BSD License:
2958 * http://developer.yahoo.net/yui/license.txt
2959 * <script type="text/javascript">
2967 if (!libFlyweight) {
2968 libFlyweight = new Roo.Element.Flyweight();
2970 libFlyweight.dom = el;
2971 return libFlyweight;
2974 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2978 Roo.lib.AnimBase = function(el, attributes, duration, method) {
2980 this.init(el, attributes, duration, method);
2984 Roo.lib.AnimBase.fly = fly;
2988 Roo.lib.AnimBase.prototype = {
2990 toString: function() {
2991 var el = this.getEl();
2992 var id = el.id || el.tagName;
2993 return ("Anim " + id);
2997 noNegatives: /width|height|opacity|padding/i,
2998 offsetAttribute: /^((width|height)|(top|left))$/,
2999 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3000 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3004 doMethod: function(attr, start, end) {
3005 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3009 setAttribute: function(attr, val, unit) {
3010 if (this.patterns.noNegatives.test(attr)) {
3011 val = (val > 0) ? val : 0;
3014 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3018 getAttribute: function(attr) {
3019 var el = this.getEl();
3020 var val = fly(el).getStyle(attr);
3022 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3023 return parseFloat(val);
3026 var a = this.patterns.offsetAttribute.exec(attr) || [];
3027 var pos = !!( a[3] );
3028 var box = !!( a[2] );
3031 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3032 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3041 getDefaultUnit: function(attr) {
3042 if (this.patterns.defaultUnit.test(attr)) {
3049 animateX : function(callback, scope) {
3050 var f = function() {
3051 this.onComplete.removeListener(f);
3052 if (typeof callback == "function") {
3053 callback.call(scope || this, this);
3056 this.onComplete.addListener(f, this);
3061 setRuntimeAttribute: function(attr) {
3064 var attributes = this.attributes;
3066 this.runtimeAttributes[attr] = {};
3068 var isset = function(prop) {
3069 return (typeof prop !== 'undefined');
3072 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3076 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3079 if (isset(attributes[attr]['to'])) {
3080 end = attributes[attr]['to'];
3081 } else if (isset(attributes[attr]['by'])) {
3082 if (start.constructor == Array) {
3084 for (var i = 0, len = start.length; i < len; ++i) {
3085 end[i] = start[i] + attributes[attr]['by'][i];
3088 end = start + attributes[attr]['by'];
3092 this.runtimeAttributes[attr].start = start;
3093 this.runtimeAttributes[attr].end = end;
3096 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3100 init: function(el, attributes, duration, method) {
3102 var isAnimated = false;
3105 var startTime = null;
3108 var actualFrames = 0;
3111 el = Roo.getDom(el);
3114 this.attributes = attributes || {};
3117 this.duration = duration || 1;
3120 this.method = method || Roo.lib.Easing.easeNone;
3123 this.useSeconds = true;
3126 this.currentFrame = 0;
3129 this.totalFrames = Roo.lib.AnimMgr.fps;
3132 this.getEl = function() {
3137 this.isAnimated = function() {
3142 this.getStartTime = function() {
3146 this.runtimeAttributes = {};
3149 this.animate = function() {
3150 if (this.isAnimated()) {
3154 this.currentFrame = 0;
3156 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3158 Roo.lib.AnimMgr.registerElement(this);
3162 this.stop = function(finish) {
3164 this.currentFrame = this.totalFrames;
3165 this._onTween.fire();
3167 Roo.lib.AnimMgr.stop(this);
3170 var onStart = function() {
3171 this.onStart.fire();
3173 this.runtimeAttributes = {};
3174 for (var attr in this.attributes) {
3175 this.setRuntimeAttribute(attr);
3180 startTime = new Date();
3184 var onTween = function() {
3186 duration: new Date() - this.getStartTime(),
3187 currentFrame: this.currentFrame
3190 data.toString = function() {
3192 'duration: ' + data.duration +
3193 ', currentFrame: ' + data.currentFrame
3197 this.onTween.fire(data);
3199 var runtimeAttributes = this.runtimeAttributes;
3201 for (var attr in runtimeAttributes) {
3202 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3208 var onComplete = function() {
3209 var actual_duration = (new Date() - startTime) / 1000 ;
3212 duration: actual_duration,
3213 frames: actualFrames,
3214 fps: actualFrames / actual_duration
3217 data.toString = function() {
3219 'duration: ' + data.duration +
3220 ', frames: ' + data.frames +
3221 ', fps: ' + data.fps
3227 this.onComplete.fire(data);
3231 this._onStart = new Roo.util.Event(this);
3232 this.onStart = new Roo.util.Event(this);
3233 this.onTween = new Roo.util.Event(this);
3234 this._onTween = new Roo.util.Event(this);
3235 this.onComplete = new Roo.util.Event(this);
3236 this._onComplete = new Roo.util.Event(this);
3237 this._onStart.addListener(onStart);
3238 this._onTween.addListener(onTween);
3239 this._onComplete.addListener(onComplete);
3244 * Portions of this file are based on pieces of Yahoo User Interface Library
3245 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3246 * YUI licensed under the BSD License:
3247 * http://developer.yahoo.net/yui/license.txt
3248 * <script type="text/javascript">
3252 Roo.lib.AnimMgr = new function() {
3269 this.registerElement = function(tween) {
3270 queue[queue.length] = tween;
3272 tween._onStart.fire();
3277 this.unRegister = function(tween, index) {
3278 tween._onComplete.fire();
3279 index = index || getIndex(tween);
3281 queue.splice(index, 1);
3285 if (tweenCount <= 0) {
3291 this.start = function() {
3292 if (thread === null) {
3293 thread = setInterval(this.run, this.delay);
3298 this.stop = function(tween) {
3300 clearInterval(thread);
3302 for (var i = 0, len = queue.length; i < len; ++i) {
3303 if (queue[0].isAnimated()) {
3304 this.unRegister(queue[0], 0);
3313 this.unRegister(tween);
3318 this.run = function() {
3319 for (var i = 0, len = queue.length; i < len; ++i) {
3320 var tween = queue[i];
3321 if (!tween || !tween.isAnimated()) {
3325 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3327 tween.currentFrame += 1;
3329 if (tween.useSeconds) {
3330 correctFrame(tween);
3332 tween._onTween.fire();
3335 Roo.lib.AnimMgr.stop(tween, i);
3340 var getIndex = function(anim) {
3341 for (var i = 0, len = queue.length; i < len; ++i) {
3342 if (queue[i] == anim) {
3350 var correctFrame = function(tween) {
3351 var frames = tween.totalFrames;
3352 var frame = tween.currentFrame;
3353 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3354 var elapsed = (new Date() - tween.getStartTime());
3357 if (elapsed < tween.duration * 1000) {
3358 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3360 tweak = frames - (frame + 1);
3362 if (tweak > 0 && isFinite(tweak)) {
3363 if (tween.currentFrame + tweak >= frames) {
3364 tweak = frames - (frame + 1);
3367 tween.currentFrame += tweak;
3371 * Portions of this file are based on pieces of Yahoo User Interface Library
3372 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3373 * YUI licensed under the BSD License:
3374 * http://developer.yahoo.net/yui/license.txt
3375 * <script type="text/javascript">
3378 Roo.lib.Bezier = new function() {
3380 this.getPosition = function(points, t) {
3381 var n = points.length;
3384 for (var i = 0; i < n; ++i) {
3385 tmp[i] = [points[i][0], points[i][1]];
3388 for (var j = 1; j < n; ++j) {
3389 for (i = 0; i < n - j; ++i) {
3390 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3391 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3395 return [ tmp[0][0], tmp[0][1] ];
3399 * Portions of this file are based on pieces of Yahoo User Interface Library
3400 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3401 * YUI licensed under the BSD License:
3402 * http://developer.yahoo.net/yui/license.txt
3403 * <script type="text/javascript">
3408 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3409 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3412 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3414 var fly = Roo.lib.AnimBase.fly;
3416 var superclass = Y.ColorAnim.superclass;
3417 var proto = Y.ColorAnim.prototype;
3419 proto.toString = function() {
3420 var el = this.getEl();
3421 var id = el.id || el.tagName;
3422 return ("ColorAnim " + id);
3425 proto.patterns.color = /color$/i;
3426 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3427 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3428 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3429 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3432 proto.parseColor = function(s) {
3433 if (s.length == 3) {
3437 var c = this.patterns.hex.exec(s);
3438 if (c && c.length == 4) {
3439 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3442 c = this.patterns.rgb.exec(s);
3443 if (c && c.length == 4) {
3444 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3447 c = this.patterns.hex3.exec(s);
3448 if (c && c.length == 4) {
3449 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3454 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3455 proto.getAttribute = function(attr) {
3456 var el = this.getEl();
3457 if (this.patterns.color.test(attr)) {
3458 var val = fly(el).getStyle(attr);
3460 if (this.patterns.transparent.test(val)) {
3461 var parent = el.parentNode;
3462 val = fly(parent).getStyle(attr);
3464 while (parent && this.patterns.transparent.test(val)) {
3465 parent = parent.parentNode;
3466 val = fly(parent).getStyle(attr);
3467 if (parent.tagName.toUpperCase() == 'HTML') {
3473 val = superclass.getAttribute.call(this, attr);
3478 proto.getAttribute = function(attr) {
3479 var el = this.getEl();
3480 if (this.patterns.color.test(attr)) {
3481 var val = fly(el).getStyle(attr);
3483 if (this.patterns.transparent.test(val)) {
3484 var parent = el.parentNode;
3485 val = fly(parent).getStyle(attr);
3487 while (parent && this.patterns.transparent.test(val)) {
3488 parent = parent.parentNode;
3489 val = fly(parent).getStyle(attr);
3490 if (parent.tagName.toUpperCase() == 'HTML') {
3496 val = superclass.getAttribute.call(this, attr);
3502 proto.doMethod = function(attr, start, end) {
3505 if (this.patterns.color.test(attr)) {
3507 for (var i = 0, len = start.length; i < len; ++i) {
3508 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3511 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3514 val = superclass.doMethod.call(this, attr, start, end);
3520 proto.setRuntimeAttribute = function(attr) {
3521 superclass.setRuntimeAttribute.call(this, attr);
3523 if (this.patterns.color.test(attr)) {
3524 var attributes = this.attributes;
3525 var start = this.parseColor(this.runtimeAttributes[attr].start);
3526 var end = this.parseColor(this.runtimeAttributes[attr].end);
3528 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3529 end = this.parseColor(attributes[attr].by);
3531 for (var i = 0, len = start.length; i < len; ++i) {
3532 end[i] = start[i] + end[i];
3536 this.runtimeAttributes[attr].start = start;
3537 this.runtimeAttributes[attr].end = end;
3543 * Portions of this file are based on pieces of Yahoo User Interface Library
3544 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3545 * YUI licensed under the BSD License:
3546 * http://developer.yahoo.net/yui/license.txt
3547 * <script type="text/javascript">
3553 easeNone: function (t, b, c, d) {
3554 return c * t / d + b;
3558 easeIn: function (t, b, c, d) {
3559 return c * (t /= d) * t + b;
3563 easeOut: function (t, b, c, d) {
3564 return -c * (t /= d) * (t - 2) + b;
3568 easeBoth: function (t, b, c, d) {
3569 if ((t /= d / 2) < 1) {
3570 return c / 2 * t * t + b;
3573 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3577 easeInStrong: function (t, b, c, d) {
3578 return c * (t /= d) * t * t * t + b;
3582 easeOutStrong: function (t, b, c, d) {
3583 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3587 easeBothStrong: function (t, b, c, d) {
3588 if ((t /= d / 2) < 1) {
3589 return c / 2 * t * t * t * t + b;
3592 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3597 elasticIn: function (t, b, c, d, a, p) {
3601 if ((t /= d) == 1) {
3608 if (!a || a < Math.abs(c)) {
3613 var s = p / (2 * Math.PI) * Math.asin(c / a);
3616 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3620 elasticOut: function (t, b, c, d, a, p) {
3624 if ((t /= d) == 1) {
3631 if (!a || a < Math.abs(c)) {
3636 var s = p / (2 * Math.PI) * Math.asin(c / a);
3639 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3643 elasticBoth: function (t, b, c, d, a, p) {
3648 if ((t /= d / 2) == 2) {
3656 if (!a || a < Math.abs(c)) {
3661 var s = p / (2 * Math.PI) * Math.asin(c / a);
3665 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3666 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3668 return a * Math.pow(2, -10 * (t -= 1)) *
3669 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3674 backIn: function (t, b, c, d, s) {
3675 if (typeof s == 'undefined') {
3678 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3682 backOut: function (t, b, c, d, s) {
3683 if (typeof s == 'undefined') {
3686 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3690 backBoth: function (t, b, c, d, s) {
3691 if (typeof s == 'undefined') {
3695 if ((t /= d / 2 ) < 1) {
3696 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3698 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3702 bounceIn: function (t, b, c, d) {
3703 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3707 bounceOut: function (t, b, c, d) {
3708 if ((t /= d) < (1 / 2.75)) {
3709 return c * (7.5625 * t * t) + b;
3710 } else if (t < (2 / 2.75)) {
3711 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3712 } else if (t < (2.5 / 2.75)) {
3713 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3715 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3719 bounceBoth: function (t, b, c, d) {
3721 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3723 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3726 * Portions of this file are based on pieces of Yahoo User Interface Library
3727 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3728 * YUI licensed under the BSD License:
3729 * http://developer.yahoo.net/yui/license.txt
3730 * <script type="text/javascript">
3734 Roo.lib.Motion = function(el, attributes, duration, method) {
3736 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3740 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3744 var superclass = Y.Motion.superclass;
3745 var proto = Y.Motion.prototype;
3747 proto.toString = function() {
3748 var el = this.getEl();
3749 var id = el.id || el.tagName;
3750 return ("Motion " + id);
3753 proto.patterns.points = /^points$/i;
3755 proto.setAttribute = function(attr, val, unit) {
3756 if (this.patterns.points.test(attr)) {
3757 unit = unit || 'px';
3758 superclass.setAttribute.call(this, 'left', val[0], unit);
3759 superclass.setAttribute.call(this, 'top', val[1], unit);
3761 superclass.setAttribute.call(this, attr, val, unit);
3765 proto.getAttribute = function(attr) {
3766 if (this.patterns.points.test(attr)) {
3768 superclass.getAttribute.call(this, 'left'),
3769 superclass.getAttribute.call(this, 'top')
3772 val = superclass.getAttribute.call(this, attr);
3778 proto.doMethod = function(attr, start, end) {
3781 if (this.patterns.points.test(attr)) {
3782 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3783 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3785 val = superclass.doMethod.call(this, attr, start, end);
3790 proto.setRuntimeAttribute = function(attr) {
3791 if (this.patterns.points.test(attr)) {
3792 var el = this.getEl();
3793 var attributes = this.attributes;
3795 var control = attributes['points']['control'] || [];
3799 if (control.length > 0 && !(control[0] instanceof Array)) {
3800 control = [control];
3803 for (i = 0,len = control.length; i < len; ++i) {
3804 tmp[i] = control[i];
3809 Roo.fly(el).position();
3811 if (isset(attributes['points']['from'])) {
3812 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3815 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3818 start = this.getAttribute('points');
3821 if (isset(attributes['points']['to'])) {
3822 end = translateValues.call(this, attributes['points']['to'], start);
3824 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3825 for (i = 0,len = control.length; i < len; ++i) {
3826 control[i] = translateValues.call(this, control[i], start);
3830 } else if (isset(attributes['points']['by'])) {
3831 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3833 for (i = 0,len = control.length; i < len; ++i) {
3834 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3838 this.runtimeAttributes[attr] = [start];
3840 if (control.length > 0) {
3841 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3844 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3847 superclass.setRuntimeAttribute.call(this, attr);
3851 var translateValues = function(val, start) {
3852 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3853 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3858 var isset = function(prop) {
3859 return (typeof prop !== 'undefined');
3863 * Portions of this file are based on pieces of Yahoo User Interface Library
3864 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3865 * YUI licensed under the BSD License:
3866 * http://developer.yahoo.net/yui/license.txt
3867 * <script type="text/javascript">
3871 Roo.lib.Scroll = function(el, attributes, duration, method) {
3873 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3877 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3881 var superclass = Y.Scroll.superclass;
3882 var proto = Y.Scroll.prototype;
3884 proto.toString = function() {
3885 var el = this.getEl();
3886 var id = el.id || el.tagName;
3887 return ("Scroll " + id);
3890 proto.doMethod = function(attr, start, end) {
3893 if (attr == 'scroll') {
3895 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3896 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3900 val = superclass.doMethod.call(this, attr, start, end);
3905 proto.getAttribute = function(attr) {
3907 var el = this.getEl();
3909 if (attr == 'scroll') {
3910 val = [ el.scrollLeft, el.scrollTop ];
3912 val = superclass.getAttribute.call(this, attr);
3918 proto.setAttribute = function(attr, val, unit) {
3919 var el = this.getEl();
3921 if (attr == 'scroll') {
3922 el.scrollLeft = val[0];
3923 el.scrollTop = val[1];
3925 superclass.setAttribute.call(this, attr, val, unit);
3931 * Ext JS Library 1.1.1
3932 * Copyright(c) 2006-2007, Ext JS, LLC.
3934 * Originally Released Under LGPL - original licence link has changed is not relivant.
3937 * <script type="text/javascript">
3942 * @class Roo.DomHelper
3943 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3944 * 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>.
3947 Roo.DomHelper = function(){
3948 var tempTableEl = null;
3949 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3950 var tableRe = /^table|tbody|tr|td$/i;
3952 // build as innerHTML where available
3954 var createHtml = function(o){
3955 if(typeof o == 'string'){
3964 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3965 if(attr == "style"){
3967 if(typeof s == "function"){
3970 if(typeof s == "string"){
3971 b += ' style="' + s + '"';
3972 }else if(typeof s == "object"){
3975 if(typeof s[key] != "function"){
3976 b += key + ":" + s[key] + ";";
3983 b += ' class="' + o["cls"] + '"';
3984 }else if(attr == "htmlFor"){
3985 b += ' for="' + o["htmlFor"] + '"';
3987 b += " " + attr + '="' + o[attr] + '"';
3991 if(emptyTags.test(o.tag)){
3995 var cn = o.children || o.cn;
3997 //http://bugs.kde.org/show_bug.cgi?id=71506
3998 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
3999 for(var i = 0, len = cn.length; i < len; i++) {
4000 b += createHtml(cn[i], b);
4003 b += createHtml(cn, b);
4009 b += "</" + o.tag + ">";
4016 var createDom = function(o, parentNode){
4018 // defininition craeted..
4020 if (o.ns && o.ns != 'html') {
4022 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4023 xmlns[o.ns] = o.xmlns;
4026 if (typeof(xmlns[o.ns]) == 'undefined') {
4027 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4033 if (typeof(o) == 'string') {
4034 return parentNode.appendChild(document.createTextNode(o));
4036 o.tag = o.tag || div;
4037 if (o.ns && Roo.isIE) {
4039 o.tag = o.ns + ':' + o.tag;
4042 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4043 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4046 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4047 attr == "style" || typeof o[attr] == "function") continue;
4049 if(attr=="cls" && Roo.isIE){
4050 el.className = o["cls"];
4052 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4053 else el[attr] = o[attr];
4056 Roo.DomHelper.applyStyles(el, o.style);
4057 var cn = o.children || o.cn;
4059 //http://bugs.kde.org/show_bug.cgi?id=71506
4060 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4061 for(var i = 0, len = cn.length; i < len; i++) {
4062 createDom(cn[i], el);
4069 el.innerHTML = o.html;
4072 parentNode.appendChild(el);
4077 var ieTable = function(depth, s, h, e){
4078 tempTableEl.innerHTML = [s, h, e].join('');
4079 var i = -1, el = tempTableEl;
4086 // kill repeat to save bytes
4090 tbe = '</tbody>'+te,
4096 * Nasty code for IE's broken table implementation
4098 var insertIntoTable = function(tag, where, el, html){
4100 tempTableEl = document.createElement('div');
4105 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4108 if(where == 'beforebegin'){
4112 before = el.nextSibling;
4115 node = ieTable(4, trs, html, tre);
4117 else if(tag == 'tr'){
4118 if(where == 'beforebegin'){
4121 node = ieTable(3, tbs, html, tbe);
4122 } else if(where == 'afterend'){
4123 before = el.nextSibling;
4125 node = ieTable(3, tbs, html, tbe);
4126 } else{ // INTO a TR
4127 if(where == 'afterbegin'){
4128 before = el.firstChild;
4130 node = ieTable(4, trs, html, tre);
4132 } else if(tag == 'tbody'){
4133 if(where == 'beforebegin'){
4136 node = ieTable(2, ts, html, te);
4137 } else if(where == 'afterend'){
4138 before = el.nextSibling;
4140 node = ieTable(2, ts, html, te);
4142 if(where == 'afterbegin'){
4143 before = el.firstChild;
4145 node = ieTable(3, tbs, html, tbe);
4148 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4151 if(where == 'afterbegin'){
4152 before = el.firstChild;
4154 node = ieTable(2, ts, html, te);
4156 el.insertBefore(node, before);
4161 /** True to force the use of DOM instead of html fragments @type Boolean */
4165 * Returns the markup for the passed Element(s) config
4166 * @param {Object} o The Dom object spec (and children)
4169 markup : function(o){
4170 return createHtml(o);
4174 * Applies a style specification to an element
4175 * @param {String/HTMLElement} el The element to apply styles to
4176 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4177 * a function which returns such a specification.
4179 applyStyles : function(el, styles){
4182 if(typeof styles == "string"){
4183 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4185 while ((matches = re.exec(styles)) != null){
4186 el.setStyle(matches[1], matches[2]);
4188 }else if (typeof styles == "object"){
4189 for (var style in styles){
4190 el.setStyle(style, styles[style]);
4192 }else if (typeof styles == "function"){
4193 Roo.DomHelper.applyStyles(el, styles.call());
4199 * Inserts an HTML fragment into the Dom
4200 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4201 * @param {HTMLElement} el The context element
4202 * @param {String} html The HTML fragmenet
4203 * @return {HTMLElement} The new node
4205 insertHtml : function(where, el, html){
4206 where = where.toLowerCase();
4207 if(el.insertAdjacentHTML){
4208 if(tableRe.test(el.tagName)){
4210 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4216 el.insertAdjacentHTML('BeforeBegin', html);
4217 return el.previousSibling;
4219 el.insertAdjacentHTML('AfterBegin', html);
4220 return el.firstChild;
4222 el.insertAdjacentHTML('BeforeEnd', html);
4223 return el.lastChild;
4225 el.insertAdjacentHTML('AfterEnd', html);
4226 return el.nextSibling;
4228 throw 'Illegal insertion point -> "' + where + '"';
4230 var range = el.ownerDocument.createRange();
4234 range.setStartBefore(el);
4235 frag = range.createContextualFragment(html);
4236 el.parentNode.insertBefore(frag, el);
4237 return el.previousSibling;
4240 range.setStartBefore(el.firstChild);
4241 frag = range.createContextualFragment(html);
4242 el.insertBefore(frag, el.firstChild);
4243 return el.firstChild;
4245 el.innerHTML = html;
4246 return el.firstChild;
4250 range.setStartAfter(el.lastChild);
4251 frag = range.createContextualFragment(html);
4252 el.appendChild(frag);
4253 return el.lastChild;
4255 el.innerHTML = html;
4256 return el.lastChild;
4259 range.setStartAfter(el);
4260 frag = range.createContextualFragment(html);
4261 el.parentNode.insertBefore(frag, el.nextSibling);
4262 return el.nextSibling;
4264 throw 'Illegal insertion point -> "' + where + '"';
4268 * Creates new Dom element(s) and inserts them before el
4269 * @param {String/HTMLElement/Element} el The context element
4270 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4271 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4272 * @return {HTMLElement/Roo.Element} The new node
4274 insertBefore : function(el, o, returnElement){
4275 return this.doInsert(el, o, returnElement, "beforeBegin");
4279 * Creates new Dom element(s) and inserts them after el
4280 * @param {String/HTMLElement/Element} el The context element
4281 * @param {Object} o The Dom object spec (and children)
4282 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4283 * @return {HTMLElement/Roo.Element} The new node
4285 insertAfter : function(el, o, returnElement){
4286 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4290 * Creates new Dom element(s) and inserts them as the first child of el
4291 * @param {String/HTMLElement/Element} el The context element
4292 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4293 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4294 * @return {HTMLElement/Roo.Element} The new node
4296 insertFirst : function(el, o, returnElement){
4297 return this.doInsert(el, o, returnElement, "afterBegin");
4301 doInsert : function(el, o, returnElement, pos, sibling){
4302 el = Roo.getDom(el);
4304 if(this.useDom || o.ns){
4305 newNode = createDom(o, null);
4306 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4308 var html = createHtml(o);
4309 newNode = this.insertHtml(pos, el, html);
4311 return returnElement ? Roo.get(newNode, true) : newNode;
4315 * Creates new Dom element(s) and appends them to el
4316 * @param {String/HTMLElement/Element} el The context element
4317 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4318 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4319 * @return {HTMLElement/Roo.Element} The new node
4321 append : function(el, o, returnElement){
4322 el = Roo.getDom(el);
4324 if(this.useDom || o.ns){
4325 newNode = createDom(o, null);
4326 el.appendChild(newNode);
4328 var html = createHtml(o);
4329 newNode = this.insertHtml("beforeEnd", el, html);
4331 return returnElement ? Roo.get(newNode, true) : newNode;
4335 * Creates new Dom element(s) and overwrites the contents of el with them
4336 * @param {String/HTMLElement/Element} el The context element
4337 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4338 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4339 * @return {HTMLElement/Roo.Element} The new node
4341 overwrite : function(el, o, returnElement){
4342 el = Roo.getDom(el);
4345 while (el.childNodes.length) {
4346 el.removeChild(el.firstChild);
4350 el.innerHTML = createHtml(o);
4353 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4357 * Creates a new Roo.DomHelper.Template from the Dom object spec
4358 * @param {Object} o The Dom object spec (and children)
4359 * @return {Roo.DomHelper.Template} The new template
4361 createTemplate : function(o){
4362 var html = createHtml(o);
4363 return new Roo.Template(html);
4369 * Ext JS Library 1.1.1
4370 * Copyright(c) 2006-2007, Ext JS, LLC.
4372 * Originally Released Under LGPL - original licence link has changed is not relivant.
4375 * <script type="text/javascript">
4379 * @class Roo.Template
4380 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4381 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4384 var t = new Roo.Template(
4385 '<div name="{id}">',
4386 '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
4389 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4391 * 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>.
4393 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4395 Roo.Template = function(html){
4396 if(html instanceof Array){
4397 html = html.join("");
4398 }else if(arguments.length > 1){
4399 html = Array.prototype.join.call(arguments, "");
4405 Roo.Template.prototype = {
4407 * Returns an HTML fragment of this template with the specified values applied.
4408 * @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'})
4409 * @return {String} The HTML fragment
4411 applyTemplate : function(values){
4413 return this.compiled(values);
4415 var useF = this.disableFormats !== true;
4416 var fm = Roo.util.Format, tpl = this;
4417 var fn = function(m, name, format, args){
4419 if(format.substr(0, 5) == "this."){
4420 return tpl.call(format.substr(5), values[name], values);
4423 // quoted values are required for strings in compiled templates,
4424 // but for non compiled we need to strip them
4425 // quoted reversed for jsmin
4426 var re = /^\s*['"](.*)["']\s*$/;
4427 args = args.split(',');
4428 for(var i = 0, len = args.length; i < len; i++){
4429 args[i] = args[i].replace(re, "$1");
4431 args = [values[name]].concat(args);
4433 args = [values[name]];
4435 return fm[format].apply(fm, args);
4438 return values[name] !== undefined ? values[name] : "";
4441 return this.html.replace(this.re, fn);
4445 * Sets the HTML used as the template and optionally compiles it.
4446 * @param {String} html
4447 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4448 * @return {Roo.Template} this
4450 set : function(html, compile){
4452 this.compiled = null;
4460 * True to disable format functions (defaults to false)
4463 disableFormats : false,
4466 * The regular expression used to match template variables
4470 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4473 * Compiles the template into an internal function, eliminating the RegEx overhead.
4474 * @return {Roo.Template} this
4476 compile : function(){
4477 var fm = Roo.util.Format;
4478 var useF = this.disableFormats !== true;
4479 var sep = Roo.isGecko ? "+" : ",";
4480 var fn = function(m, name, format, args){
4482 args = args ? ',' + args : "";
4483 if(format.substr(0, 5) != "this."){
4484 format = "fm." + format + '(';
4486 format = 'this.call("'+ format.substr(5) + '", ';
4490 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4492 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4495 // branched to use + in gecko and [].join() in others
4497 body = "this.compiled = function(values){ return '" +
4498 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4501 body = ["this.compiled = function(values){ return ['"];
4502 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4503 body.push("'].join('');};");
4504 body = body.join('');
4514 // private function used to call members
4515 call : function(fnName, value, allValues){
4516 return this[fnName](value, allValues);
4520 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4521 * @param {String/HTMLElement/Roo.Element} el The context element
4522 * @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'})
4523 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4524 * @return {HTMLElement/Roo.Element} The new node or Element
4526 insertFirst: function(el, values, returnElement){
4527 return this.doInsert('afterBegin', el, values, returnElement);
4531 * Applies the supplied values to the template and inserts the new node(s) before el.
4532 * @param {String/HTMLElement/Roo.Element} el The context element
4533 * @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'})
4534 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4535 * @return {HTMLElement/Roo.Element} The new node or Element
4537 insertBefore: function(el, values, returnElement){
4538 return this.doInsert('beforeBegin', el, values, returnElement);
4542 * Applies the supplied values to the template and inserts the new node(s) after el.
4543 * @param {String/HTMLElement/Roo.Element} el The context element
4544 * @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'})
4545 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4546 * @return {HTMLElement/Roo.Element} The new node or Element
4548 insertAfter : function(el, values, returnElement){
4549 return this.doInsert('afterEnd', el, values, returnElement);
4553 * Applies the supplied values to the template and appends the new node(s) to el.
4554 * @param {String/HTMLElement/Roo.Element} el The context element
4555 * @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'})
4556 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4557 * @return {HTMLElement/Roo.Element} The new node or Element
4559 append : function(el, values, returnElement){
4560 return this.doInsert('beforeEnd', el, values, returnElement);
4563 doInsert : function(where, el, values, returnEl){
4564 el = Roo.getDom(el);
4565 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4566 return returnEl ? Roo.get(newNode, true) : newNode;
4570 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4571 * @param {String/HTMLElement/Roo.Element} el The context element
4572 * @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'})
4573 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4574 * @return {HTMLElement/Roo.Element} The new node or Element
4576 overwrite : function(el, values, returnElement){
4577 el = Roo.getDom(el);
4578 el.innerHTML = this.applyTemplate(values);
4579 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4583 * Alias for {@link #applyTemplate}
4586 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4589 Roo.DomHelper.Template = Roo.Template;
4592 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4593 * @param {String/HTMLElement} el A DOM element or its id
4594 * @returns {Roo.Template} The created template
4597 Roo.Template.from = function(el){
4598 el = Roo.getDom(el);
4599 return new Roo.Template(el.value || el.innerHTML);
4602 * Ext JS Library 1.1.1
4603 * Copyright(c) 2006-2007, Ext JS, LLC.
4605 * Originally Released Under LGPL - original licence link has changed is not relivant.
4608 * <script type="text/javascript">
4613 * This is code is also distributed under MIT license for use
4614 * with jQuery and prototype JavaScript libraries.
4617 * @class Roo.DomQuery
4618 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).
4620 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>
4623 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.
4625 <h4>Element Selectors:</h4>
4627 <li> <b>*</b> any element</li>
4628 <li> <b>E</b> an element with the tag E</li>
4629 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4630 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4631 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4632 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4634 <h4>Attribute Selectors:</h4>
4635 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4637 <li> <b>E[foo]</b> has an attribute "foo"</li>
4638 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4639 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4640 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4641 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4642 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4643 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4645 <h4>Pseudo Classes:</h4>
4647 <li> <b>E:first-child</b> E is the first child of its parent</li>
4648 <li> <b>E:last-child</b> E is the last child of its parent</li>
4649 <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>
4650 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4651 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4652 <li> <b>E:only-child</b> E is the only child of its parent</li>
4653 <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>
4654 <li> <b>E:first</b> the first E in the resultset</li>
4655 <li> <b>E:last</b> the last E in the resultset</li>
4656 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4657 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4658 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4659 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4660 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4661 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4662 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4663 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4664 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4666 <h4>CSS Value Selectors:</h4>
4668 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4669 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4670 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4671 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4672 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4673 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4677 Roo.DomQuery = function(){
4678 var cache = {}, simpleCache = {}, valueCache = {};
4679 var nonSpace = /\S/;
4680 var trimRe = /^\s+|\s+$/g;
4681 var tplRe = /\{(\d+)\}/g;
4682 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4683 var tagTokenRe = /^(#)?([\w-\*]+)/;
4684 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4686 function child(p, index){
4688 var n = p.firstChild;
4690 if(n.nodeType == 1){
4701 while((n = n.nextSibling) && n.nodeType != 1);
4706 while((n = n.previousSibling) && n.nodeType != 1);
4710 function children(d){
4711 var n = d.firstChild, ni = -1;
4713 var nx = n.nextSibling;
4714 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4724 function byClassName(c, a, v){
4728 var r = [], ri = -1, cn;
4729 for(var i = 0, ci; ci = c[i]; i++){
4730 if((' '+ci.className+' ').indexOf(v) != -1){
4737 function attrValue(n, attr){
4738 if(!n.tagName && typeof n.length != "undefined"){
4747 if(attr == "class" || attr == "className"){
4750 return n.getAttribute(attr) || n[attr];
4754 function getNodes(ns, mode, tagName){
4755 var result = [], ri = -1, cs;
4759 tagName = tagName || "*";
4760 if(typeof ns.getElementsByTagName != "undefined"){
4764 for(var i = 0, ni; ni = ns[i]; i++){
4765 cs = ni.getElementsByTagName(tagName);
4766 for(var j = 0, ci; ci = cs[j]; j++){
4770 }else if(mode == "/" || mode == ">"){
4771 var utag = tagName.toUpperCase();
4772 for(var i = 0, ni, cn; ni = ns[i]; i++){
4773 cn = ni.children || ni.childNodes;
4774 for(var j = 0, cj; cj = cn[j]; j++){
4775 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4780 }else if(mode == "+"){
4781 var utag = tagName.toUpperCase();
4782 for(var i = 0, n; n = ns[i]; i++){
4783 while((n = n.nextSibling) && n.nodeType != 1);
4784 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4788 }else if(mode == "~"){
4789 for(var i = 0, n; n = ns[i]; i++){
4790 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4799 function concat(a, b){
4803 for(var i = 0, l = b.length; i < l; i++){
4809 function byTag(cs, tagName){
4810 if(cs.tagName || cs == document){
4816 var r = [], ri = -1;
4817 tagName = tagName.toLowerCase();
4818 for(var i = 0, ci; ci = cs[i]; i++){
4819 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4826 function byId(cs, attr, id){
4827 if(cs.tagName || cs == document){
4833 var r = [], ri = -1;
4834 for(var i = 0,ci; ci = cs[i]; i++){
4835 if(ci && ci.id == id){
4843 function byAttribute(cs, attr, value, op, custom){
4844 var r = [], ri = -1, st = custom=="{";
4845 var f = Roo.DomQuery.operators[op];
4846 for(var i = 0, ci; ci = cs[i]; i++){
4849 a = Roo.DomQuery.getStyle(ci, attr);
4851 else if(attr == "class" || attr == "className"){
4853 }else if(attr == "for"){
4855 }else if(attr == "href"){
4856 a = ci.getAttribute("href", 2);
4858 a = ci.getAttribute(attr);
4860 if((f && f(a, value)) || (!f && a)){
4867 function byPseudo(cs, name, value){
4868 return Roo.DomQuery.pseudos[name](cs, value);
4871 // This is for IE MSXML which does not support expandos.
4872 // IE runs the same speed using setAttribute, however FF slows way down
4873 // and Safari completely fails so they need to continue to use expandos.
4874 var isIE = window.ActiveXObject ? true : false;
4876 // this eval is stop the compressor from
4877 // renaming the variable to something shorter
4879 /** eval:var:batch */
4884 function nodupIEXml(cs){
4886 cs[0].setAttribute("_nodup", d);
4888 for(var i = 1, len = cs.length; i < len; i++){
4890 if(!c.getAttribute("_nodup") != d){
4891 c.setAttribute("_nodup", d);
4895 for(var i = 0, len = cs.length; i < len; i++){
4896 cs[i].removeAttribute("_nodup");
4905 var len = cs.length, c, i, r = cs, cj, ri = -1;
4906 if(!len || typeof cs.nodeType != "undefined" || len == 1){
4909 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4910 return nodupIEXml(cs);
4914 for(i = 1; c = cs[i]; i++){
4919 for(var j = 0; j < i; j++){
4922 for(j = i+1; cj = cs[j]; j++){
4934 function quickDiffIEXml(c1, c2){
4936 for(var i = 0, len = c1.length; i < len; i++){
4937 c1[i].setAttribute("_qdiff", d);
4940 for(var i = 0, len = c2.length; i < len; i++){
4941 if(c2[i].getAttribute("_qdiff") != d){
4942 r[r.length] = c2[i];
4945 for(var i = 0, len = c1.length; i < len; i++){
4946 c1[i].removeAttribute("_qdiff");
4951 function quickDiff(c1, c2){
4952 var len1 = c1.length;
4956 if(isIE && c1[0].selectSingleNode){
4957 return quickDiffIEXml(c1, c2);
4960 for(var i = 0; i < len1; i++){
4964 for(var i = 0, len = c2.length; i < len; i++){
4965 if(c2[i]._qdiff != d){
4966 r[r.length] = c2[i];
4972 function quickId(ns, mode, root, id){
4974 var d = root.ownerDocument || root;
4975 return d.getElementById(id);
4977 ns = getNodes(ns, mode, "*");
4978 return byId(ns, null, id);
4982 getStyle : function(el, name){
4983 return Roo.fly(el).getStyle(name);
4986 * Compiles a selector/xpath query into a reusable function. The returned function
4987 * takes one parameter "root" (optional), which is the context node from where the query should start.
4988 * @param {String} selector The selector/xpath query
4989 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
4990 * @return {Function}
4992 compile : function(path, type){
4993 type = type || "select";
4995 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
4996 var q = path, mode, lq;
4997 var tk = Roo.DomQuery.matchers;
4998 var tklen = tk.length;
5001 // accept leading mode switch
5002 var lmode = q.match(modeRe);
5003 if(lmode && lmode[1]){
5004 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5005 q = q.replace(lmode[1], "");
5007 // strip leading slashes
5008 while(path.substr(0, 1)=="/"){
5009 path = path.substr(1);
5012 while(q && lq != q){
5014 var tm = q.match(tagTokenRe);
5015 if(type == "select"){
5018 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5020 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5022 q = q.replace(tm[0], "");
5023 }else if(q.substr(0, 1) != '@'){
5024 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5029 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5031 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5033 q = q.replace(tm[0], "");
5036 while(!(mm = q.match(modeRe))){
5037 var matched = false;
5038 for(var j = 0; j < tklen; j++){
5040 var m = q.match(t.re);
5042 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5045 q = q.replace(m[0], "");
5050 // prevent infinite loop on bad selector
5052 throw 'Error parsing selector, parsing failed at "' + q + '"';
5056 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5057 q = q.replace(mm[1], "");
5060 fn[fn.length] = "return nodup(n);\n}";
5063 * list of variables that need from compression as they are used by eval.
5073 * eval:var:byClassName
5075 * eval:var:byAttribute
5076 * eval:var:attrValue
5084 * Selects a group of elements.
5085 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5086 * @param {Node} root (optional) The start of the query (defaults to document).
5089 select : function(path, root, type){
5090 if(!root || root == document){
5093 if(typeof root == "string"){
5094 root = document.getElementById(root);
5096 var paths = path.split(",");
5098 for(var i = 0, len = paths.length; i < len; i++){
5099 var p = paths[i].replace(trimRe, "");
5101 cache[p] = Roo.DomQuery.compile(p);
5103 throw p + " is not a valid selector";
5106 var result = cache[p](root);
5107 if(result && result != document){
5108 results = results.concat(result);
5111 if(paths.length > 1){
5112 return nodup(results);
5118 * Selects a single element.
5119 * @param {String} selector The selector/xpath query
5120 * @param {Node} root (optional) The start of the query (defaults to document).
5123 selectNode : function(path, root){
5124 return Roo.DomQuery.select(path, root)[0];
5128 * Selects the value of a node, optionally replacing null with the defaultValue.
5129 * @param {String} selector The selector/xpath query
5130 * @param {Node} root (optional) The start of the query (defaults to document).
5131 * @param {String} defaultValue
5133 selectValue : function(path, root, defaultValue){
5134 path = path.replace(trimRe, "");
5135 if(!valueCache[path]){
5136 valueCache[path] = Roo.DomQuery.compile(path, "select");
5138 var n = valueCache[path](root);
5139 n = n[0] ? n[0] : n;
5140 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5141 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5145 * Selects the value of a node, parsing integers and floats.
5146 * @param {String} selector The selector/xpath query
5147 * @param {Node} root (optional) The start of the query (defaults to document).
5148 * @param {Number} defaultValue
5151 selectNumber : function(path, root, defaultValue){
5152 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5153 return parseFloat(v);
5157 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5158 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5159 * @param {String} selector The simple selector to test
5162 is : function(el, ss){
5163 if(typeof el == "string"){
5164 el = document.getElementById(el);
5166 var isArray = (el instanceof Array);
5167 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5168 return isArray ? (result.length == el.length) : (result.length > 0);
5172 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5173 * @param {Array} el An array of elements to filter
5174 * @param {String} selector The simple selector to test
5175 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5176 * the selector instead of the ones that match
5179 filter : function(els, ss, nonMatches){
5180 ss = ss.replace(trimRe, "");
5181 if(!simpleCache[ss]){
5182 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5184 var result = simpleCache[ss](els);
5185 return nonMatches ? quickDiff(result, els) : result;
5189 * Collection of matching regular expressions and code snippets.
5193 select: 'n = byClassName(n, null, " {1} ");'
5195 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5196 select: 'n = byPseudo(n, "{1}", "{2}");'
5198 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5199 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5202 select: 'n = byId(n, null, "{1}");'
5205 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5210 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5211 * 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, > <.
5214 "=" : function(a, v){
5217 "!=" : function(a, v){
5220 "^=" : function(a, v){
5221 return a && a.substr(0, v.length) == v;
5223 "$=" : function(a, v){
5224 return a && a.substr(a.length-v.length) == v;
5226 "*=" : function(a, v){
5227 return a && a.indexOf(v) !== -1;
5229 "%=" : function(a, v){
5230 return (a % v) == 0;
5232 "|=" : function(a, v){
5233 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5235 "~=" : function(a, v){
5236 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5241 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5242 * and the argument (if any) supplied in the selector.
5245 "first-child" : function(c){
5246 var r = [], ri = -1, n;
5247 for(var i = 0, ci; ci = n = c[i]; i++){
5248 while((n = n.previousSibling) && n.nodeType != 1);
5256 "last-child" : function(c){
5257 var r = [], ri = -1, n;
5258 for(var i = 0, ci; ci = n = c[i]; i++){
5259 while((n = n.nextSibling) && n.nodeType != 1);
5267 "nth-child" : function(c, a) {
5268 var r = [], ri = -1;
5269 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5270 var f = (m[1] || 1) - 0, l = m[2] - 0;
5271 for(var i = 0, n; n = c[i]; i++){
5272 var pn = n.parentNode;
5273 if (batch != pn._batch) {
5275 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5276 if(cn.nodeType == 1){
5283 if (l == 0 || n.nodeIndex == l){
5286 } else if ((n.nodeIndex + l) % f == 0){
5294 "only-child" : function(c){
5295 var r = [], ri = -1;;
5296 for(var i = 0, ci; ci = c[i]; i++){
5297 if(!prev(ci) && !next(ci)){
5304 "empty" : function(c){
5305 var r = [], ri = -1;
5306 for(var i = 0, ci; ci = c[i]; i++){
5307 var cns = ci.childNodes, j = 0, cn, empty = true;
5310 if(cn.nodeType == 1 || cn.nodeType == 3){
5322 "contains" : function(c, v){
5323 var r = [], ri = -1;
5324 for(var i = 0, ci; ci = c[i]; i++){
5325 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5332 "nodeValue" : function(c, v){
5333 var r = [], ri = -1;
5334 for(var i = 0, ci; ci = c[i]; i++){
5335 if(ci.firstChild && ci.firstChild.nodeValue == v){
5342 "checked" : function(c){
5343 var r = [], ri = -1;
5344 for(var i = 0, ci; ci = c[i]; i++){
5345 if(ci.checked == true){
5352 "not" : function(c, ss){
5353 return Roo.DomQuery.filter(c, ss, true);
5356 "odd" : function(c){
5357 return this["nth-child"](c, "odd");
5360 "even" : function(c){
5361 return this["nth-child"](c, "even");
5364 "nth" : function(c, a){
5365 return c[a-1] || [];
5368 "first" : function(c){
5372 "last" : function(c){
5373 return c[c.length-1] || [];
5376 "has" : function(c, ss){
5377 var s = Roo.DomQuery.select;
5378 var r = [], ri = -1;
5379 for(var i = 0, ci; ci = c[i]; i++){
5380 if(s(ss, ci).length > 0){
5387 "next" : function(c, ss){
5388 var is = Roo.DomQuery.is;
5389 var r = [], ri = -1;
5390 for(var i = 0, ci; ci = c[i]; i++){
5399 "prev" : function(c, ss){
5400 var is = Roo.DomQuery.is;
5401 var r = [], ri = -1;
5402 for(var i = 0, ci; ci = c[i]; i++){
5415 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5416 * @param {String} path The selector/xpath query
5417 * @param {Node} root (optional) The start of the query (defaults to document).
5422 Roo.query = Roo.DomQuery.select;
5425 * Ext JS Library 1.1.1
5426 * Copyright(c) 2006-2007, Ext JS, LLC.
5428 * Originally Released Under LGPL - original licence link has changed is not relivant.
5431 * <script type="text/javascript">
5435 * @class Roo.util.Observable
5436 * Base class that provides a common interface for publishing events. Subclasses are expected to
5437 * to have a property "events" with all the events defined.<br>
5440 Employee = function(name){
5447 Roo.extend(Employee, Roo.util.Observable);
5449 * @param {Object} config properties to use (incuding events / listeners)
5452 Roo.util.Observable = function(cfg){
5455 this.addEvents(cfg.events || {});
5457 delete cfg.events; // make sure
5460 Roo.apply(this, cfg);
5463 this.on(this.listeners);
5464 delete this.listeners;
5467 Roo.util.Observable.prototype = {
5469 * @cfg {Object} listeners list of events and functions to call for this object,
5473 'click' : function(e) {
5483 * Fires the specified event with the passed parameters (minus the event name).
5484 * @param {String} eventName
5485 * @param {Object...} args Variable number of parameters are passed to handlers
5486 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5488 fireEvent : function(){
5489 var ce = this.events[arguments[0].toLowerCase()];
5490 if(typeof ce == "object"){
5491 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5498 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5501 * Appends an event handler to this component
5502 * @param {String} eventName The type of event to listen for
5503 * @param {Function} handler The method the event invokes
5504 * @param {Object} scope (optional) The scope in which to execute the handler
5505 * function. The handler function's "this" context.
5506 * @param {Object} options (optional) An object containing handler configuration
5507 * properties. This may contain any of the following properties:<ul>
5508 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5509 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5510 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5511 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5512 * by the specified number of milliseconds. If the event fires again within that time, the original
5513 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5516 * <b>Combining Options</b><br>
5517 * Using the options argument, it is possible to combine different types of listeners:<br>
5519 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5521 el.on('click', this.onClick, this, {
5528 * <b>Attaching multiple handlers in 1 call</b><br>
5529 * The method also allows for a single argument to be passed which is a config object containing properties
5530 * which specify multiple handlers.
5539 fn: this.onMouseOver,
5543 fn: this.onMouseOut,
5549 * Or a shorthand syntax which passes the same scope object to all handlers:
5552 'click': this.onClick,
5553 'mouseover': this.onMouseOver,
5554 'mouseout': this.onMouseOut,
5559 addListener : function(eventName, fn, scope, o){
5560 if(typeof eventName == "object"){
5563 if(this.filterOptRe.test(e)){
5566 if(typeof o[e] == "function"){
5568 this.addListener(e, o[e], o.scope, o);
5570 // individual options
5571 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5576 o = (!o || typeof o == "boolean") ? {} : o;
5577 eventName = eventName.toLowerCase();
5578 var ce = this.events[eventName] || true;
5579 if(typeof ce == "boolean"){
5580 ce = new Roo.util.Event(this, eventName);
5581 this.events[eventName] = ce;
5583 ce.addListener(fn, scope, o);
5587 * Removes a listener
5588 * @param {String} eventName The type of event to listen for
5589 * @param {Function} handler The handler to remove
5590 * @param {Object} scope (optional) The scope (this object) for the handler
5592 removeListener : function(eventName, fn, scope){
5593 var ce = this.events[eventName.toLowerCase()];
5594 if(typeof ce == "object"){
5595 ce.removeListener(fn, scope);
5600 * Removes all listeners for this object
5602 purgeListeners : function(){
5603 for(var evt in this.events){
5604 if(typeof this.events[evt] == "object"){
5605 this.events[evt].clearListeners();
5610 relayEvents : function(o, events){
5611 var createHandler = function(ename){
5613 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5616 for(var i = 0, len = events.length; i < len; i++){
5617 var ename = events[i];
5618 if(!this.events[ename]){ this.events[ename] = true; };
5619 o.on(ename, createHandler(ename), this);
5624 * Used to define events on this Observable
5625 * @param {Object} object The object with the events defined
5627 addEvents : function(o){
5631 Roo.applyIf(this.events, o);
5635 * Checks to see if this object has any listeners for a specified event
5636 * @param {String} eventName The name of the event to check for
5637 * @return {Boolean} True if the event is being listened for, else false
5639 hasListener : function(eventName){
5640 var e = this.events[eventName];
5641 return typeof e == "object" && e.listeners.length > 0;
5645 * Appends an event handler to this element (shorthand for addListener)
5646 * @param {String} eventName The type of event to listen for
5647 * @param {Function} handler The method the event invokes
5648 * @param {Object} scope (optional) The scope in which to execute the handler
5649 * function. The handler function's "this" context.
5650 * @param {Object} options (optional)
5653 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5655 * Removes a listener (shorthand for removeListener)
5656 * @param {String} eventName The type of event to listen for
5657 * @param {Function} handler The handler to remove
5658 * @param {Object} scope (optional) The scope (this object) for the handler
5661 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5664 * Starts capture on the specified Observable. All events will be passed
5665 * to the supplied function with the event name + standard signature of the event
5666 * <b>before</b> the event is fired. If the supplied function returns false,
5667 * the event will not fire.
5668 * @param {Observable} o The Observable to capture
5669 * @param {Function} fn The function to call
5670 * @param {Object} scope (optional) The scope (this object) for the fn
5673 Roo.util.Observable.capture = function(o, fn, scope){
5674 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5678 * Removes <b>all</b> added captures from the Observable.
5679 * @param {Observable} o The Observable to release
5682 Roo.util.Observable.releaseCapture = function(o){
5683 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5688 var createBuffered = function(h, o, scope){
5689 var task = new Roo.util.DelayedTask();
5691 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5695 var createSingle = function(h, e, fn, scope){
5697 e.removeListener(fn, scope);
5698 return h.apply(scope, arguments);
5702 var createDelayed = function(h, o, scope){
5704 var args = Array.prototype.slice.call(arguments, 0);
5705 setTimeout(function(){
5706 h.apply(scope, args);
5711 Roo.util.Event = function(obj, name){
5714 this.listeners = [];
5717 Roo.util.Event.prototype = {
5718 addListener : function(fn, scope, options){
5719 var o = options || {};
5720 scope = scope || this.obj;
5721 if(!this.isListening(fn, scope)){
5722 var l = {fn: fn, scope: scope, options: o};
5725 h = createDelayed(h, o, scope);
5728 h = createSingle(h, this, fn, scope);
5731 h = createBuffered(h, o, scope);
5734 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5735 this.listeners.push(l);
5737 this.listeners = this.listeners.slice(0);
5738 this.listeners.push(l);
5743 findListener : function(fn, scope){
5744 scope = scope || this.obj;
5745 var ls = this.listeners;
5746 for(var i = 0, len = ls.length; i < len; i++){
5748 if(l.fn == fn && l.scope == scope){
5755 isListening : function(fn, scope){
5756 return this.findListener(fn, scope) != -1;
5759 removeListener : function(fn, scope){
5761 if((index = this.findListener(fn, scope)) != -1){
5763 this.listeners.splice(index, 1);
5765 this.listeners = this.listeners.slice(0);
5766 this.listeners.splice(index, 1);
5773 clearListeners : function(){
5774 this.listeners = [];
5778 var ls = this.listeners, scope, len = ls.length;
5781 var args = Array.prototype.slice.call(arguments, 0);
5782 for(var i = 0; i < len; i++){
5784 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5785 this.firing = false;
5789 this.firing = false;
5796 * Ext JS Library 1.1.1
5797 * Copyright(c) 2006-2007, Ext JS, LLC.
5799 * Originally Released Under LGPL - original licence link has changed is not relivant.
5802 * <script type="text/javascript">
5806 * @class Roo.EventManager
5807 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5808 * several useful events directly.
5809 * See {@link Roo.EventObject} for more details on normalized event objects.
5812 Roo.EventManager = function(){
5813 var docReadyEvent, docReadyProcId, docReadyState = false;
5814 var resizeEvent, resizeTask, textEvent, textSize;
5815 var E = Roo.lib.Event;
5816 var D = Roo.lib.Dom;
5819 var fireDocReady = function(){
5821 docReadyState = true;
5824 clearInterval(docReadyProcId);
5826 if(Roo.isGecko || Roo.isOpera) {
5827 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5830 var defer = document.getElementById("ie-deferred-loader");
5832 defer.onreadystatechange = null;
5833 defer.parentNode.removeChild(defer);
5837 docReadyEvent.fire();
5838 docReadyEvent.clearListeners();
5843 var initDocReady = function(){
5844 docReadyEvent = new Roo.util.Event();
5845 if(Roo.isGecko || Roo.isOpera) {
5846 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5848 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5849 var defer = document.getElementById("ie-deferred-loader");
5850 defer.onreadystatechange = function(){
5851 if(this.readyState == "complete"){
5855 }else if(Roo.isSafari){
5856 docReadyProcId = setInterval(function(){
5857 var rs = document.readyState;
5858 if(rs == "complete") {
5863 // no matter what, make sure it fires on load
5864 E.on(window, "load", fireDocReady);
5867 var createBuffered = function(h, o){
5868 var task = new Roo.util.DelayedTask(h);
5870 // create new event object impl so new events don't wipe out properties
5871 e = new Roo.EventObjectImpl(e);
5872 task.delay(o.buffer, h, null, [e]);
5876 var createSingle = function(h, el, ename, fn){
5878 Roo.EventManager.removeListener(el, ename, fn);
5883 var createDelayed = function(h, o){
5885 // create new event object impl so new events don't wipe out properties
5886 e = new Roo.EventObjectImpl(e);
5887 setTimeout(function(){
5893 var listen = function(element, ename, opt, fn, scope){
5894 var o = (!opt || typeof opt == "boolean") ? {} : opt;
5895 fn = fn || o.fn; scope = scope || o.scope;
5896 var el = Roo.getDom(element);
5898 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5900 var h = function(e){
5901 e = Roo.EventObject.setEvent(e);
5904 t = e.getTarget(o.delegate, el);
5911 if(o.stopEvent === true){
5914 if(o.preventDefault === true){
5917 if(o.stopPropagation === true){
5918 e.stopPropagation();
5921 if(o.normalized === false){
5925 fn.call(scope || el, e, t, o);
5928 h = createDelayed(h, o);
5931 h = createSingle(h, el, ename, fn);
5934 h = createBuffered(h, o);
5936 fn._handlers = fn._handlers || [];
5937 fn._handlers.push([Roo.id(el), ename, h]);
5940 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5941 el.addEventListener("DOMMouseScroll", h, false);
5942 E.on(window, 'unload', function(){
5943 el.removeEventListener("DOMMouseScroll", h, false);
5946 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5947 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5952 var stopListening = function(el, ename, fn){
5953 var id = Roo.id(el), hds = fn._handlers, hd = fn;
5955 for(var i = 0, len = hds.length; i < len; i++){
5957 if(h[0] == id && h[1] == ename){
5964 E.un(el, ename, hd);
5965 el = Roo.getDom(el);
5966 if(ename == "mousewheel" && el.addEventListener){
5967 el.removeEventListener("DOMMouseScroll", hd, false);
5969 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5970 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5974 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
5981 * @scope Roo.EventManager
5986 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
5987 * object with a Roo.EventObject
5988 * @param {Function} fn The method the event invokes
5989 * @param {Object} scope An object that becomes the scope of the handler
5990 * @param {boolean} override If true, the obj passed in becomes
5991 * the execution scope of the listener
5992 * @return {Function} The wrapped function
5995 wrap : function(fn, scope, override){
5997 Roo.EventObject.setEvent(e);
5998 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6003 * Appends an event handler to an element (shorthand for addListener)
6004 * @param {String/HTMLElement} element The html element or id to assign the
6005 * @param {String} eventName The type of event to listen for
6006 * @param {Function} handler The method the event invokes
6007 * @param {Object} scope (optional) The scope in which to execute the handler
6008 * function. The handler function's "this" context.
6009 * @param {Object} options (optional) An object containing handler configuration
6010 * properties. This may contain any of the following properties:<ul>
6011 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6012 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6013 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6014 * <li>preventDefault {Boolean} True to prevent the default action</li>
6015 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6016 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6017 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6018 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6019 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6020 * by the specified number of milliseconds. If the event fires again within that time, the original
6021 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6024 * <b>Combining Options</b><br>
6025 * Using the options argument, it is possible to combine different types of listeners:<br>
6027 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6029 el.on('click', this.onClick, this, {
6036 * <b>Attaching multiple handlers in 1 call</b><br>
6037 * The method also allows for a single argument to be passed which is a config object containing properties
6038 * which specify multiple handlers.
6048 fn: this.onMouseOver
6057 * Or a shorthand syntax:<br>
6060 'click' : this.onClick,
6061 'mouseover' : this.onMouseOver,
6062 'mouseout' : this.onMouseOut
6066 addListener : function(element, eventName, fn, scope, options){
6067 if(typeof eventName == "object"){
6073 if(typeof o[e] == "function"){
6075 listen(element, e, o, o[e], o.scope);
6077 // individual options
6078 listen(element, e, o[e]);
6083 return listen(element, eventName, options, fn, scope);
6087 * Removes an event handler
6089 * @param {String/HTMLElement} element The id or html element to remove the
6091 * @param {String} eventName The type of event
6092 * @param {Function} fn
6093 * @return {Boolean} True if a listener was actually removed
6095 removeListener : function(element, eventName, fn){
6096 return stopListening(element, eventName, fn);
6100 * Fires when the document is ready (before onload and before images are loaded). Can be
6101 * accessed shorthanded Roo.onReady().
6102 * @param {Function} fn The method the event invokes
6103 * @param {Object} scope An object that becomes the scope of the handler
6104 * @param {boolean} options
6106 onDocumentReady : function(fn, scope, options){
6107 if(docReadyState){ // if it already fired
6108 docReadyEvent.addListener(fn, scope, options);
6109 docReadyEvent.fire();
6110 docReadyEvent.clearListeners();
6116 docReadyEvent.addListener(fn, scope, options);
6120 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6121 * @param {Function} fn The method the event invokes
6122 * @param {Object} scope An object that becomes the scope of the handler
6123 * @param {boolean} options
6125 onWindowResize : function(fn, scope, options){
6127 resizeEvent = new Roo.util.Event();
6128 resizeTask = new Roo.util.DelayedTask(function(){
6129 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6131 E.on(window, "resize", function(){
6133 resizeTask.delay(50);
6135 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6139 resizeEvent.addListener(fn, scope, options);
6143 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6144 * @param {Function} fn The method the event invokes
6145 * @param {Object} scope An object that becomes the scope of the handler
6146 * @param {boolean} options
6148 onTextResize : function(fn, scope, options){
6150 textEvent = new Roo.util.Event();
6151 var textEl = new Roo.Element(document.createElement('div'));
6152 textEl.dom.className = 'x-text-resize';
6153 textEl.dom.innerHTML = 'X';
6154 textEl.appendTo(document.body);
6155 textSize = textEl.dom.offsetHeight;
6156 setInterval(function(){
6157 if(textEl.dom.offsetHeight != textSize){
6158 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6160 }, this.textResizeInterval);
6162 textEvent.addListener(fn, scope, options);
6166 * Removes the passed window resize listener.
6167 * @param {Function} fn The method the event invokes
6168 * @param {Object} scope The scope of handler
6170 removeResizeListener : function(fn, scope){
6172 resizeEvent.removeListener(fn, scope);
6177 fireResize : function(){
6179 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6183 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6187 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6189 textResizeInterval : 50
6194 * @scopeAlias pub=Roo.EventManager
6198 * Appends an event handler to an element (shorthand for addListener)
6199 * @param {String/HTMLElement} element The html element or id to assign the
6200 * @param {String} eventName The type of event to listen for
6201 * @param {Function} handler The method the event invokes
6202 * @param {Object} scope (optional) The scope in which to execute the handler
6203 * function. The handler function's "this" context.
6204 * @param {Object} options (optional) An object containing handler configuration
6205 * properties. This may contain any of the following properties:<ul>
6206 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6207 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6208 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6209 * <li>preventDefault {Boolean} True to prevent the default action</li>
6210 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6211 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6212 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6213 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6214 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6215 * by the specified number of milliseconds. If the event fires again within that time, the original
6216 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6219 * <b>Combining Options</b><br>
6220 * Using the options argument, it is possible to combine different types of listeners:<br>
6222 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6224 el.on('click', this.onClick, this, {
6231 * <b>Attaching multiple handlers in 1 call</b><br>
6232 * The method also allows for a single argument to be passed which is a config object containing properties
6233 * which specify multiple handlers.
6243 fn: this.onMouseOver
6252 * Or a shorthand syntax:<br>
6255 'click' : this.onClick,
6256 'mouseover' : this.onMouseOver,
6257 'mouseout' : this.onMouseOut
6261 pub.on = pub.addListener;
6262 pub.un = pub.removeListener;
6264 pub.stoppedMouseDownEvent = new Roo.util.Event();
6268 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6269 * @param {Function} fn The method the event invokes
6270 * @param {Object} scope An object that becomes the scope of the handler
6271 * @param {boolean} override If true, the obj passed in becomes
6272 * the execution scope of the listener
6276 Roo.onReady = Roo.EventManager.onDocumentReady;
6278 Roo.onReady(function(){
6279 var bd = Roo.get(document.body);
6284 : Roo.isGecko ? "roo-gecko"
6285 : Roo.isOpera ? "roo-opera"
6286 : Roo.isSafari ? "roo-safari" : ""];
6289 cls.push("roo-mac");
6292 cls.push("roo-linux");
6294 if(Roo.isBorderBox){
6295 cls.push('roo-border-box');
6297 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6298 var p = bd.dom.parentNode;
6300 p.className += ' roo-strict';
6303 bd.addClass(cls.join(' '));
6307 * @class Roo.EventObject
6308 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6309 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6312 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6314 var target = e.getTarget();
6317 var myDiv = Roo.get("myDiv");
6318 myDiv.on("click", handleClick);
6320 Roo.EventManager.on("myDiv", 'click', handleClick);
6321 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6325 Roo.EventObject = function(){
6327 var E = Roo.lib.Event;
6329 // safari keypress events for special keys return bad keycodes
6332 63235 : 39, // right
6335 63276 : 33, // page up
6336 63277 : 34, // page down
6337 63272 : 46, // delete
6342 // normalize button clicks
6343 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6344 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6346 Roo.EventObjectImpl = function(e){
6348 this.setEvent(e.browserEvent || e);
6351 Roo.EventObjectImpl.prototype = {
6353 * Used to fix doc tools.
6354 * @scope Roo.EventObject.prototype
6360 /** The normal browser event */
6361 browserEvent : null,
6362 /** The button pressed in a mouse event */
6364 /** True if the shift key was down during the event */
6366 /** True if the control key was down during the event */
6368 /** True if the alt key was down during the event */
6427 setEvent : function(e){
6428 if(e == this || (e && e.browserEvent)){ // already wrapped
6431 this.browserEvent = e;
6433 // normalize buttons
6434 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6435 if(e.type == 'click' && this.button == -1){
6439 this.shiftKey = e.shiftKey;
6440 // mac metaKey behaves like ctrlKey
6441 this.ctrlKey = e.ctrlKey || e.metaKey;
6442 this.altKey = e.altKey;
6443 // in getKey these will be normalized for the mac
6444 this.keyCode = e.keyCode;
6445 // keyup warnings on firefox.
6446 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6447 // cache the target for the delayed and or buffered events
6448 this.target = E.getTarget(e);
6450 this.xy = E.getXY(e);
6453 this.shiftKey = false;
6454 this.ctrlKey = false;
6455 this.altKey = false;
6465 * Stop the event (preventDefault and stopPropagation)
6467 stopEvent : function(){
6468 if(this.browserEvent){
6469 if(this.browserEvent.type == 'mousedown'){
6470 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6472 E.stopEvent(this.browserEvent);
6477 * Prevents the browsers default handling of the event.
6479 preventDefault : function(){
6480 if(this.browserEvent){
6481 E.preventDefault(this.browserEvent);
6486 isNavKeyPress : function(){
6487 var k = this.keyCode;
6488 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6489 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6492 isSpecialKey : function(){
6493 var k = this.keyCode;
6494 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6495 (k == 16) || (k == 17) ||
6496 (k >= 18 && k <= 20) ||
6497 (k >= 33 && k <= 35) ||
6498 (k >= 36 && k <= 39) ||
6499 (k >= 44 && k <= 45);
6502 * Cancels bubbling of the event.
6504 stopPropagation : function(){
6505 if(this.browserEvent){
6506 if(this.type == 'mousedown'){
6507 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6509 E.stopPropagation(this.browserEvent);
6514 * Gets the key code for the event.
6517 getCharCode : function(){
6518 return this.charCode || this.keyCode;
6522 * Returns a normalized keyCode for the event.
6523 * @return {Number} The key code
6525 getKey : function(){
6526 var k = this.keyCode || this.charCode;
6527 return Roo.isSafari ? (safariKeys[k] || k) : k;
6531 * Gets the x coordinate of the event.
6534 getPageX : function(){
6539 * Gets the y coordinate of the event.
6542 getPageY : function(){
6547 * Gets the time of the event.
6550 getTime : function(){
6551 if(this.browserEvent){
6552 return E.getTime(this.browserEvent);
6558 * Gets the page coordinates of the event.
6559 * @return {Array} The xy values like [x, y]
6566 * Gets the target for the event.
6567 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6568 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6569 search as a number or element (defaults to 10 || document.body)
6570 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6571 * @return {HTMLelement}
6573 getTarget : function(selector, maxDepth, returnEl){
6574 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6577 * Gets the related target.
6578 * @return {HTMLElement}
6580 getRelatedTarget : function(){
6581 if(this.browserEvent){
6582 return E.getRelatedTarget(this.browserEvent);
6588 * Normalizes mouse wheel delta across browsers
6589 * @return {Number} The delta
6591 getWheelDelta : function(){
6592 var e = this.browserEvent;
6594 if(e.wheelDelta){ /* IE/Opera. */
6595 delta = e.wheelDelta/120;
6596 }else if(e.detail){ /* Mozilla case. */
6597 delta = -e.detail/3;
6603 * Returns true if the control, meta, shift or alt key was pressed during this event.
6606 hasModifier : function(){
6607 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6611 * Returns true if the target of this event equals el or is a child of el
6612 * @param {String/HTMLElement/Element} el
6613 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6616 within : function(el, related){
6617 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6618 return t && Roo.fly(el).contains(t);
6621 getPoint : function(){
6622 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6626 return new Roo.EventObjectImpl();
6631 * Ext JS Library 1.1.1
6632 * Copyright(c) 2006-2007, Ext JS, LLC.
6634 * Originally Released Under LGPL - original licence link has changed is not relivant.
6637 * <script type="text/javascript">
6641 // was in Composite Element!??!?!
6644 var D = Roo.lib.Dom;
6645 var E = Roo.lib.Event;
6646 var A = Roo.lib.Anim;
6648 // local style camelizing for speed
6650 var camelRe = /(-[a-z])/gi;
6651 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6652 var view = document.defaultView;
6655 * @class Roo.Element
6656 * Represents an Element in the DOM.<br><br>
6659 var el = Roo.get("my-div");
6662 var el = getEl("my-div");
6664 // or with a DOM element
6665 var el = Roo.get(myDivElement);
6667 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6668 * each call instead of constructing a new one.<br><br>
6669 * <b>Animations</b><br />
6670 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6671 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6673 Option Default Description
6674 --------- -------- ---------------------------------------------
6675 duration .35 The duration of the animation in seconds
6676 easing easeOut The YUI easing method
6677 callback none A function to execute when the anim completes
6678 scope this The scope (this) of the callback function
6680 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6681 * manipulate the animation. Here's an example:
6683 var el = Roo.get("my-div");
6688 // default animation
6689 el.setWidth(100, true);
6691 // animation with some options set
6698 // using the "anim" property to get the Anim object
6704 el.setWidth(100, opt);
6706 if(opt.anim.isAnimated()){
6710 * <b> Composite (Collections of) Elements</b><br />
6711 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6712 * @constructor Create a new Element directly.
6713 * @param {String/HTMLElement} element
6714 * @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).
6716 Roo.Element = function(element, forceNew){
6717 var dom = typeof element == "string" ?
6718 document.getElementById(element) : element;
6719 if(!dom){ // invalid id/element
6723 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6724 return Roo.Element.cache[id];
6734 * The DOM element ID
6737 this.id = id || Roo.id(dom);
6740 var El = Roo.Element;
6744 * The element's default display mode (defaults to "")
6747 originalDisplay : "",
6751 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6756 * Sets the element's visibility mode. When setVisible() is called it
6757 * will use this to determine whether to set the visibility or the display property.
6758 * @param visMode Element.VISIBILITY or Element.DISPLAY
6759 * @return {Roo.Element} this
6761 setVisibilityMode : function(visMode){
6762 this.visibilityMode = visMode;
6766 * Convenience method for setVisibilityMode(Element.DISPLAY)
6767 * @param {String} display (optional) What to set display to when visible
6768 * @return {Roo.Element} this
6770 enableDisplayMode : function(display){
6771 this.setVisibilityMode(El.DISPLAY);
6772 if(typeof display != "undefined") this.originalDisplay = display;
6777 * 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)
6778 * @param {String} selector The simple selector to test
6779 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6780 search as a number or element (defaults to 10 || document.body)
6781 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6782 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6784 findParent : function(simpleSelector, maxDepth, returnEl){
6785 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6786 maxDepth = maxDepth || 50;
6787 if(typeof maxDepth != "number"){
6788 stopEl = Roo.getDom(maxDepth);
6791 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6792 if(dq.is(p, simpleSelector)){
6793 return returnEl ? Roo.get(p) : p;
6803 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6804 * @param {String} selector The simple selector to test
6805 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6806 search as a number or element (defaults to 10 || document.body)
6807 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6808 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6810 findParentNode : function(simpleSelector, maxDepth, returnEl){
6811 var p = Roo.fly(this.dom.parentNode, '_internal');
6812 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6816 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6817 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6818 * @param {String} selector The simple selector to test
6819 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6820 search as a number or element (defaults to 10 || document.body)
6821 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6823 up : function(simpleSelector, maxDepth){
6824 return this.findParentNode(simpleSelector, maxDepth, true);
6830 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6831 * @param {String} selector The simple selector to test
6832 * @return {Boolean} True if this element matches the selector, else false
6834 is : function(simpleSelector){
6835 return Roo.DomQuery.is(this.dom, simpleSelector);
6839 * Perform animation on this element.
6840 * @param {Object} args The YUI animation control args
6841 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6842 * @param {Function} onComplete (optional) Function to call when animation completes
6843 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6844 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6845 * @return {Roo.Element} this
6847 animate : function(args, duration, onComplete, easing, animType){
6848 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6853 * @private Internal animation call
6855 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6856 animType = animType || 'run';
6858 var anim = Roo.lib.Anim[animType](
6860 (opt.duration || defaultDur) || .35,
6861 (opt.easing || defaultEase) || 'easeOut',
6863 Roo.callback(cb, this);
6864 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6872 // private legacy anim prep
6873 preanim : function(a, i){
6874 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6878 * Removes worthless text nodes
6879 * @param {Boolean} forceReclean (optional) By default the element
6880 * keeps track if it has been cleaned already so
6881 * you can call this over and over. However, if you update the element and
6882 * need to force a reclean, you can pass true.
6884 clean : function(forceReclean){
6885 if(this.isCleaned && forceReclean !== true){
6889 var d = this.dom, n = d.firstChild, ni = -1;
6891 var nx = n.nextSibling;
6892 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6899 this.isCleaned = true;
6904 calcOffsetsTo : function(el){
6907 var restorePos = false;
6908 if(el.getStyle('position') == 'static'){
6909 el.position('relative');
6914 while(op && op != d && op.tagName != 'HTML'){
6917 op = op.offsetParent;
6920 el.position('static');
6926 * Scrolls this element into view within the passed container.
6927 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6928 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6929 * @return {Roo.Element} this
6931 scrollIntoView : function(container, hscroll){
6932 var c = Roo.getDom(container) || document.body;
6935 var o = this.calcOffsetsTo(c),
6938 b = t+el.offsetHeight,
6939 r = l+el.offsetWidth;
6941 var ch = c.clientHeight;
6942 var ct = parseInt(c.scrollTop, 10);
6943 var cl = parseInt(c.scrollLeft, 10);
6945 var cr = cl + c.clientWidth;
6953 if(hscroll !== false){
6957 c.scrollLeft = r-c.clientWidth;
6964 scrollChildIntoView : function(child, hscroll){
6965 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6969 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6970 * the new height may not be available immediately.
6971 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6972 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6973 * @param {Function} onComplete (optional) Function to call when animation completes
6974 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
6975 * @return {Roo.Element} this
6977 autoHeight : function(animate, duration, onComplete, easing){
6978 var oldHeight = this.getHeight();
6980 this.setHeight(1); // force clipping
6981 setTimeout(function(){
6982 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
6984 this.setHeight(height);
6986 if(typeof onComplete == "function"){
6990 this.setHeight(oldHeight); // restore original height
6991 this.setHeight(height, animate, duration, function(){
6993 if(typeof onComplete == "function") onComplete();
6994 }.createDelegate(this), easing);
6996 }.createDelegate(this), 0);
7001 * Returns true if this element is an ancestor of the passed element
7002 * @param {HTMLElement/String} el The element to check
7003 * @return {Boolean} True if this element is an ancestor of el, else false
7005 contains : function(el){
7006 if(!el){return false;}
7007 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7011 * Checks whether the element is currently visible using both visibility and display properties.
7012 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7013 * @return {Boolean} True if the element is currently visible, else false
7015 isVisible : function(deep) {
7016 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7017 if(deep !== true || !vis){
7020 var p = this.dom.parentNode;
7021 while(p && p.tagName.toLowerCase() != "body"){
7022 if(!Roo.fly(p, '_isVisible').isVisible()){
7031 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7032 * @param {String} selector The CSS selector
7033 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7034 * @return {CompositeElement/CompositeElementLite} The composite element
7036 select : function(selector, unique){
7037 return El.select(selector, unique, this.dom);
7041 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7042 * @param {String} selector The CSS selector
7043 * @return {Array} An array of the matched nodes
7045 query : function(selector, unique){
7046 return Roo.DomQuery.select(selector, this.dom);
7050 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7051 * @param {String} selector The CSS selector
7052 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7053 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7055 child : function(selector, returnDom){
7056 var n = Roo.DomQuery.selectNode(selector, this.dom);
7057 return returnDom ? n : Roo.get(n);
7061 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7062 * @param {String} selector The CSS selector
7063 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7064 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7066 down : function(selector, returnDom){
7067 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7068 return returnDom ? n : Roo.get(n);
7072 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7073 * @param {String} group The group the DD object is member of
7074 * @param {Object} config The DD config object
7075 * @param {Object} overrides An object containing methods to override/implement on the DD object
7076 * @return {Roo.dd.DD} The DD object
7078 initDD : function(group, config, overrides){
7079 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7080 return Roo.apply(dd, overrides);
7084 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7085 * @param {String} group The group the DDProxy object is member of
7086 * @param {Object} config The DDProxy config object
7087 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7088 * @return {Roo.dd.DDProxy} The DDProxy object
7090 initDDProxy : function(group, config, overrides){
7091 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7092 return Roo.apply(dd, overrides);
7096 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7097 * @param {String} group The group the DDTarget object is member of
7098 * @param {Object} config The DDTarget config object
7099 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7100 * @return {Roo.dd.DDTarget} The DDTarget object
7102 initDDTarget : function(group, config, overrides){
7103 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7104 return Roo.apply(dd, overrides);
7108 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7109 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7110 * @param {Boolean} visible Whether the element is visible
7111 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7112 * @return {Roo.Element} this
7114 setVisible : function(visible, animate){
7116 if(this.visibilityMode == El.DISPLAY){
7117 this.setDisplayed(visible);
7120 this.dom.style.visibility = visible ? "visible" : "hidden";
7123 // closure for composites
7125 var visMode = this.visibilityMode;
7127 this.setOpacity(.01);
7128 this.setVisible(true);
7130 this.anim({opacity: { to: (visible?1:0) }},
7131 this.preanim(arguments, 1),
7132 null, .35, 'easeIn', function(){
7134 if(visMode == El.DISPLAY){
7135 dom.style.display = "none";
7137 dom.style.visibility = "hidden";
7139 Roo.get(dom).setOpacity(1);
7147 * Returns true if display is not "none"
7150 isDisplayed : function() {
7151 return this.getStyle("display") != "none";
7155 * Toggles the element's visibility or display, depending on visibility mode.
7156 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7157 * @return {Roo.Element} this
7159 toggle : function(animate){
7160 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7165 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7166 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7167 * @return {Roo.Element} this
7169 setDisplayed : function(value) {
7170 if(typeof value == "boolean"){
7171 value = value ? this.originalDisplay : "none";
7173 this.setStyle("display", value);
7178 * Tries to focus the element. Any exceptions are caught and ignored.
7179 * @return {Roo.Element} this
7181 focus : function() {
7189 * Tries to blur the element. Any exceptions are caught and ignored.
7190 * @return {Roo.Element} this
7200 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7201 * @param {String/Array} className The CSS class to add, or an array of classes
7202 * @return {Roo.Element} this
7204 addClass : function(className){
7205 if(className instanceof Array){
7206 for(var i = 0, len = className.length; i < len; i++) {
7207 this.addClass(className[i]);
7210 if(className && !this.hasClass(className)){
7211 this.dom.className = this.dom.className + " " + className;
7218 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7219 * @param {String/Array} className The CSS class to add, or an array of classes
7220 * @return {Roo.Element} this
7222 radioClass : function(className){
7223 var siblings = this.dom.parentNode.childNodes;
7224 for(var i = 0; i < siblings.length; i++) {
7225 var s = siblings[i];
7226 if(s.nodeType == 1){
7227 Roo.get(s).removeClass(className);
7230 this.addClass(className);
7235 * Removes one or more CSS classes from the element.
7236 * @param {String/Array} className The CSS class to remove, or an array of classes
7237 * @return {Roo.Element} this
7239 removeClass : function(className){
7240 if(!className || !this.dom.className){
7243 if(className instanceof Array){
7244 for(var i = 0, len = className.length; i < len; i++) {
7245 this.removeClass(className[i]);
7248 if(this.hasClass(className)){
7249 var re = this.classReCache[className];
7251 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7252 this.classReCache[className] = re;
7254 this.dom.className =
7255 this.dom.className.replace(re, " ");
7265 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7266 * @param {String} className The CSS class to toggle
7267 * @return {Roo.Element} this
7269 toggleClass : function(className){
7270 if(this.hasClass(className)){
7271 this.removeClass(className);
7273 this.addClass(className);
7279 * Checks if the specified CSS class exists on this element's DOM node.
7280 * @param {String} className The CSS class to check for
7281 * @return {Boolean} True if the class exists, else false
7283 hasClass : function(className){
7284 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7288 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7289 * @param {String} oldClassName The CSS class to replace
7290 * @param {String} newClassName The replacement CSS class
7291 * @return {Roo.Element} this
7293 replaceClass : function(oldClassName, newClassName){
7294 this.removeClass(oldClassName);
7295 this.addClass(newClassName);
7300 * Returns an object with properties matching the styles requested.
7301 * For example, el.getStyles('color', 'font-size', 'width') might return
7302 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7303 * @param {String} style1 A style name
7304 * @param {String} style2 A style name
7305 * @param {String} etc.
7306 * @return {Object} The style object
7308 getStyles : function(){
7309 var a = arguments, len = a.length, r = {};
7310 for(var i = 0; i < len; i++){
7311 r[a[i]] = this.getStyle(a[i]);
7317 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7318 * @param {String} property The style property whose value is returned.
7319 * @return {String} The current value of the style property for this element.
7321 getStyle : function(){
7322 return view && view.getComputedStyle ?
7324 var el = this.dom, v, cs, camel;
7325 if(prop == 'float'){
7328 if(el.style && (v = el.style[prop])){
7331 if(cs = view.getComputedStyle(el, "")){
7332 if(!(camel = propCache[prop])){
7333 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7340 var el = this.dom, v, cs, camel;
7341 if(prop == 'opacity'){
7342 if(typeof el.style.filter == 'string'){
7343 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7345 var fv = parseFloat(m[1]);
7347 return fv ? fv / 100 : 0;
7352 }else if(prop == 'float'){
7353 prop = "styleFloat";
7355 if(!(camel = propCache[prop])){
7356 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7358 if(v = el.style[camel]){
7361 if(cs = el.currentStyle){
7369 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7370 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7371 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7372 * @return {Roo.Element} this
7374 setStyle : function(prop, value){
7375 if(typeof prop == "string"){
7377 if(!(camel = propCache[prop])){
7378 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7380 if(camel == 'opacity') {
7381 this.setOpacity(value);
7383 this.dom.style[camel] = value;
7386 for(var style in prop){
7387 if(typeof prop[style] != "function"){
7388 this.setStyle(style, prop[style]);
7396 * More flexible version of {@link #setStyle} for setting style properties.
7397 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7398 * a function which returns such a specification.
7399 * @return {Roo.Element} this
7401 applyStyles : function(style){
7402 Roo.DomHelper.applyStyles(this.dom, style);
7407 * 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).
7408 * @return {Number} The X position of the element
7411 return D.getX(this.dom);
7415 * 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).
7416 * @return {Number} The Y position of the element
7419 return D.getY(this.dom);
7423 * 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).
7424 * @return {Array} The XY position of the element
7427 return D.getXY(this.dom);
7431 * 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).
7432 * @param {Number} The X position of the element
7433 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7434 * @return {Roo.Element} this
7436 setX : function(x, animate){
7438 D.setX(this.dom, x);
7440 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7446 * 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).
7447 * @param {Number} The Y position of the element
7448 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7449 * @return {Roo.Element} this
7451 setY : function(y, animate){
7453 D.setY(this.dom, y);
7455 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7461 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7462 * @param {String} left The left CSS property value
7463 * @return {Roo.Element} this
7465 setLeft : function(left){
7466 this.setStyle("left", this.addUnits(left));
7471 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7472 * @param {String} top The top CSS property value
7473 * @return {Roo.Element} this
7475 setTop : function(top){
7476 this.setStyle("top", this.addUnits(top));
7481 * Sets the element's CSS right style.
7482 * @param {String} right The right CSS property value
7483 * @return {Roo.Element} this
7485 setRight : function(right){
7486 this.setStyle("right", this.addUnits(right));
7491 * Sets the element's CSS bottom style.
7492 * @param {String} bottom The bottom CSS property value
7493 * @return {Roo.Element} this
7495 setBottom : function(bottom){
7496 this.setStyle("bottom", this.addUnits(bottom));
7501 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7502 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7503 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7504 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7505 * @return {Roo.Element} this
7507 setXY : function(pos, animate){
7509 D.setXY(this.dom, pos);
7511 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7517 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7518 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7519 * @param {Number} x X value for new position (coordinates are page-based)
7520 * @param {Number} y Y value for new position (coordinates are page-based)
7521 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7522 * @return {Roo.Element} this
7524 setLocation : function(x, y, animate){
7525 this.setXY([x, y], this.preanim(arguments, 2));
7530 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7531 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7532 * @param {Number} x X value for new position (coordinates are page-based)
7533 * @param {Number} y Y value for new position (coordinates are page-based)
7534 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7535 * @return {Roo.Element} this
7537 moveTo : function(x, y, animate){
7538 this.setXY([x, y], this.preanim(arguments, 2));
7543 * Returns the region of the given element.
7544 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7545 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7547 getRegion : function(){
7548 return D.getRegion(this.dom);
7552 * Returns the offset height of the element
7553 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7554 * @return {Number} The element's height
7556 getHeight : function(contentHeight){
7557 var h = this.dom.offsetHeight || 0;
7558 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7562 * Returns the offset width of the element
7563 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7564 * @return {Number} The element's width
7566 getWidth : function(contentWidth){
7567 var w = this.dom.offsetWidth || 0;
7568 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7572 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7573 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7574 * if a height has not been set using CSS.
7577 getComputedHeight : function(){
7578 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7580 h = parseInt(this.getStyle('height'), 10) || 0;
7581 if(!this.isBorderBox()){
7582 h += this.getFrameWidth('tb');
7589 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7590 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7591 * if a width has not been set using CSS.
7594 getComputedWidth : function(){
7595 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7597 w = parseInt(this.getStyle('width'), 10) || 0;
7598 if(!this.isBorderBox()){
7599 w += this.getFrameWidth('lr');
7606 * Returns the size of the element.
7607 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7608 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7610 getSize : function(contentSize){
7611 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7615 * Returns the width and height of the viewport.
7616 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7618 getViewSize : function(){
7619 var d = this.dom, doc = document, aw = 0, ah = 0;
7620 if(d == doc || d == doc.body){
7621 return {width : D.getViewWidth(), height: D.getViewHeight()};
7624 width : d.clientWidth,
7625 height: d.clientHeight
7631 * Returns the value of the "value" attribute
7632 * @param {Boolean} asNumber true to parse the value as a number
7633 * @return {String/Number}
7635 getValue : function(asNumber){
7636 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7640 adjustWidth : function(width){
7641 if(typeof width == "number"){
7642 if(this.autoBoxAdjust && !this.isBorderBox()){
7643 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7653 adjustHeight : function(height){
7654 if(typeof height == "number"){
7655 if(this.autoBoxAdjust && !this.isBorderBox()){
7656 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7666 * Set the width of the element
7667 * @param {Number} width The new width
7668 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7669 * @return {Roo.Element} this
7671 setWidth : function(width, animate){
7672 width = this.adjustWidth(width);
7674 this.dom.style.width = this.addUnits(width);
7676 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7682 * Set the height of the element
7683 * @param {Number} height The new height
7684 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7685 * @return {Roo.Element} this
7687 setHeight : function(height, animate){
7688 height = this.adjustHeight(height);
7690 this.dom.style.height = this.addUnits(height);
7692 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7698 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7699 * @param {Number} width The new width
7700 * @param {Number} height The new height
7701 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7702 * @return {Roo.Element} this
7704 setSize : function(width, height, animate){
7705 if(typeof width == "object"){ // in case of object from getSize()
7706 height = width.height; width = width.width;
7708 width = this.adjustWidth(width); height = this.adjustHeight(height);
7710 this.dom.style.width = this.addUnits(width);
7711 this.dom.style.height = this.addUnits(height);
7713 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7719 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7720 * @param {Number} x X value for new position (coordinates are page-based)
7721 * @param {Number} y Y value for new position (coordinates are page-based)
7722 * @param {Number} width The new width
7723 * @param {Number} height The new height
7724 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7725 * @return {Roo.Element} this
7727 setBounds : function(x, y, width, height, animate){
7729 this.setSize(width, height);
7730 this.setLocation(x, y);
7732 width = this.adjustWidth(width); height = this.adjustHeight(height);
7733 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7734 this.preanim(arguments, 4), 'motion');
7740 * 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.
7741 * @param {Roo.lib.Region} region The region to fill
7742 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7743 * @return {Roo.Element} this
7745 setRegion : function(region, animate){
7746 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7751 * Appends an event handler
7753 * @param {String} eventName The type of event to append
7754 * @param {Function} fn The method the event invokes
7755 * @param {Object} scope (optional) The scope (this object) of the fn
7756 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7758 addListener : function(eventName, fn, scope, options){
7759 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7763 * Removes an event handler from this element
7764 * @param {String} eventName the type of event to remove
7765 * @param {Function} fn the method the event invokes
7766 * @return {Roo.Element} this
7768 removeListener : function(eventName, fn){
7769 Roo.EventManager.removeListener(this.dom, eventName, fn);
7774 * Removes all previous added listeners from this element
7775 * @return {Roo.Element} this
7777 removeAllListeners : function(){
7778 E.purgeElement(this.dom);
7782 relayEvent : function(eventName, observable){
7783 this.on(eventName, function(e){
7784 observable.fireEvent(eventName, e);
7789 * Set the opacity of the element
7790 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7791 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7792 * @return {Roo.Element} this
7794 setOpacity : function(opacity, animate){
7796 var s = this.dom.style;
7799 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7800 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7802 s.opacity = opacity;
7805 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7811 * Gets the left X coordinate
7812 * @param {Boolean} local True to get the local css position instead of page coordinate
7815 getLeft : function(local){
7819 return parseInt(this.getStyle("left"), 10) || 0;
7824 * Gets the right X coordinate of the element (element X position + element width)
7825 * @param {Boolean} local True to get the local css position instead of page coordinate
7828 getRight : function(local){
7830 return this.getX() + this.getWidth();
7832 return (this.getLeft(true) + this.getWidth()) || 0;
7837 * Gets the top Y coordinate
7838 * @param {Boolean} local True to get the local css position instead of page coordinate
7841 getTop : function(local) {
7845 return parseInt(this.getStyle("top"), 10) || 0;
7850 * Gets the bottom Y coordinate of the element (element Y position + element height)
7851 * @param {Boolean} local True to get the local css position instead of page coordinate
7854 getBottom : function(local){
7856 return this.getY() + this.getHeight();
7858 return (this.getTop(true) + this.getHeight()) || 0;
7863 * Initializes positioning on this element. If a desired position is not passed, it will make the
7864 * the element positioned relative IF it is not already positioned.
7865 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7866 * @param {Number} zIndex (optional) The zIndex to apply
7867 * @param {Number} x (optional) Set the page X position
7868 * @param {Number} y (optional) Set the page Y position
7870 position : function(pos, zIndex, x, y){
7872 if(this.getStyle('position') == 'static'){
7873 this.setStyle('position', 'relative');
7876 this.setStyle("position", pos);
7879 this.setStyle("z-index", zIndex);
7881 if(x !== undefined && y !== undefined){
7883 }else if(x !== undefined){
7885 }else if(y !== undefined){
7891 * Clear positioning back to the default when the document was loaded
7892 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7893 * @return {Roo.Element} this
7895 clearPositioning : function(value){
7903 "position" : "static"
7909 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7910 * snapshot before performing an update and then restoring the element.
7913 getPositioning : function(){
7914 var l = this.getStyle("left");
7915 var t = this.getStyle("top");
7917 "position" : this.getStyle("position"),
7919 "right" : l ? "" : this.getStyle("right"),
7921 "bottom" : t ? "" : this.getStyle("bottom"),
7922 "z-index" : this.getStyle("z-index")
7927 * Gets the width of the border(s) for the specified side(s)
7928 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7929 * passing lr would get the border (l)eft width + the border (r)ight width.
7930 * @return {Number} The width of the sides passed added together
7932 getBorderWidth : function(side){
7933 return this.addStyles(side, El.borders);
7937 * Gets the width of the padding(s) for the specified side(s)
7938 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7939 * passing lr would get the padding (l)eft + the padding (r)ight.
7940 * @return {Number} The padding of the sides passed added together
7942 getPadding : function(side){
7943 return this.addStyles(side, El.paddings);
7947 * Set positioning with an object returned by getPositioning().
7948 * @param {Object} posCfg
7949 * @return {Roo.Element} this
7951 setPositioning : function(pc){
7952 this.applyStyles(pc);
7953 if(pc.right == "auto"){
7954 this.dom.style.right = "";
7956 if(pc.bottom == "auto"){
7957 this.dom.style.bottom = "";
7963 fixDisplay : function(){
7964 if(this.getStyle("display") == "none"){
7965 this.setStyle("visibility", "hidden");
7966 this.setStyle("display", this.originalDisplay); // first try reverting to default
7967 if(this.getStyle("display") == "none"){ // if that fails, default to block
7968 this.setStyle("display", "block");
7974 * Quick set left and top adding default units
7975 * @param {String} left The left CSS property value
7976 * @param {String} top The top CSS property value
7977 * @return {Roo.Element} this
7979 setLeftTop : function(left, top){
7980 this.dom.style.left = this.addUnits(left);
7981 this.dom.style.top = this.addUnits(top);
7986 * Move this element relative to its current position.
7987 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
7988 * @param {Number} distance How far to move the element in pixels
7989 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7990 * @return {Roo.Element} this
7992 move : function(direction, distance, animate){
7993 var xy = this.getXY();
7994 direction = direction.toLowerCase();
7998 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8002 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8007 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8012 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8019 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8020 * @return {Roo.Element} this
8023 if(!this.isClipped){
8024 this.isClipped = true;
8025 this.originalClip = {
8026 "o": this.getStyle("overflow"),
8027 "x": this.getStyle("overflow-x"),
8028 "y": this.getStyle("overflow-y")
8030 this.setStyle("overflow", "hidden");
8031 this.setStyle("overflow-x", "hidden");
8032 this.setStyle("overflow-y", "hidden");
8038 * Return clipping (overflow) to original clipping before clip() was called
8039 * @return {Roo.Element} this
8041 unclip : function(){
8043 this.isClipped = false;
8044 var o = this.originalClip;
8045 if(o.o){this.setStyle("overflow", o.o);}
8046 if(o.x){this.setStyle("overflow-x", o.x);}
8047 if(o.y){this.setStyle("overflow-y", o.y);}
8054 * Gets the x,y coordinates specified by the anchor position on the element.
8055 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8056 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8057 * {width: (target width), height: (target height)} (defaults to the element's current size)
8058 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8059 * @return {Array} [x, y] An array containing the element's x and y coordinates
8061 getAnchorXY : function(anchor, local, s){
8062 //Passing a different size is useful for pre-calculating anchors,
8063 //especially for anchored animations that change the el size.
8065 var w, h, vp = false;
8068 if(d == document.body || d == document){
8070 w = D.getViewWidth(); h = D.getViewHeight();
8072 w = this.getWidth(); h = this.getHeight();
8075 w = s.width; h = s.height;
8077 var x = 0, y = 0, r = Math.round;
8078 switch((anchor || "tl").toLowerCase()){
8120 var sc = this.getScroll();
8121 return [x + sc.left, y + sc.top];
8123 //Add the element's offset xy
8124 var o = this.getXY();
8125 return [x+o[0], y+o[1]];
8129 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8130 * supported position values.
8131 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8132 * @param {String} position The position to align to.
8133 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8134 * @return {Array} [x, y]
8136 getAlignToXY : function(el, p, o){
8140 throw "Element.alignTo with an element that doesn't exist";
8142 var c = false; //constrain to viewport
8143 var p1 = "", p2 = "";
8150 }else if(p.indexOf("-") == -1){
8153 p = p.toLowerCase();
8154 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8156 throw "Element.alignTo with an invalid alignment " + p;
8158 p1 = m[1]; p2 = m[2]; c = !!m[3];
8160 //Subtract the aligned el's internal xy from the target's offset xy
8161 //plus custom offset to get the aligned el's new offset xy
8162 var a1 = this.getAnchorXY(p1, true);
8163 var a2 = el.getAnchorXY(p2, false);
8164 var x = a2[0] - a1[0] + o[0];
8165 var y = a2[1] - a1[1] + o[1];
8167 //constrain the aligned el to viewport if necessary
8168 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8169 // 5px of margin for ie
8170 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8172 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8173 //perpendicular to the vp border, allow the aligned el to slide on that border,
8174 //otherwise swap the aligned el to the opposite border of the target.
8175 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8176 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8177 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8178 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8181 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8182 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8184 if((x+w) > dw + scrollX){
8185 x = swapX ? r.left-w : dw+scrollX-w;
8188 x = swapX ? r.right : scrollX;
8190 if((y+h) > dh + scrollY){
8191 y = swapY ? r.top-h : dh+scrollY-h;
8194 y = swapY ? r.bottom : scrollY;
8201 getConstrainToXY : function(){
8202 var os = {top:0, left:0, bottom:0, right: 0};
8204 return function(el, local, offsets, proposedXY){
8206 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8208 var vw, vh, vx = 0, vy = 0;
8209 if(el.dom == document.body || el.dom == document){
8210 vw = Roo.lib.Dom.getViewWidth();
8211 vh = Roo.lib.Dom.getViewHeight();
8213 vw = el.dom.clientWidth;
8214 vh = el.dom.clientHeight;
8216 var vxy = el.getXY();
8222 var s = el.getScroll();
8224 vx += offsets.left + s.left;
8225 vy += offsets.top + s.top;
8227 vw -= offsets.right;
8228 vh -= offsets.bottom;
8233 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8234 var x = xy[0], y = xy[1];
8235 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8237 // only move it if it needs it
8240 // first validate right/bottom
8249 // then make sure top/left isn't negative
8258 return moved ? [x, y] : false;
8263 adjustForConstraints : function(xy, parent, offsets){
8264 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8268 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8269 * document it aligns it to the viewport.
8270 * The position parameter is optional, and can be specified in any one of the following formats:
8272 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8273 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8274 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8275 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8276 * <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
8277 * element's anchor point, and the second value is used as the target's anchor point.</li>
8279 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8280 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8281 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8282 * that specified in order to enforce the viewport constraints.
8283 * Following are all of the supported anchor positions:
8286 ----- -----------------------------
8287 tl The top left corner (default)
8288 t The center of the top edge
8289 tr The top right corner
8290 l The center of the left edge
8291 c In the center of the element
8292 r The center of the right edge
8293 bl The bottom left corner
8294 b The center of the bottom edge
8295 br The bottom right corner
8299 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8300 el.alignTo("other-el");
8302 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8303 el.alignTo("other-el", "tr?");
8305 // align the bottom right corner of el with the center left edge of other-el
8306 el.alignTo("other-el", "br-l?");
8308 // align the center of el with the bottom left corner of other-el and
8309 // adjust the x position by -6 pixels (and the y position by 0)
8310 el.alignTo("other-el", "c-bl", [-6, 0]);
8312 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8313 * @param {String} position The position to align to.
8314 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8315 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8316 * @return {Roo.Element} this
8318 alignTo : function(element, position, offsets, animate){
8319 var xy = this.getAlignToXY(element, position, offsets);
8320 this.setXY(xy, this.preanim(arguments, 3));
8325 * Anchors an element to another element and realigns it when the window is resized.
8326 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8327 * @param {String} position The position to align to.
8328 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8329 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8330 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8331 * is a number, it is used as the buffer delay (defaults to 50ms).
8332 * @param {Function} callback The function to call after the animation finishes
8333 * @return {Roo.Element} this
8335 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8336 var action = function(){
8337 this.alignTo(el, alignment, offsets, animate);
8338 Roo.callback(callback, this);
8340 Roo.EventManager.onWindowResize(action, this);
8341 var tm = typeof monitorScroll;
8342 if(tm != 'undefined'){
8343 Roo.EventManager.on(window, 'scroll', action, this,
8344 {buffer: tm == 'number' ? monitorScroll : 50});
8346 action.call(this); // align immediately
8350 * Clears any opacity settings from this element. Required in some cases for IE.
8351 * @return {Roo.Element} this
8353 clearOpacity : function(){
8354 if (window.ActiveXObject) {
8355 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8356 this.dom.style.filter = "";
8359 this.dom.style.opacity = "";
8360 this.dom.style["-moz-opacity"] = "";
8361 this.dom.style["-khtml-opacity"] = "";
8367 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8368 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8369 * @return {Roo.Element} this
8371 hide : function(animate){
8372 this.setVisible(false, this.preanim(arguments, 0));
8377 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8378 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8379 * @return {Roo.Element} this
8381 show : function(animate){
8382 this.setVisible(true, this.preanim(arguments, 0));
8387 * @private Test if size has a unit, otherwise appends the default
8389 addUnits : function(size){
8390 return Roo.Element.addUnits(size, this.defaultUnit);
8394 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8395 * @return {Roo.Element} this
8397 beginMeasure : function(){
8399 if(el.offsetWidth || el.offsetHeight){
8400 return this; // offsets work already
8403 var p = this.dom, b = document.body; // start with this element
8404 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8405 var pe = Roo.get(p);
8406 if(pe.getStyle('display') == 'none'){
8407 changed.push({el: p, visibility: pe.getStyle("visibility")});
8408 p.style.visibility = "hidden";
8409 p.style.display = "block";
8413 this._measureChanged = changed;
8419 * Restores displays to before beginMeasure was called
8420 * @return {Roo.Element} this
8422 endMeasure : function(){
8423 var changed = this._measureChanged;
8425 for(var i = 0, len = changed.length; i < len; i++) {
8427 r.el.style.visibility = r.visibility;
8428 r.el.style.display = "none";
8430 this._measureChanged = null;
8436 * Update the innerHTML of this element, optionally searching for and processing scripts
8437 * @param {String} html The new HTML
8438 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8439 * @param {Function} callback For async script loading you can be noticed when the update completes
8440 * @return {Roo.Element} this
8442 update : function(html, loadScripts, callback){
8443 if(typeof html == "undefined"){
8446 if(loadScripts !== true){
8447 this.dom.innerHTML = html;
8448 if(typeof callback == "function"){
8456 html += '<span id="' + id + '"></span>';
8458 E.onAvailable(id, function(){
8459 var hd = document.getElementsByTagName("head")[0];
8460 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8461 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8462 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8465 while(match = re.exec(html)){
8466 var attrs = match[1];
8467 var srcMatch = attrs ? attrs.match(srcRe) : false;
8468 if(srcMatch && srcMatch[2]){
8469 var s = document.createElement("script");
8470 s.src = srcMatch[2];
8471 var typeMatch = attrs.match(typeRe);
8472 if(typeMatch && typeMatch[2]){
8473 s.type = typeMatch[2];
8476 }else if(match[2] && match[2].length > 0){
8477 if(window.execScript) {
8478 window.execScript(match[2]);
8486 window.eval(match[2]);
8490 var el = document.getElementById(id);
8491 if(el){el.parentNode.removeChild(el);}
8492 if(typeof callback == "function"){
8496 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8501 * Direct access to the UpdateManager update() method (takes the same parameters).
8502 * @param {String/Function} url The url for this request or a function to call to get the url
8503 * @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}
8504 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8505 * @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.
8506 * @return {Roo.Element} this
8509 var um = this.getUpdateManager();
8510 um.update.apply(um, arguments);
8515 * Gets this element's UpdateManager
8516 * @return {Roo.UpdateManager} The UpdateManager
8518 getUpdateManager : function(){
8519 if(!this.updateManager){
8520 this.updateManager = new Roo.UpdateManager(this);
8522 return this.updateManager;
8526 * Disables text selection for this element (normalized across browsers)
8527 * @return {Roo.Element} this
8529 unselectable : function(){
8530 this.dom.unselectable = "on";
8531 this.swallowEvent("selectstart", true);
8532 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8533 this.addClass("x-unselectable");
8538 * Calculates the x, y to center this element on the screen
8539 * @return {Array} The x, y values [x, y]
8541 getCenterXY : function(){
8542 return this.getAlignToXY(document, 'c-c');
8546 * Centers the Element in either the viewport, or another Element.
8547 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8549 center : function(centerIn){
8550 this.alignTo(centerIn || document, 'c-c');
8555 * Tests various css rules/browsers to determine if this element uses a border box
8558 isBorderBox : function(){
8559 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8563 * Return a box {x, y, width, height} that can be used to set another elements
8564 * size/location to match this element.
8565 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8566 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8567 * @return {Object} box An object in the format {x, y, width, height}
8569 getBox : function(contentBox, local){
8574 var left = parseInt(this.getStyle("left"), 10) || 0;
8575 var top = parseInt(this.getStyle("top"), 10) || 0;
8578 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8580 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8582 var l = this.getBorderWidth("l")+this.getPadding("l");
8583 var r = this.getBorderWidth("r")+this.getPadding("r");
8584 var t = this.getBorderWidth("t")+this.getPadding("t");
8585 var b = this.getBorderWidth("b")+this.getPadding("b");
8586 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)};
8588 bx.right = bx.x + bx.width;
8589 bx.bottom = bx.y + bx.height;
8594 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8595 for more information about the sides.
8596 * @param {String} sides
8599 getFrameWidth : function(sides, onlyContentBox){
8600 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8604 * 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.
8605 * @param {Object} box The box to fill {x, y, width, height}
8606 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8607 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8608 * @return {Roo.Element} this
8610 setBox : function(box, adjust, animate){
8611 var w = box.width, h = box.height;
8612 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8613 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8614 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8616 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8621 * Forces the browser to repaint this element
8622 * @return {Roo.Element} this
8624 repaint : function(){
8626 this.addClass("x-repaint");
8627 setTimeout(function(){
8628 Roo.get(dom).removeClass("x-repaint");
8634 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8635 * then it returns the calculated width of the sides (see getPadding)
8636 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8637 * @return {Object/Number}
8639 getMargins : function(side){
8642 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8643 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8644 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8645 right: parseInt(this.getStyle("margin-right"), 10) || 0
8648 return this.addStyles(side, El.margins);
8653 addStyles : function(sides, styles){
8655 for(var i = 0, len = sides.length; i < len; i++){
8656 v = this.getStyle(styles[sides.charAt(i)]);
8658 w = parseInt(v, 10);
8666 * Creates a proxy element of this element
8667 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8668 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8669 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8670 * @return {Roo.Element} The new proxy element
8672 createProxy : function(config, renderTo, matchBox){
8674 renderTo = Roo.getDom(renderTo);
8676 renderTo = document.body;
8678 config = typeof config == "object" ?
8679 config : {tag : "div", cls: config};
8680 var proxy = Roo.DomHelper.append(renderTo, config, true);
8682 proxy.setBox(this.getBox());
8688 * Puts a mask over this element to disable user interaction. Requires core.css.
8689 * This method can only be applied to elements which accept child nodes.
8690 * @param {String} msg (optional) A message to display in the mask
8691 * @param {String} msgCls (optional) A css class to apply to the msg element
8692 * @return {Element} The mask element
8694 mask : function(msg, msgCls){
8695 if(this.getStyle("position") == "static"){
8696 this.setStyle("position", "relative");
8699 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8701 this.addClass("x-masked");
8702 this._mask.setDisplayed(true);
8703 if(typeof msg == 'string'){
8705 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8707 var mm = this._maskMsg;
8708 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8709 mm.dom.firstChild.innerHTML = msg;
8710 mm.setDisplayed(true);
8713 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8714 this._mask.setHeight(this.getHeight());
8720 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8721 * it is cached for reuse.
8723 unmask : function(removeEl){
8725 if(removeEl === true){
8726 this._mask.remove();
8729 this._maskMsg.remove();
8730 delete this._maskMsg;
8733 this._mask.setDisplayed(false);
8735 this._maskMsg.setDisplayed(false);
8739 this.removeClass("x-masked");
8743 * Returns true if this element is masked
8746 isMasked : function(){
8747 return this._mask && this._mask.isVisible();
8751 * Creates an iframe shim for this element to keep selects and other windowed objects from
8753 * @return {Roo.Element} The new shim element
8755 createShim : function(){
8756 var el = document.createElement('iframe');
8757 el.frameBorder = 'no';
8758 el.className = 'roo-shim';
8759 if(Roo.isIE && Roo.isSecure){
8760 el.src = Roo.SSL_SECURE_URL;
8762 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8763 shim.autoBoxAdjust = false;
8768 * Removes this element from the DOM and deletes it from the cache
8770 remove : function(){
8771 if(this.dom.parentNode){
8772 this.dom.parentNode.removeChild(this.dom);
8774 delete El.cache[this.dom.id];
8778 * Sets up event handlers to add and remove a css class when the mouse is over this element
8779 * @param {String} className
8780 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8781 * mouseout events for children elements
8782 * @return {Roo.Element} this
8784 addClassOnOver : function(className, preventFlicker){
8785 this.on("mouseover", function(){
8786 Roo.fly(this, '_internal').addClass(className);
8788 var removeFn = function(e){
8789 if(preventFlicker !== true || !e.within(this, true)){
8790 Roo.fly(this, '_internal').removeClass(className);
8793 this.on("mouseout", removeFn, this.dom);
8798 * Sets up event handlers to add and remove a css class when this element has the focus
8799 * @param {String} className
8800 * @return {Roo.Element} this
8802 addClassOnFocus : function(className){
8803 this.on("focus", function(){
8804 Roo.fly(this, '_internal').addClass(className);
8806 this.on("blur", function(){
8807 Roo.fly(this, '_internal').removeClass(className);
8812 * 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)
8813 * @param {String} className
8814 * @return {Roo.Element} this
8816 addClassOnClick : function(className){
8818 this.on("mousedown", function(){
8819 Roo.fly(dom, '_internal').addClass(className);
8820 var d = Roo.get(document);
8821 var fn = function(){
8822 Roo.fly(dom, '_internal').removeClass(className);
8823 d.removeListener("mouseup", fn);
8825 d.on("mouseup", fn);
8831 * Stops the specified event from bubbling and optionally prevents the default action
8832 * @param {String} eventName
8833 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8834 * @return {Roo.Element} this
8836 swallowEvent : function(eventName, preventDefault){
8837 var fn = function(e){
8838 e.stopPropagation();
8843 if(eventName instanceof Array){
8844 for(var i = 0, len = eventName.length; i < len; i++){
8845 this.on(eventName[i], fn);
8849 this.on(eventName, fn);
8856 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8859 * Sizes this element to its parent element's dimensions performing
8860 * neccessary box adjustments.
8861 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8862 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8863 * @return {Roo.Element} this
8865 fitToParent : function(monitorResize, targetParent) {
8866 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8867 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8868 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8871 var p = Roo.get(targetParent || this.dom.parentNode);
8872 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8873 if (monitorResize === true) {
8874 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8875 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8881 * Gets the next sibling, skipping text nodes
8882 * @return {HTMLElement} The next sibling or null
8884 getNextSibling : function(){
8885 var n = this.dom.nextSibling;
8886 while(n && n.nodeType != 1){
8893 * Gets the previous sibling, skipping text nodes
8894 * @return {HTMLElement} The previous sibling or null
8896 getPrevSibling : function(){
8897 var n = this.dom.previousSibling;
8898 while(n && n.nodeType != 1){
8899 n = n.previousSibling;
8906 * Appends the passed element(s) to this element
8907 * @param {String/HTMLElement/Array/Element/CompositeElement} el
8908 * @return {Roo.Element} this
8910 appendChild: function(el){
8917 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8918 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
8919 * automatically generated with the specified attributes.
8920 * @param {HTMLElement} insertBefore (optional) a child element of this element
8921 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8922 * @return {Roo.Element} The new child element
8924 createChild: function(config, insertBefore, returnDom){
8925 config = config || {tag:'div'};
8927 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8929 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
8933 * Appends this element to the passed element
8934 * @param {String/HTMLElement/Element} el The new parent element
8935 * @return {Roo.Element} this
8937 appendTo: function(el){
8938 el = Roo.getDom(el);
8939 el.appendChild(this.dom);
8944 * Inserts this element before the passed element in the DOM
8945 * @param {String/HTMLElement/Element} el The element to insert before
8946 * @return {Roo.Element} this
8948 insertBefore: function(el){
8949 el = Roo.getDom(el);
8950 el.parentNode.insertBefore(this.dom, el);
8955 * Inserts this element after the passed element in the DOM
8956 * @param {String/HTMLElement/Element} el The element to insert after
8957 * @return {Roo.Element} this
8959 insertAfter: function(el){
8960 el = Roo.getDom(el);
8961 el.parentNode.insertBefore(this.dom, el.nextSibling);
8966 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8967 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8968 * @return {Roo.Element} The new child
8970 insertFirst: function(el, returnDom){
8972 if(typeof el == 'object' && !el.nodeType){ // dh config
8973 return this.createChild(el, this.dom.firstChild, returnDom);
8975 el = Roo.getDom(el);
8976 this.dom.insertBefore(el, this.dom.firstChild);
8977 return !returnDom ? Roo.get(el) : el;
8982 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
8983 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8984 * @param {String} where (optional) 'before' or 'after' defaults to before
8985 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8986 * @return {Roo.Element} the inserted Element
8988 insertSibling: function(el, where, returnDom){
8989 where = where ? where.toLowerCase() : 'before';
8991 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
8993 if(typeof el == 'object' && !el.nodeType){ // dh config
8994 if(where == 'after' && !this.dom.nextSibling){
8995 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
8997 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9001 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9002 where == 'before' ? this.dom : this.dom.nextSibling);
9011 * Creates and wraps this element with another element
9012 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9013 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9014 * @return {HTMLElement/Element} The newly created wrapper element
9016 wrap: function(config, returnDom){
9018 config = {tag: "div"};
9020 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9021 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9026 * Replaces the passed element with this element
9027 * @param {String/HTMLElement/Element} el The element to replace
9028 * @return {Roo.Element} this
9030 replace: function(el){
9032 this.insertBefore(el);
9038 * Inserts an html fragment into this element
9039 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9040 * @param {String} html The HTML fragment
9041 * @param {Boolean} returnEl True to return an Roo.Element
9042 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9044 insertHtml : function(where, html, returnEl){
9045 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9046 return returnEl ? Roo.get(el) : el;
9050 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9051 * @param {Object} o The object with the attributes
9052 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9053 * @return {Roo.Element} this
9055 set : function(o, useSet){
9057 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9059 if(attr == "style" || typeof o[attr] == "function") continue;
9061 el.className = o["cls"];
9063 if(useSet) el.setAttribute(attr, o[attr]);
9064 else el[attr] = o[attr];
9068 Roo.DomHelper.applyStyles(el, o.style);
9074 * Convenience method for constructing a KeyMap
9075 * @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:
9076 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9077 * @param {Function} fn The function to call
9078 * @param {Object} scope (optional) The scope of the function
9079 * @return {Roo.KeyMap} The KeyMap created
9081 addKeyListener : function(key, fn, scope){
9083 if(typeof key != "object" || key instanceof Array){
9099 return new Roo.KeyMap(this, config);
9103 * Creates a KeyMap for this element
9104 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9105 * @return {Roo.KeyMap} The KeyMap created
9107 addKeyMap : function(config){
9108 return new Roo.KeyMap(this, config);
9112 * Returns true if this element is scrollable.
9115 isScrollable : function(){
9117 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9121 * 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().
9122 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9123 * @param {Number} value The new scroll value
9124 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9125 * @return {Element} this
9128 scrollTo : function(side, value, animate){
9129 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9131 this.dom[prop] = value;
9133 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9134 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9140 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9141 * within this element's scrollable range.
9142 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9143 * @param {Number} distance How far to scroll the element in pixels
9144 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9145 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9146 * was scrolled as far as it could go.
9148 scroll : function(direction, distance, animate){
9149 if(!this.isScrollable()){
9153 var l = el.scrollLeft, t = el.scrollTop;
9154 var w = el.scrollWidth, h = el.scrollHeight;
9155 var cw = el.clientWidth, ch = el.clientHeight;
9156 direction = direction.toLowerCase();
9157 var scrolled = false;
9158 var a = this.preanim(arguments, 2);
9163 var v = Math.min(l + distance, w-cw);
9164 this.scrollTo("left", v, a);
9171 var v = Math.max(l - distance, 0);
9172 this.scrollTo("left", v, a);
9180 var v = Math.max(t - distance, 0);
9181 this.scrollTo("top", v, a);
9189 var v = Math.min(t + distance, h-ch);
9190 this.scrollTo("top", v, a);
9199 * Translates the passed page coordinates into left/top css values for this element
9200 * @param {Number/Array} x The page x or an array containing [x, y]
9201 * @param {Number} y The page y
9202 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9204 translatePoints : function(x, y){
9205 if(typeof x == 'object' || x instanceof Array){
9208 var p = this.getStyle('position');
9209 var o = this.getXY();
9211 var l = parseInt(this.getStyle('left'), 10);
9212 var t = parseInt(this.getStyle('top'), 10);
9215 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9218 t = (p == "relative") ? 0 : this.dom.offsetTop;
9221 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9225 * Returns the current scroll position of the element.
9226 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9228 getScroll : function(){
9229 var d = this.dom, doc = document;
9230 if(d == doc || d == doc.body){
9231 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9232 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9233 return {left: l, top: t};
9235 return {left: d.scrollLeft, top: d.scrollTop};
9240 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9241 * are convert to standard 6 digit hex color.
9242 * @param {String} attr The css attribute
9243 * @param {String} defaultValue The default value to use when a valid color isn't found
9244 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9247 getColor : function(attr, defaultValue, prefix){
9248 var v = this.getStyle(attr);
9249 if(!v || v == "transparent" || v == "inherit") {
9250 return defaultValue;
9252 var color = typeof prefix == "undefined" ? "#" : prefix;
9253 if(v.substr(0, 4) == "rgb("){
9254 var rvs = v.slice(4, v.length -1).split(",");
9255 for(var i = 0; i < 3; i++){
9256 var h = parseInt(rvs[i]).toString(16);
9263 if(v.substr(0, 1) == "#"){
9265 for(var i = 1; i < 4; i++){
9266 var c = v.charAt(i);
9269 }else if(v.length == 7){
9270 color += v.substr(1);
9274 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9278 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9279 * gradient background, rounded corners and a 4-way shadow.
9280 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9281 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9282 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9283 * @return {Roo.Element} this
9285 boxWrap : function(cls){
9286 cls = cls || 'x-box';
9287 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9288 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9293 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9294 * @param {String} namespace The namespace in which to look for the attribute
9295 * @param {String} name The attribute name
9296 * @return {String} The attribute value
9298 getAttributeNS : Roo.isIE ? function(ns, name){
9300 var type = typeof d[ns+":"+name];
9301 if(type != 'undefined' && type != 'unknown'){
9302 return d[ns+":"+name];
9305 } : function(ns, name){
9307 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9311 var ep = El.prototype;
9314 * Appends an event handler (Shorthand for addListener)
9315 * @param {String} eventName The type of event to append
9316 * @param {Function} fn The method the event invokes
9317 * @param {Object} scope (optional) The scope (this object) of the fn
9318 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9321 ep.on = ep.addListener;
9323 ep.mon = ep.addListener;
9326 * Removes an event handler from this element (shorthand for removeListener)
9327 * @param {String} eventName the type of event to remove
9328 * @param {Function} fn the method the event invokes
9329 * @return {Roo.Element} this
9332 ep.un = ep.removeListener;
9335 * true to automatically adjust width and height settings for box-model issues (default to true)
9337 ep.autoBoxAdjust = true;
9340 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9343 El.addUnits = function(v, defaultUnit){
9344 if(v === "" || v == "auto"){
9347 if(v === undefined){
9350 if(typeof v == "number" || !El.unitPattern.test(v)){
9351 return v + (defaultUnit || 'px');
9356 // special markup used throughout Roo when box wrapping elements
9357 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>';
9359 * Visibility mode constant - Use visibility to hide element
9365 * Visibility mode constant - Use display to hide element
9371 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9372 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9373 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9385 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9386 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9387 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9388 * @return {Element} The Element object
9391 El.get = function(el){
9393 if(!el){ return null; }
9394 if(typeof el == "string"){ // element id
9395 if(!(elm = document.getElementById(el))){
9398 if(ex = El.cache[el]){
9401 ex = El.cache[el] = new El(elm);
9404 }else if(el.tagName){ // dom element
9408 if(ex = El.cache[id]){
9411 ex = El.cache[id] = new El(el);
9414 }else if(el instanceof El){
9416 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9417 // catch case where it hasn't been appended
9418 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9421 }else if(el.isComposite){
9423 }else if(el instanceof Array){
9424 return El.select(el);
9425 }else if(el == document){
9426 // create a bogus element object representing the document object
9428 var f = function(){};
9429 f.prototype = El.prototype;
9431 docEl.dom = document;
9439 El.uncache = function(el){
9440 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9442 delete El.cache[a[i].id || a[i]];
9448 // Garbage collection - uncache elements/purge listeners on orphaned elements
9449 // so we don't hold a reference and cause the browser to retain them
9450 El.garbageCollect = function(){
9451 if(!Roo.enableGarbageCollector){
9452 clearInterval(El.collectorThread);
9455 for(var eid in El.cache){
9456 var el = El.cache[eid], d = el.dom;
9457 // -------------------------------------------------------
9458 // Determining what is garbage:
9459 // -------------------------------------------------------
9461 // dom node is null, definitely garbage
9462 // -------------------------------------------------------
9464 // no parentNode == direct orphan, definitely garbage
9465 // -------------------------------------------------------
9466 // !d.offsetParent && !document.getElementById(eid)
9467 // display none elements have no offsetParent so we will
9468 // also try to look it up by it's id. However, check
9469 // offsetParent first so we don't do unneeded lookups.
9470 // This enables collection of elements that are not orphans
9471 // directly, but somewhere up the line they have an orphan
9473 // -------------------------------------------------------
9474 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9475 delete El.cache[eid];
9476 if(d && Roo.enableListenerCollection){
9482 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9486 El.Flyweight = function(dom){
9489 El.Flyweight.prototype = El.prototype;
9491 El._flyweights = {};
9493 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9494 * the dom node can be overwritten by other code.
9495 * @param {String/HTMLElement} el The dom node or id
9496 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9497 * prevent conflicts (e.g. internally Roo uses "_internal")
9499 * @return {Element} The shared Element object
9501 El.fly = function(el, named){
9502 named = named || '_global';
9503 el = Roo.getDom(el);
9507 if(!El._flyweights[named]){
9508 El._flyweights[named] = new El.Flyweight();
9510 El._flyweights[named].dom = el;
9511 return El._flyweights[named];
9515 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9516 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9517 * Shorthand of {@link Roo.Element#get}
9518 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9519 * @return {Element} The Element object
9525 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9526 * the dom node can be overwritten by other code.
9527 * Shorthand of {@link Roo.Element#fly}
9528 * @param {String/HTMLElement} el The dom node or id
9529 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9530 * prevent conflicts (e.g. internally Roo uses "_internal")
9532 * @return {Element} The shared Element object
9538 // speedy lookup for elements never to box adjust
9539 var noBoxAdjust = Roo.isStrict ? {
9542 input:1, select:1, textarea:1
9544 if(Roo.isIE || Roo.isGecko){
9545 noBoxAdjust['button'] = 1;
9549 Roo.EventManager.on(window, 'unload', function(){
9551 delete El._flyweights;
9559 Roo.Element.selectorFunction = Roo.DomQuery.select;
9562 Roo.Element.select = function(selector, unique, root){
9564 if(typeof selector == "string"){
9565 els = Roo.Element.selectorFunction(selector, root);
9566 }else if(selector.length !== undefined){
9569 throw "Invalid selector";
9571 if(unique === true){
9572 return new Roo.CompositeElement(els);
9574 return new Roo.CompositeElementLite(els);
9578 * Selects elements based on the passed CSS selector to enable working on them as 1.
9579 * @param {String/Array} selector The CSS selector or an array of elements
9580 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9581 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9582 * @return {CompositeElementLite/CompositeElement}
9586 Roo.select = Roo.Element.select;
9603 * Ext JS Library 1.1.1
9604 * Copyright(c) 2006-2007, Ext JS, LLC.
9606 * Originally Released Under LGPL - original licence link has changed is not relivant.
9609 * <script type="text/javascript">
9614 //Notifies Element that fx methods are available
9615 Roo.enableFx = true;
9619 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9620 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9621 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9622 * Element effects to work.</p><br/>
9624 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9625 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9626 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9627 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9628 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9629 * expected results and should be done with care.</p><br/>
9631 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9632 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9635 ----- -----------------------------
9636 tl The top left corner
9637 t The center of the top edge
9638 tr The top right corner
9639 l The center of the left edge
9640 r The center of the right edge
9641 bl The bottom left corner
9642 b The center of the bottom edge
9643 br The bottom right corner
9645 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9646 * below are common options that can be passed to any Fx method.</b>
9647 * @cfg {Function} callback A function called when the effect is finished
9648 * @cfg {Object} scope The scope of the effect function
9649 * @cfg {String} easing A valid Easing value for the effect
9650 * @cfg {String} afterCls A css class to apply after the effect
9651 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9652 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9653 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9654 * effects that end with the element being visually hidden, ignored otherwise)
9655 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9656 * a function which returns such a specification that will be applied to the Element after the effect finishes
9657 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9658 * @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
9659 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9663 * Slides the element into view. An anchor point can be optionally passed to set the point of
9664 * origin for the slide effect. This function automatically handles wrapping the element with
9665 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9668 // default: slide the element in from the top
9671 // custom: slide the element in from the right with a 2-second duration
9672 el.slideIn('r', { duration: 2 });
9674 // common config options shown with default values
9680 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9681 * @param {Object} options (optional) Object literal with any of the Fx config options
9682 * @return {Roo.Element} The Element
9684 slideIn : function(anchor, o){
9685 var el = this.getFxEl();
9688 el.queueFx(o, function(){
9690 anchor = anchor || "t";
9692 // fix display to visibility
9695 // restore values after effect
9696 var r = this.getFxRestore();
9697 var b = this.getBox();
9698 // fixed size for slide
9702 var wrap = this.fxWrap(r.pos, o, "hidden");
9704 var st = this.dom.style;
9705 st.visibility = "visible";
9706 st.position = "absolute";
9708 // clear out temp styles after slide and unwrap
9709 var after = function(){
9710 el.fxUnwrap(wrap, r.pos, o);
9712 st.height = r.height;
9715 // time to calc the positions
9716 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9718 switch(anchor.toLowerCase()){
9720 wrap.setSize(b.width, 0);
9721 st.left = st.bottom = "0";
9725 wrap.setSize(0, b.height);
9726 st.right = st.top = "0";
9730 wrap.setSize(0, b.height);
9732 st.left = st.top = "0";
9733 a = {width: bw, points: pt};
9736 wrap.setSize(b.width, 0);
9737 wrap.setY(b.bottom);
9738 st.left = st.top = "0";
9739 a = {height: bh, points: pt};
9743 st.right = st.bottom = "0";
9744 a = {width: bw, height: bh};
9748 wrap.setY(b.y+b.height);
9749 st.right = st.top = "0";
9750 a = {width: bw, height: bh, points: pt};
9754 wrap.setXY([b.right, b.bottom]);
9755 st.left = st.top = "0";
9756 a = {width: bw, height: bh, points: pt};
9760 wrap.setX(b.x+b.width);
9761 st.left = st.bottom = "0";
9762 a = {width: bw, height: bh, points: pt};
9765 this.dom.style.visibility = "visible";
9768 arguments.callee.anim = wrap.fxanim(a,
9778 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9779 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9780 * 'hidden') but block elements will still take up space in the document. The element must be removed
9781 * from the DOM using the 'remove' config option if desired. This function automatically handles
9782 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9785 // default: slide the element out to the top
9788 // custom: slide the element out to the right with a 2-second duration
9789 el.slideOut('r', { duration: 2 });
9791 // common config options shown with default values
9799 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9800 * @param {Object} options (optional) Object literal with any of the Fx config options
9801 * @return {Roo.Element} The Element
9803 slideOut : function(anchor, o){
9804 var el = this.getFxEl();
9807 el.queueFx(o, function(){
9809 anchor = anchor || "t";
9811 // restore values after effect
9812 var r = this.getFxRestore();
9814 var b = this.getBox();
9815 // fixed size for slide
9819 var wrap = this.fxWrap(r.pos, o, "visible");
9821 var st = this.dom.style;
9822 st.visibility = "visible";
9823 st.position = "absolute";
9827 var after = function(){
9829 el.setDisplayed(false);
9834 el.fxUnwrap(wrap, r.pos, o);
9837 st.height = r.height;
9842 var a, zero = {to: 0};
9843 switch(anchor.toLowerCase()){
9845 st.left = st.bottom = "0";
9849 st.right = st.top = "0";
9853 st.left = st.top = "0";
9854 a = {width: zero, points: {to:[b.right, b.y]}};
9857 st.left = st.top = "0";
9858 a = {height: zero, points: {to:[b.x, b.bottom]}};
9861 st.right = st.bottom = "0";
9862 a = {width: zero, height: zero};
9865 st.right = st.top = "0";
9866 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9869 st.left = st.top = "0";
9870 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9873 st.left = st.bottom = "0";
9874 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9878 arguments.callee.anim = wrap.fxanim(a,
9888 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
9889 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
9890 * The element must be removed from the DOM using the 'remove' config option if desired.
9896 // common config options shown with default values
9904 * @param {Object} options (optional) Object literal with any of the Fx config options
9905 * @return {Roo.Element} The Element
9908 var el = this.getFxEl();
9911 el.queueFx(o, function(){
9912 this.clearOpacity();
9915 // restore values after effect
9916 var r = this.getFxRestore();
9917 var st = this.dom.style;
9919 var after = function(){
9921 el.setDisplayed(false);
9928 el.setPositioning(r.pos);
9930 st.height = r.height;
9935 var width = this.getWidth();
9936 var height = this.getHeight();
9938 arguments.callee.anim = this.fxanim({
9939 width : {to: this.adjustWidth(width * 2)},
9940 height : {to: this.adjustHeight(height * 2)},
9941 points : {by: [-(width * .5), -(height * .5)]},
9943 fontSize: {to:200, unit: "%"}
9954 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9955 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
9956 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9962 // all config options shown with default values
9970 * @param {Object} options (optional) Object literal with any of the Fx config options
9971 * @return {Roo.Element} The Element
9973 switchOff : function(o){
9974 var el = this.getFxEl();
9977 el.queueFx(o, function(){
9978 this.clearOpacity();
9981 // restore values after effect
9982 var r = this.getFxRestore();
9983 var st = this.dom.style;
9985 var after = function(){
9987 el.setDisplayed(false);
9993 el.setPositioning(r.pos);
9995 st.height = r.height;
10000 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10001 this.clearOpacity();
10005 points:{by:[0, this.getHeight() * .5]}
10006 }, o, 'motion', 0.3, 'easeIn', after);
10007 }).defer(100, this);
10014 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10015 * changed using the "attr" config option) and then fading back to the original color. If no original
10016 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10019 // default: highlight background to yellow
10022 // custom: highlight foreground text to blue for 2 seconds
10023 el.highlight("0000ff", { attr: 'color', duration: 2 });
10025 // common config options shown with default values
10026 el.highlight("ffff9c", {
10027 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10028 endColor: (current color) or "ffffff",
10033 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10034 * @param {Object} options (optional) Object literal with any of the Fx config options
10035 * @return {Roo.Element} The Element
10037 highlight : function(color, o){
10038 var el = this.getFxEl();
10041 el.queueFx(o, function(){
10042 color = color || "ffff9c";
10043 attr = o.attr || "backgroundColor";
10045 this.clearOpacity();
10048 var origColor = this.getColor(attr);
10049 var restoreColor = this.dom.style[attr];
10050 endColor = (o.endColor || origColor) || "ffffff";
10052 var after = function(){
10053 el.dom.style[attr] = restoreColor;
10058 a[attr] = {from: color, to: endColor};
10059 arguments.callee.anim = this.fxanim(a,
10069 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10072 // default: a single light blue ripple
10075 // custom: 3 red ripples lasting 3 seconds total
10076 el.frame("ff0000", 3, { duration: 3 });
10078 // common config options shown with default values
10079 el.frame("C3DAF9", 1, {
10080 duration: 1 //duration of entire animation (not each individual ripple)
10081 // Note: Easing is not configurable and will be ignored if included
10084 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10085 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10086 * @param {Object} options (optional) Object literal with any of the Fx config options
10087 * @return {Roo.Element} The Element
10089 frame : function(color, count, o){
10090 var el = this.getFxEl();
10093 el.queueFx(o, function(){
10094 color = color || "#C3DAF9";
10095 if(color.length == 6){
10096 color = "#" + color;
10098 count = count || 1;
10099 duration = o.duration || 1;
10102 var b = this.getBox();
10103 var animFn = function(){
10104 var proxy = this.createProxy({
10107 visbility:"hidden",
10108 position:"absolute",
10109 "z-index":"35000", // yee haw
10110 border:"0px solid " + color
10113 var scale = Roo.isBorderBox ? 2 : 1;
10115 top:{from:b.y, to:b.y - 20},
10116 left:{from:b.x, to:b.x - 20},
10117 borderWidth:{from:0, to:10},
10118 opacity:{from:1, to:0},
10119 height:{from:b.height, to:(b.height + (20*scale))},
10120 width:{from:b.width, to:(b.width + (20*scale))}
10121 }, duration, function(){
10125 animFn.defer((duration/2)*1000, this);
10136 * Creates a pause before any subsequent queued effects begin. If there are
10137 * no effects queued after the pause it will have no effect.
10142 * @param {Number} seconds The length of time to pause (in seconds)
10143 * @return {Roo.Element} The Element
10145 pause : function(seconds){
10146 var el = this.getFxEl();
10149 el.queueFx(o, function(){
10150 setTimeout(function(){
10152 }, seconds * 1000);
10158 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10159 * using the "endOpacity" config option.
10162 // default: fade in from opacity 0 to 100%
10165 // custom: fade in from opacity 0 to 75% over 2 seconds
10166 el.fadeIn({ endOpacity: .75, duration: 2});
10168 // common config options shown with default values
10170 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10175 * @param {Object} options (optional) Object literal with any of the Fx config options
10176 * @return {Roo.Element} The Element
10178 fadeIn : function(o){
10179 var el = this.getFxEl();
10181 el.queueFx(o, function(){
10182 this.setOpacity(0);
10184 this.dom.style.visibility = 'visible';
10185 var to = o.endOpacity || 1;
10186 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10187 o, null, .5, "easeOut", function(){
10189 this.clearOpacity();
10198 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10199 * using the "endOpacity" config option.
10202 // default: fade out from the element's current opacity to 0
10205 // custom: fade out from the element's current opacity to 25% over 2 seconds
10206 el.fadeOut({ endOpacity: .25, duration: 2});
10208 // common config options shown with default values
10210 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10217 * @param {Object} options (optional) Object literal with any of the Fx config options
10218 * @return {Roo.Element} The Element
10220 fadeOut : function(o){
10221 var el = this.getFxEl();
10223 el.queueFx(o, function(){
10224 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10225 o, null, .5, "easeOut", function(){
10226 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10227 this.dom.style.display = "none";
10229 this.dom.style.visibility = "hidden";
10231 this.clearOpacity();
10239 * Animates the transition of an element's dimensions from a starting height/width
10240 * to an ending height/width.
10243 // change height and width to 100x100 pixels
10244 el.scale(100, 100);
10246 // common config options shown with default values. The height and width will default to
10247 // the element's existing values if passed as null.
10250 [element's height], {
10255 * @param {Number} width The new width (pass undefined to keep the original width)
10256 * @param {Number} height The new height (pass undefined to keep the original height)
10257 * @param {Object} options (optional) Object literal with any of the Fx config options
10258 * @return {Roo.Element} The Element
10260 scale : function(w, h, o){
10261 this.shift(Roo.apply({}, o, {
10269 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10270 * Any of these properties not specified in the config object will not be changed. This effect
10271 * requires that at least one new dimension, position or opacity setting must be passed in on
10272 * the config object in order for the function to have any effect.
10275 // slide the element horizontally to x position 200 while changing the height and opacity
10276 el.shift({ x: 200, height: 50, opacity: .8 });
10278 // common config options shown with default values.
10280 width: [element's width],
10281 height: [element's height],
10282 x: [element's x position],
10283 y: [element's y position],
10284 opacity: [element's opacity],
10289 * @param {Object} options Object literal with any of the Fx config options
10290 * @return {Roo.Element} The Element
10292 shift : function(o){
10293 var el = this.getFxEl();
10295 el.queueFx(o, function(){
10296 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10297 if(w !== undefined){
10298 a.width = {to: this.adjustWidth(w)};
10300 if(h !== undefined){
10301 a.height = {to: this.adjustHeight(h)};
10303 if(x !== undefined || y !== undefined){
10305 x !== undefined ? x : this.getX(),
10306 y !== undefined ? y : this.getY()
10309 if(op !== undefined){
10310 a.opacity = {to: op};
10312 if(o.xy !== undefined){
10313 a.points = {to: o.xy};
10315 arguments.callee.anim = this.fxanim(a,
10316 o, 'motion', .35, "easeOut", function(){
10324 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10325 * ending point of the effect.
10328 // default: slide the element downward while fading out
10331 // custom: slide the element out to the right with a 2-second duration
10332 el.ghost('r', { duration: 2 });
10334 // common config options shown with default values
10342 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10343 * @param {Object} options (optional) Object literal with any of the Fx config options
10344 * @return {Roo.Element} The Element
10346 ghost : function(anchor, o){
10347 var el = this.getFxEl();
10350 el.queueFx(o, function(){
10351 anchor = anchor || "b";
10353 // restore values after effect
10354 var r = this.getFxRestore();
10355 var w = this.getWidth(),
10356 h = this.getHeight();
10358 var st = this.dom.style;
10360 var after = function(){
10362 el.setDisplayed(false);
10368 el.setPositioning(r.pos);
10369 st.width = r.width;
10370 st.height = r.height;
10375 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10376 switch(anchor.toLowerCase()){
10403 arguments.callee.anim = this.fxanim(a,
10413 * Ensures that all effects queued after syncFx is called on the element are
10414 * run concurrently. This is the opposite of {@link #sequenceFx}.
10415 * @return {Roo.Element} The Element
10417 syncFx : function(){
10418 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10427 * Ensures that all effects queued after sequenceFx is called on the element are
10428 * run in sequence. This is the opposite of {@link #syncFx}.
10429 * @return {Roo.Element} The Element
10431 sequenceFx : function(){
10432 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10434 concurrent : false,
10441 nextFx : function(){
10442 var ef = this.fxQueue[0];
10449 * Returns true if the element has any effects actively running or queued, else returns false.
10450 * @return {Boolean} True if element has active effects, else false
10452 hasActiveFx : function(){
10453 return this.fxQueue && this.fxQueue[0];
10457 * Stops any running effects and clears the element's internal effects queue if it contains
10458 * any additional effects that haven't started yet.
10459 * @return {Roo.Element} The Element
10461 stopFx : function(){
10462 if(this.hasActiveFx()){
10463 var cur = this.fxQueue[0];
10464 if(cur && cur.anim && cur.anim.isAnimated()){
10465 this.fxQueue = [cur]; // clear out others
10466 cur.anim.stop(true);
10473 beforeFx : function(o){
10474 if(this.hasActiveFx() && !o.concurrent){
10485 * Returns true if the element is currently blocking so that no other effect can be queued
10486 * until this effect is finished, else returns false if blocking is not set. This is commonly
10487 * used to ensure that an effect initiated by a user action runs to completion prior to the
10488 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10489 * @return {Boolean} True if blocking, else false
10491 hasFxBlock : function(){
10492 var q = this.fxQueue;
10493 return q && q[0] && q[0].block;
10497 queueFx : function(o, fn){
10501 if(!this.hasFxBlock()){
10502 Roo.applyIf(o, this.fxDefaults);
10504 var run = this.beforeFx(o);
10505 fn.block = o.block;
10506 this.fxQueue.push(fn);
10518 fxWrap : function(pos, o, vis){
10520 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10523 wrapXY = this.getXY();
10525 var div = document.createElement("div");
10526 div.style.visibility = vis;
10527 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10528 wrap.setPositioning(pos);
10529 if(wrap.getStyle("position") == "static"){
10530 wrap.position("relative");
10532 this.clearPositioning('auto');
10534 wrap.dom.appendChild(this.dom);
10536 wrap.setXY(wrapXY);
10543 fxUnwrap : function(wrap, pos, o){
10544 this.clearPositioning();
10545 this.setPositioning(pos);
10547 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10553 getFxRestore : function(){
10554 var st = this.dom.style;
10555 return {pos: this.getPositioning(), width: st.width, height : st.height};
10559 afterFx : function(o){
10561 this.applyStyles(o.afterStyle);
10564 this.addClass(o.afterCls);
10566 if(o.remove === true){
10569 Roo.callback(o.callback, o.scope, [this]);
10571 this.fxQueue.shift();
10577 getFxEl : function(){ // support for composite element fx
10578 return Roo.get(this.dom);
10582 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10583 animType = animType || 'run';
10585 var anim = Roo.lib.Anim[animType](
10587 (opt.duration || defaultDur) || .35,
10588 (opt.easing || defaultEase) || 'easeOut',
10590 Roo.callback(cb, this);
10599 // backwords compat
10600 Roo.Fx.resize = Roo.Fx.scale;
10602 //When included, Roo.Fx is automatically applied to Element so that all basic
10603 //effects are available directly via the Element API
10604 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10606 * Ext JS Library 1.1.1
10607 * Copyright(c) 2006-2007, Ext JS, LLC.
10609 * Originally Released Under LGPL - original licence link has changed is not relivant.
10612 * <script type="text/javascript">
10617 * @class Roo.CompositeElement
10618 * Standard composite class. Creates a Roo.Element for every element in the collection.
10620 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10621 * actions will be performed on all the elements in this collection.</b>
10623 * All methods return <i>this</i> and can be chained.
10625 var els = Roo.select("#some-el div.some-class", true);
10626 // or select directly from an existing element
10627 var el = Roo.get('some-el');
10628 el.select('div.some-class', true);
10630 els.setWidth(100); // all elements become 100 width
10631 els.hide(true); // all elements fade out and hide
10633 els.setWidth(100).hide(true);
10636 Roo.CompositeElement = function(els){
10637 this.elements = [];
10638 this.addElements(els);
10640 Roo.CompositeElement.prototype = {
10642 addElements : function(els){
10643 if(!els) return this;
10644 if(typeof els == "string"){
10645 els = Roo.Element.selectorFunction(els);
10647 var yels = this.elements;
10648 var index = yels.length-1;
10649 for(var i = 0, len = els.length; i < len; i++) {
10650 yels[++index] = Roo.get(els[i]);
10656 * Clears this composite and adds the elements returned by the passed selector.
10657 * @param {String/Array} els A string CSS selector, an array of elements or an element
10658 * @return {CompositeElement} this
10660 fill : function(els){
10661 this.elements = [];
10667 * Filters this composite to only elements that match the passed selector.
10668 * @param {String} selector A string CSS selector
10669 * @return {CompositeElement} this
10671 filter : function(selector){
10673 this.each(function(el){
10674 if(el.is(selector)){
10675 els[els.length] = el.dom;
10682 invoke : function(fn, args){
10683 var els = this.elements;
10684 for(var i = 0, len = els.length; i < len; i++) {
10685 Roo.Element.prototype[fn].apply(els[i], args);
10690 * Adds elements to this composite.
10691 * @param {String/Array} els A string CSS selector, an array of elements or an element
10692 * @return {CompositeElement} this
10694 add : function(els){
10695 if(typeof els == "string"){
10696 this.addElements(Roo.Element.selectorFunction(els));
10697 }else if(els.length !== undefined){
10698 this.addElements(els);
10700 this.addElements([els]);
10705 * Calls the passed function passing (el, this, index) for each element in this composite.
10706 * @param {Function} fn The function to call
10707 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10708 * @return {CompositeElement} this
10710 each : function(fn, scope){
10711 var els = this.elements;
10712 for(var i = 0, len = els.length; i < len; i++){
10713 if(fn.call(scope || els[i], els[i], this, i) === false) {
10721 * Returns the Element object at the specified index
10722 * @param {Number} index
10723 * @return {Roo.Element}
10725 item : function(index){
10726 return this.elements[index] || null;
10730 * Returns the first Element
10731 * @return {Roo.Element}
10733 first : function(){
10734 return this.item(0);
10738 * Returns the last Element
10739 * @return {Roo.Element}
10742 return this.item(this.elements.length-1);
10746 * Returns the number of elements in this composite
10749 getCount : function(){
10750 return this.elements.length;
10754 * Returns true if this composite contains the passed element
10757 contains : function(el){
10758 return this.indexOf(el) !== -1;
10762 * Returns true if this composite contains the passed element
10765 indexOf : function(el){
10766 return this.elements.indexOf(Roo.get(el));
10771 * Removes the specified element(s).
10772 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10773 * or an array of any of those.
10774 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10775 * @return {CompositeElement} this
10777 removeElement : function(el, removeDom){
10778 if(el instanceof Array){
10779 for(var i = 0, len = el.length; i < len; i++){
10780 this.removeElement(el[i]);
10784 var index = typeof el == 'number' ? el : this.indexOf(el);
10787 var d = this.elements[index];
10791 d.parentNode.removeChild(d);
10794 this.elements.splice(index, 1);
10800 * Replaces the specified element with the passed element.
10801 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10803 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10804 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10805 * @return {CompositeElement} this
10807 replaceElement : function(el, replacement, domReplace){
10808 var index = typeof el == 'number' ? el : this.indexOf(el);
10811 this.elements[index].replaceWith(replacement);
10813 this.elements.splice(index, 1, Roo.get(replacement))
10820 * Removes all elements.
10822 clear : function(){
10823 this.elements = [];
10827 Roo.CompositeElement.createCall = function(proto, fnName){
10828 if(!proto[fnName]){
10829 proto[fnName] = function(){
10830 return this.invoke(fnName, arguments);
10834 for(var fnName in Roo.Element.prototype){
10835 if(typeof Roo.Element.prototype[fnName] == "function"){
10836 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10842 * Ext JS Library 1.1.1
10843 * Copyright(c) 2006-2007, Ext JS, LLC.
10845 * Originally Released Under LGPL - original licence link has changed is not relivant.
10848 * <script type="text/javascript">
10852 * @class Roo.CompositeElementLite
10853 * @extends Roo.CompositeElement
10854 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10856 var els = Roo.select("#some-el div.some-class");
10857 // or select directly from an existing element
10858 var el = Roo.get('some-el');
10859 el.select('div.some-class');
10861 els.setWidth(100); // all elements become 100 width
10862 els.hide(true); // all elements fade out and hide
10864 els.setWidth(100).hide(true);
10865 </code></pre><br><br>
10866 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10867 * actions will be performed on all the elements in this collection.</b>
10869 Roo.CompositeElementLite = function(els){
10870 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10871 this.el = new Roo.Element.Flyweight();
10873 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10874 addElements : function(els){
10876 if(els instanceof Array){
10877 this.elements = this.elements.concat(els);
10879 var yels = this.elements;
10880 var index = yels.length-1;
10881 for(var i = 0, len = els.length; i < len; i++) {
10882 yels[++index] = els[i];
10888 invoke : function(fn, args){
10889 var els = this.elements;
10891 for(var i = 0, len = els.length; i < len; i++) {
10893 Roo.Element.prototype[fn].apply(el, args);
10898 * Returns a flyweight Element of the dom element object at the specified index
10899 * @param {Number} index
10900 * @return {Roo.Element}
10902 item : function(index){
10903 if(!this.elements[index]){
10906 this.el.dom = this.elements[index];
10910 // fixes scope with flyweight
10911 addListener : function(eventName, handler, scope, opt){
10912 var els = this.elements;
10913 for(var i = 0, len = els.length; i < len; i++) {
10914 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10920 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10921 * passed is the flyweight (shared) Roo.Element instance, so if you require a
10922 * a reference to the dom node, use el.dom.</b>
10923 * @param {Function} fn The function to call
10924 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10925 * @return {CompositeElement} this
10927 each : function(fn, scope){
10928 var els = this.elements;
10930 for(var i = 0, len = els.length; i < len; i++){
10932 if(fn.call(scope || el, el, this, i) === false){
10939 indexOf : function(el){
10940 return this.elements.indexOf(Roo.getDom(el));
10943 replaceElement : function(el, replacement, domReplace){
10944 var index = typeof el == 'number' ? el : this.indexOf(el);
10946 replacement = Roo.getDom(replacement);
10948 var d = this.elements[index];
10949 d.parentNode.insertBefore(replacement, d);
10950 d.parentNode.removeChild(d);
10952 this.elements.splice(index, 1, replacement);
10957 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10961 * Ext JS Library 1.1.1
10962 * Copyright(c) 2006-2007, Ext JS, LLC.
10964 * Originally Released Under LGPL - original licence link has changed is not relivant.
10967 * <script type="text/javascript">
10973 * @class Roo.data.Connection
10974 * @extends Roo.util.Observable
10975 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
10976 * either to a configured URL, or to a URL specified at request time.<br><br>
10978 * Requests made by this class are asynchronous, and will return immediately. No data from
10979 * the server will be available to the statement immediately following the {@link #request} call.
10980 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
10982 * Note: If you are doing a file upload, you will not get a normal response object sent back to
10983 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
10984 * The response object is created using the innerHTML of the IFRAME's document as the responseText
10985 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
10986 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
10987 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
10988 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
10989 * standard DOM methods.
10991 * @param {Object} config a configuration object.
10993 Roo.data.Connection = function(config){
10994 Roo.apply(this, config);
10997 * @event beforerequest
10998 * Fires before a network request is made to retrieve a data object.
10999 * @param {Connection} conn This Connection object.
11000 * @param {Object} options The options config object passed to the {@link #request} method.
11002 "beforerequest" : true,
11004 * @event requestcomplete
11005 * Fires if the request was successfully completed.
11006 * @param {Connection} conn This Connection object.
11007 * @param {Object} response The XHR object containing the response data.
11008 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11009 * @param {Object} options The options config object passed to the {@link #request} method.
11011 "requestcomplete" : true,
11013 * @event requestexception
11014 * Fires if an error HTTP status was returned from the server.
11015 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11016 * @param {Connection} conn This Connection object.
11017 * @param {Object} response The XHR object containing the response data.
11018 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11019 * @param {Object} options The options config object passed to the {@link #request} method.
11021 "requestexception" : true
11023 Roo.data.Connection.superclass.constructor.call(this);
11026 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11028 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11031 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11032 * extra parameters to each request made by this object. (defaults to undefined)
11035 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11036 * to each request made by this object. (defaults to undefined)
11039 * @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)
11042 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11046 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11052 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11055 disableCaching: true,
11058 * Sends an HTTP request to a remote server.
11059 * @param {Object} options An object which may contain the following properties:<ul>
11060 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11061 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11062 * request, a url encoded string or a function to call to get either.</li>
11063 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11064 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11065 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11066 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11067 * <li>options {Object} The parameter to the request call.</li>
11068 * <li>success {Boolean} True if the request succeeded.</li>
11069 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11071 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11072 * The callback is passed the following parameters:<ul>
11073 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11074 * <li>options {Object} The parameter to the request call.</li>
11076 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11077 * The callback is passed the following parameters:<ul>
11078 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11079 * <li>options {Object} The parameter to the request call.</li>
11081 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11082 * for the callback function. Defaults to the browser window.</li>
11083 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11084 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11085 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11086 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11087 * params for the post data. Any params will be appended to the URL.</li>
11088 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11090 * @return {Number} transactionId
11092 request : function(o){
11093 if(this.fireEvent("beforerequest", this, o) !== false){
11096 if(typeof p == "function"){
11097 p = p.call(o.scope||window, o);
11099 if(typeof p == "object"){
11100 p = Roo.urlEncode(o.params);
11102 if(this.extraParams){
11103 var extras = Roo.urlEncode(this.extraParams);
11104 p = p ? (p + '&' + extras) : extras;
11107 var url = o.url || this.url;
11108 if(typeof url == 'function'){
11109 url = url.call(o.scope||window, o);
11113 var form = Roo.getDom(o.form);
11114 url = url || form.action;
11116 var enctype = form.getAttribute("enctype");
11117 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11118 return this.doFormUpload(o, p, url);
11120 var f = Roo.lib.Ajax.serializeForm(form);
11121 p = p ? (p + '&' + f) : f;
11124 var hs = o.headers;
11125 if(this.defaultHeaders){
11126 hs = Roo.apply(hs || {}, this.defaultHeaders);
11133 success: this.handleResponse,
11134 failure: this.handleFailure,
11136 argument: {options: o},
11137 timeout : this.timeout
11140 var method = o.method||this.method||(p ? "POST" : "GET");
11142 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11143 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11146 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11150 }else if(this.autoAbort !== false){
11154 if((method == 'GET' && p) || o.xmlData){
11155 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11158 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11159 return this.transId;
11161 Roo.callback(o.callback, o.scope, [o, null, null]);
11167 * Determine whether this object has a request outstanding.
11168 * @param {Number} transactionId (Optional) defaults to the last transaction
11169 * @return {Boolean} True if there is an outstanding request.
11171 isLoading : function(transId){
11173 return Roo.lib.Ajax.isCallInProgress(transId);
11175 return this.transId ? true : false;
11180 * Aborts any outstanding request.
11181 * @param {Number} transactionId (Optional) defaults to the last transaction
11183 abort : function(transId){
11184 if(transId || this.isLoading()){
11185 Roo.lib.Ajax.abort(transId || this.transId);
11190 handleResponse : function(response){
11191 this.transId = false;
11192 var options = response.argument.options;
11193 response.argument = options ? options.argument : null;
11194 this.fireEvent("requestcomplete", this, response, options);
11195 Roo.callback(options.success, options.scope, [response, options]);
11196 Roo.callback(options.callback, options.scope, [options, true, response]);
11200 handleFailure : function(response, e){
11201 this.transId = false;
11202 var options = response.argument.options;
11203 response.argument = options ? options.argument : null;
11204 this.fireEvent("requestexception", this, response, options, e);
11205 Roo.callback(options.failure, options.scope, [response, options]);
11206 Roo.callback(options.callback, options.scope, [options, false, response]);
11210 doFormUpload : function(o, ps, url){
11212 var frame = document.createElement('iframe');
11215 frame.className = 'x-hidden';
11217 frame.src = Roo.SSL_SECURE_URL;
11219 document.body.appendChild(frame);
11222 document.frames[id].name = id;
11225 var form = Roo.getDom(o.form);
11227 form.method = 'POST';
11228 form.enctype = form.encoding = 'multipart/form-data';
11234 if(ps){ // add dynamic params
11236 ps = Roo.urlDecode(ps, false);
11238 if(ps.hasOwnProperty(k)){
11239 hd = document.createElement('input');
11240 hd.type = 'hidden';
11243 form.appendChild(hd);
11250 var r = { // bogus response object
11255 r.argument = o ? o.argument : null;
11260 doc = frame.contentWindow.document;
11262 doc = (frame.contentDocument || window.frames[id].document);
11264 if(doc && doc.body){
11265 r.responseText = doc.body.innerHTML;
11267 if(doc && doc.XMLDocument){
11268 r.responseXML = doc.XMLDocument;
11270 r.responseXML = doc;
11277 Roo.EventManager.removeListener(frame, 'load', cb, this);
11279 this.fireEvent("requestcomplete", this, r, o);
11280 Roo.callback(o.success, o.scope, [r, o]);
11281 Roo.callback(o.callback, o.scope, [o, true, r]);
11283 setTimeout(function(){document.body.removeChild(frame);}, 100);
11286 Roo.EventManager.on(frame, 'load', cb, this);
11289 if(hiddens){ // remove dynamic params
11290 for(var i = 0, len = hiddens.length; i < len; i++){
11291 form.removeChild(hiddens[i]);
11299 * @extends Roo.data.Connection
11300 * Global Ajax request class.
11304 Roo.Ajax = new Roo.data.Connection({
11307 * @cfg {String} url @hide
11310 * @cfg {Object} extraParams @hide
11313 * @cfg {Object} defaultHeaders @hide
11316 * @cfg {String} method (Optional) @hide
11319 * @cfg {Number} timeout (Optional) @hide
11322 * @cfg {Boolean} autoAbort (Optional) @hide
11326 * @cfg {Boolean} disableCaching (Optional) @hide
11330 * @property disableCaching
11331 * True to add a unique cache-buster param to GET requests. (defaults to true)
11336 * The default URL to be used for requests to the server. (defaults to undefined)
11340 * @property extraParams
11341 * An object containing properties which are used as
11342 * extra parameters to each request made by this object. (defaults to undefined)
11346 * @property defaultHeaders
11347 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11352 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11356 * @property timeout
11357 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11362 * @property autoAbort
11363 * Whether a new request should abort any pending requests. (defaults to false)
11369 * Serialize the passed form into a url encoded string
11370 * @param {String/HTMLElement} form
11373 serializeForm : function(form){
11374 return Roo.lib.Ajax.serializeForm(form);
11378 * Ext JS Library 1.1.1
11379 * Copyright(c) 2006-2007, Ext JS, LLC.
11381 * Originally Released Under LGPL - original licence link has changed is not relivant.
11384 * <script type="text/javascript">
11389 * @extends Roo.data.Connection
11390 * Global Ajax request class.
11392 * @instanceOf Roo.data.Connection
11394 Roo.Ajax = new Roo.data.Connection({
11403 * @cfg {String} url @hide
11406 * @cfg {Object} extraParams @hide
11409 * @cfg {Object} defaultHeaders @hide
11412 * @cfg {String} method (Optional) @hide
11415 * @cfg {Number} timeout (Optional) @hide
11418 * @cfg {Boolean} autoAbort (Optional) @hide
11422 * @cfg {Boolean} disableCaching (Optional) @hide
11426 * @property disableCaching
11427 * True to add a unique cache-buster param to GET requests. (defaults to true)
11432 * The default URL to be used for requests to the server. (defaults to undefined)
11436 * @property extraParams
11437 * An object containing properties which are used as
11438 * extra parameters to each request made by this object. (defaults to undefined)
11442 * @property defaultHeaders
11443 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11448 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11452 * @property timeout
11453 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11458 * @property autoAbort
11459 * Whether a new request should abort any pending requests. (defaults to false)
11465 * Serialize the passed form into a url encoded string
11466 * @param {String/HTMLElement} form
11469 serializeForm : function(form){
11470 return Roo.lib.Ajax.serializeForm(form);
11474 * Ext JS Library 1.1.1
11475 * Copyright(c) 2006-2007, Ext JS, LLC.
11477 * Originally Released Under LGPL - original licence link has changed is not relivant.
11480 * <script type="text/javascript">
11485 * @class Roo.UpdateManager
11486 * @extends Roo.util.Observable
11487 * Provides AJAX-style update for Element object.<br><br>
11490 * // Get it from a Roo.Element object
11491 * var el = Roo.get("foo");
11492 * var mgr = el.getUpdateManager();
11493 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11495 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11497 * // or directly (returns the same UpdateManager instance)
11498 * var mgr = new Roo.UpdateManager("myElementId");
11499 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11500 * mgr.on("update", myFcnNeedsToKnow);
11502 // short handed call directly from the element object
11503 Roo.get("foo").load({
11507 text: "Loading Foo..."
11511 * Create new UpdateManager directly.
11512 * @param {String/HTMLElement/Roo.Element} el The element to update
11513 * @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).
11515 Roo.UpdateManager = function(el, forceNew){
11517 if(!forceNew && el.updateManager){
11518 return el.updateManager;
11521 * The Element object
11522 * @type Roo.Element
11526 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11529 this.defaultUrl = null;
11533 * @event beforeupdate
11534 * Fired before an update is made, return false from your handler and the update is cancelled.
11535 * @param {Roo.Element} el
11536 * @param {String/Object/Function} url
11537 * @param {String/Object} params
11539 "beforeupdate": true,
11542 * Fired after successful update is made.
11543 * @param {Roo.Element} el
11544 * @param {Object} oResponseObject The response Object
11549 * Fired on update failure.
11550 * @param {Roo.Element} el
11551 * @param {Object} oResponseObject The response Object
11555 var d = Roo.UpdateManager.defaults;
11557 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11560 this.sslBlankUrl = d.sslBlankUrl;
11562 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11565 this.disableCaching = d.disableCaching;
11567 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11570 this.indicatorText = d.indicatorText;
11572 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11575 this.showLoadIndicator = d.showLoadIndicator;
11577 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11580 this.timeout = d.timeout;
11583 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11586 this.loadScripts = d.loadScripts;
11589 * Transaction object of current executing transaction
11591 this.transaction = null;
11596 this.autoRefreshProcId = null;
11598 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11601 this.refreshDelegate = this.refresh.createDelegate(this);
11603 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11606 this.updateDelegate = this.update.createDelegate(this);
11608 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11611 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11615 this.successDelegate = this.processSuccess.createDelegate(this);
11619 this.failureDelegate = this.processFailure.createDelegate(this);
11621 if(!this.renderer){
11623 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11625 this.renderer = new Roo.UpdateManager.BasicRenderer();
11628 Roo.UpdateManager.superclass.constructor.call(this);
11631 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11633 * Get the Element this UpdateManager is bound to
11634 * @return {Roo.Element} The element
11636 getEl : function(){
11640 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11641 * @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:
11644 url: "your-url.php",<br/>
11645 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11646 callback: yourFunction,<br/>
11647 scope: yourObject, //(optional scope) <br/>
11648 discardUrl: false, <br/>
11649 nocache: false,<br/>
11650 text: "Loading...",<br/>
11652 scripts: false<br/>
11655 * The only required property is url. The optional properties nocache, text and scripts
11656 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11657 * @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}
11658 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11659 * @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.
11661 update : function(url, params, callback, discardUrl){
11662 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11663 var method = this.method, cfg;
11664 if(typeof url == "object"){ // must be config object
11667 params = params || cfg.params;
11668 callback = callback || cfg.callback;
11669 discardUrl = discardUrl || cfg.discardUrl;
11670 if(callback && cfg.scope){
11671 callback = callback.createDelegate(cfg.scope);
11673 if(typeof cfg.method != "undefined"){method = cfg.method;};
11674 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11675 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11676 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11677 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11679 this.showLoading();
11681 this.defaultUrl = url;
11683 if(typeof url == "function"){
11684 url = url.call(this);
11687 method = method || (params ? "POST" : "GET");
11688 if(method == "GET"){
11689 url = this.prepareUrl(url);
11692 var o = Roo.apply(cfg ||{}, {
11695 success: this.successDelegate,
11696 failure: this.failureDelegate,
11697 callback: undefined,
11698 timeout: (this.timeout*1000),
11699 argument: {"url": url, "form": null, "callback": callback, "params": params}
11702 this.transaction = Roo.Ajax.request(o);
11707 * 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.
11708 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11709 * @param {String/HTMLElement} form The form Id or form element
11710 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11711 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11712 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11714 formUpdate : function(form, url, reset, callback){
11715 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11716 if(typeof url == "function"){
11717 url = url.call(this);
11719 form = Roo.getDom(form);
11720 this.transaction = Roo.Ajax.request({
11723 success: this.successDelegate,
11724 failure: this.failureDelegate,
11725 timeout: (this.timeout*1000),
11726 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11728 this.showLoading.defer(1, this);
11733 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11734 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11736 refresh : function(callback){
11737 if(this.defaultUrl == null){
11740 this.update(this.defaultUrl, null, callback, true);
11744 * Set this element to auto refresh.
11745 * @param {Number} interval How often to update (in seconds).
11746 * @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)
11747 * @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}
11748 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11749 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11751 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11753 this.update(url || this.defaultUrl, params, callback, true);
11755 if(this.autoRefreshProcId){
11756 clearInterval(this.autoRefreshProcId);
11758 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11762 * Stop auto refresh on this element.
11764 stopAutoRefresh : function(){
11765 if(this.autoRefreshProcId){
11766 clearInterval(this.autoRefreshProcId);
11767 delete this.autoRefreshProcId;
11771 isAutoRefreshing : function(){
11772 return this.autoRefreshProcId ? true : false;
11775 * Called to update the element to "Loading" state. Override to perform custom action.
11777 showLoading : function(){
11778 if(this.showLoadIndicator){
11779 this.el.update(this.indicatorText);
11784 * Adds unique parameter to query string if disableCaching = true
11787 prepareUrl : function(url){
11788 if(this.disableCaching){
11789 var append = "_dc=" + (new Date().getTime());
11790 if(url.indexOf("?") !== -1){
11791 url += "&" + append;
11793 url += "?" + append;
11802 processSuccess : function(response){
11803 this.transaction = null;
11804 if(response.argument.form && response.argument.reset){
11805 try{ // put in try/catch since some older FF releases had problems with this
11806 response.argument.form.reset();
11809 if(this.loadScripts){
11810 this.renderer.render(this.el, response, this,
11811 this.updateComplete.createDelegate(this, [response]));
11813 this.renderer.render(this.el, response, this);
11814 this.updateComplete(response);
11818 updateComplete : function(response){
11819 this.fireEvent("update", this.el, response);
11820 if(typeof response.argument.callback == "function"){
11821 response.argument.callback(this.el, true, response);
11828 processFailure : function(response){
11829 this.transaction = null;
11830 this.fireEvent("failure", this.el, response);
11831 if(typeof response.argument.callback == "function"){
11832 response.argument.callback(this.el, false, response);
11837 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11838 * @param {Object} renderer The object implementing the render() method
11840 setRenderer : function(renderer){
11841 this.renderer = renderer;
11844 getRenderer : function(){
11845 return this.renderer;
11849 * Set the defaultUrl used for updates
11850 * @param {String/Function} defaultUrl The url or a function to call to get the url
11852 setDefaultUrl : function(defaultUrl){
11853 this.defaultUrl = defaultUrl;
11857 * Aborts the executing transaction
11859 abort : function(){
11860 if(this.transaction){
11861 Roo.Ajax.abort(this.transaction);
11866 * Returns true if an update is in progress
11867 * @return {Boolean}
11869 isUpdating : function(){
11870 if(this.transaction){
11871 return Roo.Ajax.isLoading(this.transaction);
11878 * @class Roo.UpdateManager.defaults
11879 * @static (not really - but it helps the doc tool)
11880 * The defaults collection enables customizing the default properties of UpdateManager
11882 Roo.UpdateManager.defaults = {
11884 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11890 * True to process scripts by default (Defaults to false).
11893 loadScripts : false,
11896 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11899 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11901 * Whether to append unique parameter on get request to disable caching (Defaults to false).
11904 disableCaching : false,
11906 * Whether to show indicatorText when loading (Defaults to true).
11909 showLoadIndicator : true,
11911 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
11914 indicatorText : '<div class="loading-indicator">Loading...</div>'
11918 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11920 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11921 * @param {String/HTMLElement/Roo.Element} el The element to update
11922 * @param {String} url The url
11923 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11924 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11927 * @member Roo.UpdateManager
11929 Roo.UpdateManager.updateElement = function(el, url, params, options){
11930 var um = Roo.get(el, true).getUpdateManager();
11931 Roo.apply(um, options);
11932 um.update(url, params, options ? options.callback : null);
11934 // alias for backwards compat
11935 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11937 * @class Roo.UpdateManager.BasicRenderer
11938 * Default Content renderer. Updates the elements innerHTML with the responseText.
11940 Roo.UpdateManager.BasicRenderer = function(){};
11942 Roo.UpdateManager.BasicRenderer.prototype = {
11944 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11945 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11946 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11947 * @param {Roo.Element} el The element being rendered
11948 * @param {Object} response The YUI Connect response object
11949 * @param {UpdateManager} updateManager The calling update manager
11950 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11952 render : function(el, response, updateManager, callback){
11953 el.update(response.responseText, updateManager.loadScripts, callback);
11958 * Ext JS Library 1.1.1
11959 * Copyright(c) 2006-2007, Ext JS, LLC.
11961 * Originally Released Under LGPL - original licence link has changed is not relivant.
11964 * <script type="text/javascript">
11968 * @class Roo.util.DelayedTask
11969 * Provides a convenient method of performing setTimeout where a new
11970 * timeout cancels the old timeout. An example would be performing validation on a keypress.
11971 * You can use this class to buffer
11972 * the keypress events for a certain number of milliseconds, and perform only if they stop
11973 * for that amount of time.
11974 * @constructor The parameters to this constructor serve as defaults and are not required.
11975 * @param {Function} fn (optional) The default function to timeout
11976 * @param {Object} scope (optional) The default scope of that timeout
11977 * @param {Array} args (optional) The default Array of arguments
11979 Roo.util.DelayedTask = function(fn, scope, args){
11980 var id = null, d, t;
11982 var call = function(){
11983 var now = new Date().getTime();
11987 fn.apply(scope, args || []);
11991 * Cancels any pending timeout and queues a new one
11992 * @param {Number} delay The milliseconds to delay
11993 * @param {Function} newFn (optional) Overrides function passed to constructor
11994 * @param {Object} newScope (optional) Overrides scope passed to constructor
11995 * @param {Array} newArgs (optional) Overrides args passed to constructor
11997 this.delay = function(delay, newFn, newScope, newArgs){
11998 if(id && delay != d){
12002 t = new Date().getTime();
12004 scope = newScope || scope;
12005 args = newArgs || args;
12007 id = setInterval(call, d);
12012 * Cancel the last queued timeout
12014 this.cancel = function(){
12022 * Ext JS Library 1.1.1
12023 * Copyright(c) 2006-2007, Ext JS, LLC.
12025 * Originally Released Under LGPL - original licence link has changed is not relivant.
12028 * <script type="text/javascript">
12032 Roo.util.TaskRunner = function(interval){
12033 interval = interval || 10;
12034 var tasks = [], removeQueue = [];
12036 var running = false;
12038 var stopThread = function(){
12044 var startThread = function(){
12047 id = setInterval(runTasks, interval);
12051 var removeTask = function(task){
12052 removeQueue.push(task);
12058 var runTasks = function(){
12059 if(removeQueue.length > 0){
12060 for(var i = 0, len = removeQueue.length; i < len; i++){
12061 tasks.remove(removeQueue[i]);
12064 if(tasks.length < 1){
12069 var now = new Date().getTime();
12070 for(var i = 0, len = tasks.length; i < len; ++i){
12072 var itime = now - t.taskRunTime;
12073 if(t.interval <= itime){
12074 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12075 t.taskRunTime = now;
12076 if(rt === false || t.taskRunCount === t.repeat){
12081 if(t.duration && t.duration <= (now - t.taskStartTime)){
12088 * Queues a new task.
12089 * @param {Object} task
12091 this.start = function(task){
12093 task.taskStartTime = new Date().getTime();
12094 task.taskRunTime = 0;
12095 task.taskRunCount = 0;
12100 this.stop = function(task){
12105 this.stopAll = function(){
12107 for(var i = 0, len = tasks.length; i < len; i++){
12108 if(tasks[i].onStop){
12117 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12119 * Ext JS Library 1.1.1
12120 * Copyright(c) 2006-2007, Ext JS, LLC.
12122 * Originally Released Under LGPL - original licence link has changed is not relivant.
12125 * <script type="text/javascript">
12130 * @class Roo.util.MixedCollection
12131 * @extends Roo.util.Observable
12132 * A Collection class that maintains both numeric indexes and keys and exposes events.
12134 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12135 * collection (defaults to false)
12136 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12137 * and return the key value for that item. This is used when available to look up the key on items that
12138 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12139 * equivalent to providing an implementation for the {@link #getKey} method.
12141 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12149 * Fires when the collection is cleared.
12154 * Fires when an item is added to the collection.
12155 * @param {Number} index The index at which the item was added.
12156 * @param {Object} o The item added.
12157 * @param {String} key The key associated with the added item.
12162 * Fires when an item is replaced in the collection.
12163 * @param {String} key he key associated with the new added.
12164 * @param {Object} old The item being replaced.
12165 * @param {Object} new The new item.
12170 * Fires when an item is removed from the collection.
12171 * @param {Object} o The item being removed.
12172 * @param {String} key (optional) The key associated with the removed item.
12177 this.allowFunctions = allowFunctions === true;
12179 this.getKey = keyFn;
12181 Roo.util.MixedCollection.superclass.constructor.call(this);
12184 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12185 allowFunctions : false,
12188 * Adds an item to the collection.
12189 * @param {String} key The key to associate with the item
12190 * @param {Object} o The item to add.
12191 * @return {Object} The item added.
12193 add : function(key, o){
12194 if(arguments.length == 1){
12196 key = this.getKey(o);
12198 if(typeof key == "undefined" || key === null){
12200 this.items.push(o);
12201 this.keys.push(null);
12203 var old = this.map[key];
12205 return this.replace(key, o);
12208 this.items.push(o);
12210 this.keys.push(key);
12212 this.fireEvent("add", this.length-1, o, key);
12217 * MixedCollection has a generic way to fetch keys if you implement getKey.
12220 var mc = new Roo.util.MixedCollection();
12221 mc.add(someEl.dom.id, someEl);
12222 mc.add(otherEl.dom.id, otherEl);
12226 var mc = new Roo.util.MixedCollection();
12227 mc.getKey = function(el){
12233 // or via the constructor
12234 var mc = new Roo.util.MixedCollection(false, function(el){
12240 * @param o {Object} The item for which to find the key.
12241 * @return {Object} The key for the passed item.
12243 getKey : function(o){
12248 * Replaces an item in the collection.
12249 * @param {String} key The key associated with the item to replace, or the item to replace.
12250 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12251 * @return {Object} The new item.
12253 replace : function(key, o){
12254 if(arguments.length == 1){
12256 key = this.getKey(o);
12258 var old = this.item(key);
12259 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12260 return this.add(key, o);
12262 var index = this.indexOfKey(key);
12263 this.items[index] = o;
12265 this.fireEvent("replace", key, old, o);
12270 * Adds all elements of an Array or an Object to the collection.
12271 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12272 * an Array of values, each of which are added to the collection.
12274 addAll : function(objs){
12275 if(arguments.length > 1 || objs instanceof Array){
12276 var args = arguments.length > 1 ? arguments : objs;
12277 for(var i = 0, len = args.length; i < len; i++){
12281 for(var key in objs){
12282 if(this.allowFunctions || typeof objs[key] != "function"){
12283 this.add(key, objs[key]);
12290 * Executes the specified function once for every item in the collection, passing each
12291 * item as the first and only parameter. returning false from the function will stop the iteration.
12292 * @param {Function} fn The function to execute for each item.
12293 * @param {Object} scope (optional) The scope in which to execute the function.
12295 each : function(fn, scope){
12296 var items = [].concat(this.items); // each safe for removal
12297 for(var i = 0, len = items.length; i < len; i++){
12298 if(fn.call(scope || items[i], items[i], i, len) === false){
12305 * Executes the specified function once for every key in the collection, passing each
12306 * key, and its associated item as the first two parameters.
12307 * @param {Function} fn The function to execute for each item.
12308 * @param {Object} scope (optional) The scope in which to execute the function.
12310 eachKey : function(fn, scope){
12311 for(var i = 0, len = this.keys.length; i < len; i++){
12312 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12317 * Returns the first item in the collection which elicits a true return value from the
12318 * passed selection function.
12319 * @param {Function} fn The selection function to execute for each item.
12320 * @param {Object} scope (optional) The scope in which to execute the function.
12321 * @return {Object} The first item in the collection which returned true from the selection function.
12323 find : function(fn, scope){
12324 for(var i = 0, len = this.items.length; i < len; i++){
12325 if(fn.call(scope || window, this.items[i], this.keys[i])){
12326 return this.items[i];
12333 * Inserts an item at the specified index in the collection.
12334 * @param {Number} index The index to insert the item at.
12335 * @param {String} key The key to associate with the new item, or the item itself.
12336 * @param {Object} o (optional) If the second parameter was a key, the new item.
12337 * @return {Object} The item inserted.
12339 insert : function(index, key, o){
12340 if(arguments.length == 2){
12342 key = this.getKey(o);
12344 if(index >= this.length){
12345 return this.add(key, o);
12348 this.items.splice(index, 0, o);
12349 if(typeof key != "undefined" && key != null){
12352 this.keys.splice(index, 0, key);
12353 this.fireEvent("add", index, o, key);
12358 * Removed an item from the collection.
12359 * @param {Object} o The item to remove.
12360 * @return {Object} The item removed.
12362 remove : function(o){
12363 return this.removeAt(this.indexOf(o));
12367 * Remove an item from a specified index in the collection.
12368 * @param {Number} index The index within the collection of the item to remove.
12370 removeAt : function(index){
12371 if(index < this.length && index >= 0){
12373 var o = this.items[index];
12374 this.items.splice(index, 1);
12375 var key = this.keys[index];
12376 if(typeof key != "undefined"){
12377 delete this.map[key];
12379 this.keys.splice(index, 1);
12380 this.fireEvent("remove", o, key);
12385 * Removed an item associated with the passed key fom the collection.
12386 * @param {String} key The key of the item to remove.
12388 removeKey : function(key){
12389 return this.removeAt(this.indexOfKey(key));
12393 * Returns the number of items in the collection.
12394 * @return {Number} the number of items in the collection.
12396 getCount : function(){
12397 return this.length;
12401 * Returns index within the collection of the passed Object.
12402 * @param {Object} o The item to find the index of.
12403 * @return {Number} index of the item.
12405 indexOf : function(o){
12406 if(!this.items.indexOf){
12407 for(var i = 0, len = this.items.length; i < len; i++){
12408 if(this.items[i] == o) return i;
12412 return this.items.indexOf(o);
12417 * Returns index within the collection of the passed key.
12418 * @param {String} key The key to find the index of.
12419 * @return {Number} index of the key.
12421 indexOfKey : function(key){
12422 if(!this.keys.indexOf){
12423 for(var i = 0, len = this.keys.length; i < len; i++){
12424 if(this.keys[i] == key) return i;
12428 return this.keys.indexOf(key);
12433 * Returns the item associated with the passed key OR index. Key has priority over index.
12434 * @param {String/Number} key The key or index of the item.
12435 * @return {Object} The item associated with the passed key.
12437 item : function(key){
12438 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12439 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12443 * Returns the item at the specified index.
12444 * @param {Number} index The index of the item.
12447 itemAt : function(index){
12448 return this.items[index];
12452 * Returns the item associated with the passed key.
12453 * @param {String/Number} key The key of the item.
12454 * @return {Object} The item associated with the passed key.
12456 key : function(key){
12457 return this.map[key];
12461 * Returns true if the collection contains the passed Object as an item.
12462 * @param {Object} o The Object to look for in the collection.
12463 * @return {Boolean} True if the collection contains the Object as an item.
12465 contains : function(o){
12466 return this.indexOf(o) != -1;
12470 * Returns true if the collection contains the passed Object as a key.
12471 * @param {String} key The key to look for in the collection.
12472 * @return {Boolean} True if the collection contains the Object as a key.
12474 containsKey : function(key){
12475 return typeof this.map[key] != "undefined";
12479 * Removes all items from the collection.
12481 clear : function(){
12486 this.fireEvent("clear");
12490 * Returns the first item in the collection.
12491 * @return {Object} the first item in the collection..
12493 first : function(){
12494 return this.items[0];
12498 * Returns the last item in the collection.
12499 * @return {Object} the last item in the collection..
12502 return this.items[this.length-1];
12505 _sort : function(property, dir, fn){
12506 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12507 fn = fn || function(a, b){
12510 var c = [], k = this.keys, items = this.items;
12511 for(var i = 0, len = items.length; i < len; i++){
12512 c[c.length] = {key: k[i], value: items[i], index: i};
12514 c.sort(function(a, b){
12515 var v = fn(a[property], b[property]) * dsc;
12517 v = (a.index < b.index ? -1 : 1);
12521 for(var i = 0, len = c.length; i < len; i++){
12522 items[i] = c[i].value;
12525 this.fireEvent("sort", this);
12529 * Sorts this collection with the passed comparison function
12530 * @param {String} direction (optional) "ASC" or "DESC"
12531 * @param {Function} fn (optional) comparison function
12533 sort : function(dir, fn){
12534 this._sort("value", dir, fn);
12538 * Sorts this collection by keys
12539 * @param {String} direction (optional) "ASC" or "DESC"
12540 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12542 keySort : function(dir, fn){
12543 this._sort("key", dir, fn || function(a, b){
12544 return String(a).toUpperCase()-String(b).toUpperCase();
12549 * Returns a range of items in this collection
12550 * @param {Number} startIndex (optional) defaults to 0
12551 * @param {Number} endIndex (optional) default to the last item
12552 * @return {Array} An array of items
12554 getRange : function(start, end){
12555 var items = this.items;
12556 if(items.length < 1){
12559 start = start || 0;
12560 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12563 for(var i = start; i <= end; i++) {
12564 r[r.length] = items[i];
12567 for(var i = start; i >= end; i--) {
12568 r[r.length] = items[i];
12575 * Filter the <i>objects</i> in this collection by a specific property.
12576 * Returns a new collection that has been filtered.
12577 * @param {String} property A property on your objects
12578 * @param {String/RegExp} value Either string that the property values
12579 * should start with or a RegExp to test against the property
12580 * @return {MixedCollection} The new filtered collection
12582 filter : function(property, value){
12583 if(!value.exec){ // not a regex
12584 value = String(value);
12585 if(value.length == 0){
12586 return this.clone();
12588 value = new RegExp("^" + Roo.escapeRe(value), "i");
12590 return this.filterBy(function(o){
12591 return o && value.test(o[property]);
12596 * Filter by a function. * Returns a new collection that has been filtered.
12597 * The passed function will be called with each
12598 * object in the collection. If the function returns true, the value is included
12599 * otherwise it is filtered.
12600 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12601 * @param {Object} scope (optional) The scope of the function (defaults to this)
12602 * @return {MixedCollection} The new filtered collection
12604 filterBy : function(fn, scope){
12605 var r = new Roo.util.MixedCollection();
12606 r.getKey = this.getKey;
12607 var k = this.keys, it = this.items;
12608 for(var i = 0, len = it.length; i < len; i++){
12609 if(fn.call(scope||this, it[i], k[i])){
12610 r.add(k[i], it[i]);
12617 * Creates a duplicate of this collection
12618 * @return {MixedCollection}
12620 clone : function(){
12621 var r = new Roo.util.MixedCollection();
12622 var k = this.keys, it = this.items;
12623 for(var i = 0, len = it.length; i < len; i++){
12624 r.add(k[i], it[i]);
12626 r.getKey = this.getKey;
12631 * Returns the item associated with the passed key or index.
12633 * @param {String/Number} key The key or index of the item.
12634 * @return {Object} The item associated with the passed key.
12636 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12638 * Ext JS Library 1.1.1
12639 * Copyright(c) 2006-2007, Ext JS, LLC.
12641 * Originally Released Under LGPL - original licence link has changed is not relivant.
12644 * <script type="text/javascript">
12647 * @class Roo.util.JSON
12648 * Modified version of Douglas Crockford"s json.js that doesn"t
12649 * mess with the Object prototype
12650 * http://www.json.org/js.html
12653 Roo.util.JSON = new (function(){
12654 var useHasOwn = {}.hasOwnProperty ? true : false;
12656 // crashes Safari in some instances
12657 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12659 var pad = function(n) {
12660 return n < 10 ? "0" + n : n;
12673 var encodeString = function(s){
12674 if (/["\\\x00-\x1f]/.test(s)) {
12675 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12680 c = b.charCodeAt();
12682 Math.floor(c / 16).toString(16) +
12683 (c % 16).toString(16);
12686 return '"' + s + '"';
12689 var encodeArray = function(o){
12690 var a = ["["], b, i, l = o.length, v;
12691 for (i = 0; i < l; i += 1) {
12693 switch (typeof v) {
12702 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12710 var encodeDate = function(o){
12711 return '"' + o.getFullYear() + "-" +
12712 pad(o.getMonth() + 1) + "-" +
12713 pad(o.getDate()) + "T" +
12714 pad(o.getHours()) + ":" +
12715 pad(o.getMinutes()) + ":" +
12716 pad(o.getSeconds()) + '"';
12720 * Encodes an Object, Array or other value
12721 * @param {Mixed} o The variable to encode
12722 * @return {String} The JSON string
12724 this.encode = function(o){
12725 if(typeof o == "undefined" || o === null){
12727 }else if(o instanceof Array){
12728 return encodeArray(o);
12729 }else if(o instanceof Date){
12730 return encodeDate(o);
12731 }else if(typeof o == "string"){
12732 return encodeString(o);
12733 }else if(typeof o == "number"){
12734 return isFinite(o) ? String(o) : "null";
12735 }else if(typeof o == "boolean"){
12738 var a = ["{"], b, i, v;
12740 if(!useHasOwn || o.hasOwnProperty(i)) {
12742 switch (typeof v) {
12751 a.push(this.encode(i), ":",
12752 v === null ? "null" : this.encode(v));
12763 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12764 * @param {String} json The JSON string
12765 * @return {Object} The resulting object
12767 this.decode = function(json){
12771 return eval("(" + json + ')');
12775 * Shorthand for {@link Roo.util.JSON#encode}
12776 * @member Roo encode
12778 Roo.encode = Roo.util.JSON.encode;
12780 * Shorthand for {@link Roo.util.JSON#decode}
12781 * @member Roo decode
12783 Roo.decode = Roo.util.JSON.decode;
12786 * Ext JS Library 1.1.1
12787 * Copyright(c) 2006-2007, Ext JS, LLC.
12789 * Originally Released Under LGPL - original licence link has changed is not relivant.
12792 * <script type="text/javascript">
12796 * @class Roo.util.Format
12797 * Reusable data formatting functions
12800 Roo.util.Format = function(){
12801 var trimRe = /^\s+|\s+$/g;
12804 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12805 * @param {String} value The string to truncate
12806 * @param {Number} length The maximum length to allow before truncating
12807 * @return {String} The converted text
12809 ellipsis : function(value, len){
12810 if(value && value.length > len){
12811 return value.substr(0, len-3)+"...";
12817 * Checks a reference and converts it to empty string if it is undefined
12818 * @param {Mixed} value Reference to check
12819 * @return {Mixed} Empty string if converted, otherwise the original value
12821 undef : function(value){
12822 return typeof value != "undefined" ? value : "";
12826 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12827 * @param {String} value The string to encode
12828 * @return {String} The encoded text
12830 htmlEncode : function(value){
12831 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12835 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12836 * @param {String} value The string to decode
12837 * @return {String} The decoded text
12839 htmlDecode : function(value){
12840 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12844 * Trims any whitespace from either side of a string
12845 * @param {String} value The text to trim
12846 * @return {String} The trimmed text
12848 trim : function(value){
12849 return String(value).replace(trimRe, "");
12853 * Returns a substring from within an original string
12854 * @param {String} value The original text
12855 * @param {Number} start The start index of the substring
12856 * @param {Number} length The length of the substring
12857 * @return {String} The substring
12859 substr : function(value, start, length){
12860 return String(value).substr(start, length);
12864 * Converts a string to all lower case letters
12865 * @param {String} value The text to convert
12866 * @return {String} The converted text
12868 lowercase : function(value){
12869 return String(value).toLowerCase();
12873 * Converts a string to all upper case letters
12874 * @param {String} value The text to convert
12875 * @return {String} The converted text
12877 uppercase : function(value){
12878 return String(value).toUpperCase();
12882 * Converts the first character only of a string to upper case
12883 * @param {String} value The text to convert
12884 * @return {String} The converted text
12886 capitalize : function(value){
12887 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12891 call : function(value, fn){
12892 if(arguments.length > 2){
12893 var args = Array.prototype.slice.call(arguments, 2);
12894 args.unshift(value);
12896 return /** eval:var:value */ eval(fn).apply(window, args);
12898 /** eval:var:value */
12899 return /** eval:var:value */ eval(fn).call(window, value);
12904 * Format a number as US currency
12905 * @param {Number/String} value The numeric value to format
12906 * @return {String} The formatted currency string
12908 usMoney : function(v){
12909 v = (Math.round((v-0)*100))/100;
12910 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12912 var ps = v.split('.');
12914 var sub = ps[1] ? '.'+ ps[1] : '.00';
12915 var r = /(\d+)(\d{3})/;
12916 while (r.test(whole)) {
12917 whole = whole.replace(r, '$1' + ',' + '$2');
12919 return "$" + whole + sub ;
12923 * Parse a value into a formatted date using the specified format pattern.
12924 * @param {Mixed} value The value to format
12925 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12926 * @return {String} The formatted date string
12928 date : function(v, format){
12932 if(!(v instanceof Date)){
12933 v = new Date(Date.parse(v));
12935 return v.dateFormat(format || "m/d/Y");
12939 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12940 * @param {String} format Any valid date format string
12941 * @return {Function} The date formatting function
12943 dateRenderer : function(format){
12944 return function(v){
12945 return Roo.util.Format.date(v, format);
12950 stripTagsRE : /<\/?[^>]+>/gi,
12953 * Strips all HTML tags
12954 * @param {Mixed} value The text from which to strip tags
12955 * @return {String} The stripped text
12957 stripTags : function(v){
12958 return !v ? v : String(v).replace(this.stripTagsRE, "");
12963 * Ext JS Library 1.1.1
12964 * Copyright(c) 2006-2007, Ext JS, LLC.
12966 * Originally Released Under LGPL - original licence link has changed is not relivant.
12969 * <script type="text/javascript">
12976 * @class Roo.MasterTemplate
12977 * @extends Roo.Template
12978 * Provides a template that can have child templates. The syntax is:
12980 var t = new Roo.MasterTemplate(
12981 '<select name="{name}">',
12982 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
12985 t.add('options', {value: 'foo', text: 'bar'});
12986 // or you can add multiple child elements in one shot
12987 t.addAll('options', [
12988 {value: 'foo', text: 'bar'},
12989 {value: 'foo2', text: 'bar2'},
12990 {value: 'foo3', text: 'bar3'}
12992 // then append, applying the master template values
12993 t.append('my-form', {name: 'my-select'});
12995 * A name attribute for the child template is not required if you have only one child
12996 * template or you want to refer to them by index.
12998 Roo.MasterTemplate = function(){
12999 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13000 this.originalHtml = this.html;
13002 var m, re = this.subTemplateRe;
13005 while(m = re.exec(this.html)){
13006 var name = m[1], content = m[2];
13011 tpl : new Roo.Template(content)
13014 st[name] = st[subIndex];
13016 st[subIndex].tpl.compile();
13017 st[subIndex].tpl.call = this.call.createDelegate(this);
13020 this.subCount = subIndex;
13023 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13025 * The regular expression used to match sub templates
13029 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13032 * Applies the passed values to a child template.
13033 * @param {String/Number} name (optional) The name or index of the child template
13034 * @param {Array/Object} values The values to be applied to the template
13035 * @return {MasterTemplate} this
13037 add : function(name, values){
13038 if(arguments.length == 1){
13039 values = arguments[0];
13042 var s = this.subs[name];
13043 s.buffer[s.buffer.length] = s.tpl.apply(values);
13048 * Applies all the passed values to a child template.
13049 * @param {String/Number} name (optional) The name or index of the child template
13050 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13051 * @param {Boolean} reset (optional) True to reset the template first
13052 * @return {MasterTemplate} this
13054 fill : function(name, values, reset){
13056 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13064 for(var i = 0, len = values.length; i < len; i++){
13065 this.add(name, values[i]);
13071 * Resets the template for reuse
13072 * @return {MasterTemplate} this
13074 reset : function(){
13076 for(var i = 0; i < this.subCount; i++){
13082 applyTemplate : function(values){
13084 var replaceIndex = -1;
13085 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13086 return s[++replaceIndex].buffer.join("");
13088 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13091 apply : function(){
13092 return this.applyTemplate.apply(this, arguments);
13095 compile : function(){return this;}
13099 * Alias for fill().
13102 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13104 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13105 * var tpl = Roo.MasterTemplate.from('element-id');
13106 * @param {String/HTMLElement} el
13107 * @param {Object} config
13110 Roo.MasterTemplate.from = function(el, config){
13111 el = Roo.getDom(el);
13112 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13115 * Ext JS Library 1.1.1
13116 * Copyright(c) 2006-2007, Ext JS, LLC.
13118 * Originally Released Under LGPL - original licence link has changed is not relivant.
13121 * <script type="text/javascript">
13126 * @class Roo.util.CSS
13127 * Utility class for manipulating CSS rules
13130 Roo.util.CSS = function(){
13132 var doc = document;
13134 var camelRe = /(-[a-z])/gi;
13135 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13139 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13140 * tag and appended to the HEAD of the document.
13141 * @param {String} cssText The text containing the css rules
13142 * @param {String} id An id to add to the stylesheet for later removal
13143 * @return {StyleSheet}
13145 createStyleSheet : function(cssText, id){
13147 var head = doc.getElementsByTagName("head")[0];
13148 var rules = doc.createElement("style");
13149 rules.setAttribute("type", "text/css");
13151 rules.setAttribute("id", id);
13154 head.appendChild(rules);
13155 ss = rules.styleSheet;
13156 ss.cssText = cssText;
13159 rules.appendChild(doc.createTextNode(cssText));
13161 rules.cssText = cssText;
13163 head.appendChild(rules);
13164 ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13166 this.cacheStyleSheet(ss);
13171 * Removes a style or link tag by id
13172 * @param {String} id The id of the tag
13174 removeStyleSheet : function(id){
13175 var existing = doc.getElementById(id);
13177 existing.parentNode.removeChild(existing);
13182 * Dynamically swaps an existing stylesheet reference for a new one
13183 * @param {String} id The id of an existing link tag to remove
13184 * @param {String} url The href of the new stylesheet to include
13186 swapStyleSheet : function(id, url){
13187 this.removeStyleSheet(id);
13188 var ss = doc.createElement("link");
13189 ss.setAttribute("rel", "stylesheet");
13190 ss.setAttribute("type", "text/css");
13191 ss.setAttribute("id", id);
13192 ss.setAttribute("href", url);
13193 doc.getElementsByTagName("head")[0].appendChild(ss);
13197 * Refresh the rule cache if you have dynamically added stylesheets
13198 * @return {Object} An object (hash) of rules indexed by selector
13200 refreshCache : function(){
13201 return this.getRules(true);
13205 cacheStyleSheet : function(ss){
13209 try{// try catch for cross domain access issue
13210 var ssRules = ss.cssRules || ss.rules;
13211 for(var j = ssRules.length-1; j >= 0; --j){
13212 rules[ssRules[j].selectorText] = ssRules[j];
13218 * Gets all css rules for the document
13219 * @param {Boolean} refreshCache true to refresh the internal cache
13220 * @return {Object} An object (hash) of rules indexed by selector
13222 getRules : function(refreshCache){
13223 if(rules == null || refreshCache){
13225 var ds = doc.styleSheets;
13226 for(var i =0, len = ds.length; i < len; i++){
13228 this.cacheStyleSheet(ds[i]);
13236 * Gets an an individual CSS rule by selector(s)
13237 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13238 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13239 * @return {CSSRule} The CSS rule or null if one is not found
13241 getRule : function(selector, refreshCache){
13242 var rs = this.getRules(refreshCache);
13243 if(!(selector instanceof Array)){
13244 return rs[selector];
13246 for(var i = 0; i < selector.length; i++){
13247 if(rs[selector[i]]){
13248 return rs[selector[i]];
13256 * Updates a rule property
13257 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13258 * @param {String} property The css property
13259 * @param {String} value The new value for the property
13260 * @return {Boolean} true If a rule was found and updated
13262 updateRule : function(selector, property, value){
13263 if(!(selector instanceof Array)){
13264 var rule = this.getRule(selector);
13266 rule.style[property.replace(camelRe, camelFn)] = value;
13270 for(var i = 0; i < selector.length; i++){
13271 if(this.updateRule(selector[i], property, value)){
13281 * Ext JS Library 1.1.1
13282 * Copyright(c) 2006-2007, Ext JS, LLC.
13284 * Originally Released Under LGPL - original licence link has changed is not relivant.
13287 * <script type="text/javascript">
13293 * @class Roo.util.ClickRepeater
13294 * @extends Roo.util.Observable
13296 * A wrapper class which can be applied to any element. Fires a "click" event while the
13297 * mouse is pressed. The interval between firings may be specified in the config but
13298 * defaults to 10 milliseconds.
13300 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13302 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13303 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13304 * Similar to an autorepeat key delay.
13305 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13306 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13307 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13308 * "interval" and "delay" are ignored. "immediate" is honored.
13309 * @cfg {Boolean} preventDefault True to prevent the default click event
13310 * @cfg {Boolean} stopDefault True to stop the default click event
13313 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13314 * 2007-02-02 jvs Renamed to ClickRepeater
13315 * 2007-02-03 jvs Modifications for FF Mac and Safari
13318 * @param {String/HTMLElement/Element} el The element to listen on
13319 * @param {Object} config
13321 Roo.util.ClickRepeater = function(el, config)
13323 this.el = Roo.get(el);
13324 this.el.unselectable();
13326 Roo.apply(this, config);
13331 * Fires when the mouse button is depressed.
13332 * @param {Roo.util.ClickRepeater} this
13334 "mousedown" : true,
13337 * Fires on a specified interval during the time the element is pressed.
13338 * @param {Roo.util.ClickRepeater} this
13343 * Fires when the mouse key is released.
13344 * @param {Roo.util.ClickRepeater} this
13349 this.el.on("mousedown", this.handleMouseDown, this);
13350 if(this.preventDefault || this.stopDefault){
13351 this.el.on("click", function(e){
13352 if(this.preventDefault){
13353 e.preventDefault();
13355 if(this.stopDefault){
13361 // allow inline handler
13363 this.on("click", this.handler, this.scope || this);
13366 Roo.util.ClickRepeater.superclass.constructor.call(this);
13369 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13372 preventDefault : true,
13373 stopDefault : false,
13377 handleMouseDown : function(){
13378 clearTimeout(this.timer);
13380 if(this.pressClass){
13381 this.el.addClass(this.pressClass);
13383 this.mousedownTime = new Date();
13385 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13386 this.el.on("mouseout", this.handleMouseOut, this);
13388 this.fireEvent("mousedown", this);
13389 this.fireEvent("click", this);
13391 this.timer = this.click.defer(this.delay || this.interval, this);
13395 click : function(){
13396 this.fireEvent("click", this);
13397 this.timer = this.click.defer(this.getInterval(), this);
13401 getInterval: function(){
13402 if(!this.accelerate){
13403 return this.interval;
13405 var pressTime = this.mousedownTime.getElapsed();
13406 if(pressTime < 500){
13408 }else if(pressTime < 1700){
13410 }else if(pressTime < 2600){
13412 }else if(pressTime < 3500){
13414 }else if(pressTime < 4400){
13416 }else if(pressTime < 5300){
13418 }else if(pressTime < 6200){
13426 handleMouseOut : function(){
13427 clearTimeout(this.timer);
13428 if(this.pressClass){
13429 this.el.removeClass(this.pressClass);
13431 this.el.on("mouseover", this.handleMouseReturn, this);
13435 handleMouseReturn : function(){
13436 this.el.un("mouseover", this.handleMouseReturn);
13437 if(this.pressClass){
13438 this.el.addClass(this.pressClass);
13444 handleMouseUp : function(){
13445 clearTimeout(this.timer);
13446 this.el.un("mouseover", this.handleMouseReturn);
13447 this.el.un("mouseout", this.handleMouseOut);
13448 Roo.get(document).un("mouseup", this.handleMouseUp);
13449 this.el.removeClass(this.pressClass);
13450 this.fireEvent("mouseup", this);
13454 * Ext JS Library 1.1.1
13455 * Copyright(c) 2006-2007, Ext JS, LLC.
13457 * Originally Released Under LGPL - original licence link has changed is not relivant.
13460 * <script type="text/javascript">
13465 * @class Roo.KeyNav
13466 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13467 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13468 * way to implement custom navigation schemes for any UI component.</p>
13469 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13470 * pageUp, pageDown, del, home, end. Usage:</p>
13472 var nav = new Roo.KeyNav("my-element", {
13473 "left" : function(e){
13474 this.moveLeft(e.ctrlKey);
13476 "right" : function(e){
13477 this.moveRight(e.ctrlKey);
13479 "enter" : function(e){
13486 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13487 * @param {Object} config The config
13489 Roo.KeyNav = function(el, config){
13490 this.el = Roo.get(el);
13491 Roo.apply(this, config);
13492 if(!this.disabled){
13493 this.disabled = true;
13498 Roo.KeyNav.prototype = {
13500 * @cfg {Boolean} disabled
13501 * True to disable this KeyNav instance (defaults to false)
13505 * @cfg {String} defaultEventAction
13506 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13507 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13508 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13510 defaultEventAction: "stopEvent",
13512 * @cfg {Boolean} forceKeyDown
13513 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13514 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13515 * handle keydown instead of keypress.
13517 forceKeyDown : false,
13520 prepareEvent : function(e){
13521 var k = e.getKey();
13522 var h = this.keyToHandler[k];
13523 //if(h && this[h]){
13524 // e.stopPropagation();
13526 if(Roo.isSafari && h && k >= 37 && k <= 40){
13532 relay : function(e){
13533 var k = e.getKey();
13534 var h = this.keyToHandler[k];
13536 if(this.doRelay(e, this[h], h) !== true){
13537 e[this.defaultEventAction]();
13543 doRelay : function(e, h, hname){
13544 return h.call(this.scope || this, e);
13547 // possible handlers
13561 // quick lookup hash
13578 * Enable this KeyNav
13580 enable: function(){
13582 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13583 // the EventObject will normalize Safari automatically
13584 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13585 this.el.on("keydown", this.relay, this);
13587 this.el.on("keydown", this.prepareEvent, this);
13588 this.el.on("keypress", this.relay, this);
13590 this.disabled = false;
13595 * Disable this KeyNav
13597 disable: function(){
13598 if(!this.disabled){
13599 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13600 this.el.un("keydown", this.relay);
13602 this.el.un("keydown", this.prepareEvent);
13603 this.el.un("keypress", this.relay);
13605 this.disabled = true;
13610 * Ext JS Library 1.1.1
13611 * Copyright(c) 2006-2007, Ext JS, LLC.
13613 * Originally Released Under LGPL - original licence link has changed is not relivant.
13616 * <script type="text/javascript">
13621 * @class Roo.KeyMap
13622 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13623 * The constructor accepts the same config object as defined by {@link #addBinding}.
13624 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13625 * combination it will call the function with this signature (if the match is a multi-key
13626 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13627 * A KeyMap can also handle a string representation of keys.<br />
13630 // map one key by key code
13631 var map = new Roo.KeyMap("my-element", {
13632 key: 13, // or Roo.EventObject.ENTER
13637 // map multiple keys to one action by string
13638 var map = new Roo.KeyMap("my-element", {
13644 // map multiple keys to multiple actions by strings and array of codes
13645 var map = new Roo.KeyMap("my-element", [
13648 fn: function(){ alert("Return was pressed"); }
13651 fn: function(){ alert('a, b or c was pressed'); }
13656 fn: function(){ alert('Control + shift + tab was pressed.'); }
13660 * <b>Note: A KeyMap starts enabled</b>
13662 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13663 * @param {Object} config The config (see {@link #addBinding})
13664 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13666 Roo.KeyMap = function(el, config, eventName){
13667 this.el = Roo.get(el);
13668 this.eventName = eventName || "keydown";
13669 this.bindings = [];
13671 this.addBinding(config);
13676 Roo.KeyMap.prototype = {
13678 * True to stop the event from bubbling and prevent the default browser action if the
13679 * key was handled by the KeyMap (defaults to false)
13685 * Add a new binding to this KeyMap. The following config object properties are supported:
13687 Property Type Description
13688 ---------- --------------- ----------------------------------------------------------------------
13689 key String/Array A single keycode or an array of keycodes to handle
13690 shift Boolean True to handle key only when shift is pressed (defaults to false)
13691 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13692 alt Boolean True to handle key only when alt is pressed (defaults to false)
13693 fn Function The function to call when KeyMap finds the expected key combination
13694 scope Object The scope of the callback function
13700 var map = new Roo.KeyMap(document, {
13701 key: Roo.EventObject.ENTER,
13706 //Add a new binding to the existing KeyMap later
13714 * @param {Object/Array} config A single KeyMap config or an array of configs
13716 addBinding : function(config){
13717 if(config instanceof Array){
13718 for(var i = 0, len = config.length; i < len; i++){
13719 this.addBinding(config[i]);
13723 var keyCode = config.key,
13724 shift = config.shift,
13725 ctrl = config.ctrl,
13728 scope = config.scope;
13729 if(typeof keyCode == "string"){
13731 var keyString = keyCode.toUpperCase();
13732 for(var j = 0, len = keyString.length; j < len; j++){
13733 ks.push(keyString.charCodeAt(j));
13737 var keyArray = keyCode instanceof Array;
13738 var handler = function(e){
13739 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13740 var k = e.getKey();
13742 for(var i = 0, len = keyCode.length; i < len; i++){
13743 if(keyCode[i] == k){
13744 if(this.stopEvent){
13747 fn.call(scope || window, k, e);
13753 if(this.stopEvent){
13756 fn.call(scope || window, k, e);
13761 this.bindings.push(handler);
13765 * Shorthand for adding a single key listener
13766 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13767 * following options:
13768 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13769 * @param {Function} fn The function to call
13770 * @param {Object} scope (optional) The scope of the function
13772 on : function(key, fn, scope){
13773 var keyCode, shift, ctrl, alt;
13774 if(typeof key == "object" && !(key instanceof Array)){
13793 handleKeyDown : function(e){
13794 if(this.enabled){ //just in case
13795 var b = this.bindings;
13796 for(var i = 0, len = b.length; i < len; i++){
13797 b[i].call(this, e);
13803 * Returns true if this KeyMap is enabled
13804 * @return {Boolean}
13806 isEnabled : function(){
13807 return this.enabled;
13811 * Enables this KeyMap
13813 enable: function(){
13815 this.el.on(this.eventName, this.handleKeyDown, this);
13816 this.enabled = true;
13821 * Disable this KeyMap
13823 disable: function(){
13825 this.el.removeListener(this.eventName, this.handleKeyDown, this);
13826 this.enabled = false;
13831 * Ext JS Library 1.1.1
13832 * Copyright(c) 2006-2007, Ext JS, LLC.
13834 * Originally Released Under LGPL - original licence link has changed is not relivant.
13837 * <script type="text/javascript">
13842 * @class Roo.util.TextMetrics
13843 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13844 * wide, in pixels, a given block of text will be.
13847 Roo.util.TextMetrics = function(){
13851 * Measures the size of the specified text
13852 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13853 * that can affect the size of the rendered text
13854 * @param {String} text The text to measure
13855 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13856 * in order to accurately measure the text height
13857 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13859 measure : function(el, text, fixedWidth){
13861 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13864 shared.setFixedWidth(fixedWidth || 'auto');
13865 return shared.getSize(text);
13869 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13870 * the overhead of multiple calls to initialize the style properties on each measurement.
13871 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13872 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13873 * in order to accurately measure the text height
13874 * @return {Roo.util.TextMetrics.Instance} instance The new instance
13876 createInstance : function(el, fixedWidth){
13877 return Roo.util.TextMetrics.Instance(el, fixedWidth);
13884 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13885 var ml = new Roo.Element(document.createElement('div'));
13886 document.body.appendChild(ml.dom);
13887 ml.position('absolute');
13888 ml.setLeftTop(-1000, -1000);
13892 ml.setWidth(fixedWidth);
13897 * Returns the size of the specified text based on the internal element's style and width properties
13898 * @memberOf Roo.util.TextMetrics.Instance#
13899 * @param {String} text The text to measure
13900 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13902 getSize : function(text){
13904 var s = ml.getSize();
13910 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13911 * that can affect the size of the rendered text
13912 * @memberOf Roo.util.TextMetrics.Instance#
13913 * @param {String/HTMLElement} el The element, dom node or id
13915 bind : function(el){
13917 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13922 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
13923 * to set a fixed width in order to accurately measure the text height.
13924 * @memberOf Roo.util.TextMetrics.Instance#
13925 * @param {Number} width The width to set on the element
13927 setFixedWidth : function(width){
13928 ml.setWidth(width);
13932 * Returns the measured width of the specified text
13933 * @memberOf Roo.util.TextMetrics.Instance#
13934 * @param {String} text The text to measure
13935 * @return {Number} width The width in pixels
13937 getWidth : function(text){
13938 ml.dom.style.width = 'auto';
13939 return this.getSize(text).width;
13943 * Returns the measured height of the specified text. For multiline text, be sure to call
13944 * {@link #setFixedWidth} if necessary.
13945 * @memberOf Roo.util.TextMetrics.Instance#
13946 * @param {String} text The text to measure
13947 * @return {Number} height The height in pixels
13949 getHeight : function(text){
13950 return this.getSize(text).height;
13954 instance.bind(bindTo);
13959 // backwards compat
13960 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13962 * Ext JS Library 1.1.1
13963 * Copyright(c) 2006-2007, Ext JS, LLC.
13965 * Originally Released Under LGPL - original licence link has changed is not relivant.
13968 * <script type="text/javascript">
13972 * @class Roo.state.Provider
13973 * Abstract base class for state provider implementations. This class provides methods
13974 * for encoding and decoding <b>typed</b> variables including dates and defines the
13975 * Provider interface.
13977 Roo.state.Provider = function(){
13979 * @event statechange
13980 * Fires when a state change occurs.
13981 * @param {Provider} this This state provider
13982 * @param {String} key The state key which was changed
13983 * @param {String} value The encoded value for the state
13986 "statechange": true
13989 Roo.state.Provider.superclass.constructor.call(this);
13991 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
13993 * Returns the current value for a key
13994 * @param {String} name The key name
13995 * @param {Mixed} defaultValue A default value to return if the key's value is not found
13996 * @return {Mixed} The state data
13998 get : function(name, defaultValue){
13999 return typeof this.state[name] == "undefined" ?
14000 defaultValue : this.state[name];
14004 * Clears a value from the state
14005 * @param {String} name The key name
14007 clear : function(name){
14008 delete this.state[name];
14009 this.fireEvent("statechange", this, name, null);
14013 * Sets the value for a key
14014 * @param {String} name The key name
14015 * @param {Mixed} value The value to set
14017 set : function(name, value){
14018 this.state[name] = value;
14019 this.fireEvent("statechange", this, name, value);
14023 * Decodes a string previously encoded with {@link #encodeValue}.
14024 * @param {String} value The value to decode
14025 * @return {Mixed} The decoded value
14027 decodeValue : function(cookie){
14028 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14029 var matches = re.exec(unescape(cookie));
14030 if(!matches || !matches[1]) return; // non state cookie
14031 var type = matches[1];
14032 var v = matches[2];
14035 return parseFloat(v);
14037 return new Date(Date.parse(v));
14042 var values = v.split("^");
14043 for(var i = 0, len = values.length; i < len; i++){
14044 all.push(this.decodeValue(values[i]));
14049 var values = v.split("^");
14050 for(var i = 0, len = values.length; i < len; i++){
14051 var kv = values[i].split("=");
14052 all[kv[0]] = this.decodeValue(kv[1]);
14061 * Encodes a value including type information. Decode with {@link #decodeValue}.
14062 * @param {Mixed} value The value to encode
14063 * @return {String} The encoded value
14065 encodeValue : function(v){
14067 if(typeof v == "number"){
14069 }else if(typeof v == "boolean"){
14070 enc = "b:" + (v ? "1" : "0");
14071 }else if(v instanceof Date){
14072 enc = "d:" + v.toGMTString();
14073 }else if(v instanceof Array){
14075 for(var i = 0, len = v.length; i < len; i++){
14076 flat += this.encodeValue(v[i]);
14077 if(i != len-1) flat += "^";
14080 }else if(typeof v == "object"){
14083 if(typeof v[key] != "function"){
14084 flat += key + "=" + this.encodeValue(v[key]) + "^";
14087 enc = "o:" + flat.substring(0, flat.length-1);
14091 return escape(enc);
14097 * Ext JS Library 1.1.1
14098 * Copyright(c) 2006-2007, Ext JS, LLC.
14100 * Originally Released Under LGPL - original licence link has changed is not relivant.
14103 * <script type="text/javascript">
14106 * @class Roo.state.Manager
14107 * This is the global state manager. By default all components that are "state aware" check this class
14108 * for state information if you don't pass them a custom state provider. In order for this class
14109 * to be useful, it must be initialized with a provider when your application initializes.
14111 // in your initialization function
14113 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14115 // supposed you have a {@link Roo.BorderLayout}
14116 var layout = new Roo.BorderLayout(...);
14117 layout.restoreState();
14118 // or a {Roo.BasicDialog}
14119 var dialog = new Roo.BasicDialog(...);
14120 dialog.restoreState();
14124 Roo.state.Manager = function(){
14125 var provider = new Roo.state.Provider();
14129 * Configures the default state provider for your application
14130 * @param {Provider} stateProvider The state provider to set
14132 setProvider : function(stateProvider){
14133 provider = stateProvider;
14137 * Returns the current value for a key
14138 * @param {String} name The key name
14139 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14140 * @return {Mixed} The state data
14142 get : function(key, defaultValue){
14143 return provider.get(key, defaultValue);
14147 * Sets the value for a key
14148 * @param {String} name The key name
14149 * @param {Mixed} value The state data
14151 set : function(key, value){
14152 provider.set(key, value);
14156 * Clears a value from the state
14157 * @param {String} name The key name
14159 clear : function(key){
14160 provider.clear(key);
14164 * Gets the currently configured state provider
14165 * @return {Provider} The state provider
14167 getProvider : function(){
14174 * Ext JS Library 1.1.1
14175 * Copyright(c) 2006-2007, Ext JS, LLC.
14177 * Originally Released Under LGPL - original licence link has changed is not relivant.
14180 * <script type="text/javascript">
14183 * @class Roo.state.CookieProvider
14184 * @extends Roo.state.Provider
14185 * The default Provider implementation which saves state via cookies.
14188 var cp = new Roo.state.CookieProvider({
14190 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14191 domain: "roojs.com"
14193 Roo.state.Manager.setProvider(cp);
14195 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14196 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14197 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14198 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14199 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14200 * domain the page is running on including the 'www' like 'www.roojs.com')
14201 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14203 * Create a new CookieProvider
14204 * @param {Object} config The configuration object
14206 Roo.state.CookieProvider = function(config){
14207 Roo.state.CookieProvider.superclass.constructor.call(this);
14209 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14210 this.domain = null;
14211 this.secure = false;
14212 Roo.apply(this, config);
14213 this.state = this.readCookies();
14216 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14218 set : function(name, value){
14219 if(typeof value == "undefined" || value === null){
14223 this.setCookie(name, value);
14224 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14228 clear : function(name){
14229 this.clearCookie(name);
14230 Roo.state.CookieProvider.superclass.clear.call(this, name);
14234 readCookies : function(){
14236 var c = document.cookie + ";";
14237 var re = /\s?(.*?)=(.*?);/g;
14239 while((matches = re.exec(c)) != null){
14240 var name = matches[1];
14241 var value = matches[2];
14242 if(name && name.substring(0,3) == "ys-"){
14243 cookies[name.substr(3)] = this.decodeValue(value);
14250 setCookie : function(name, value){
14251 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14252 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14253 ((this.path == null) ? "" : ("; path=" + this.path)) +
14254 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14255 ((this.secure == true) ? "; secure" : "");
14259 clearCookie : function(name){
14260 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14261 ((this.path == null) ? "" : ("; path=" + this.path)) +
14262 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14263 ((this.secure == true) ? "; secure" : "");
14267 * Ext JS Library 1.1.1
14268 * Copyright(c) 2006-2007, Ext JS, LLC.
14270 * Originally Released Under LGPL - original licence link has changed is not relivant.
14273 * <script type="text/javascript">
14279 * These classes are derivatives of the similarly named classes in the YUI Library.
14280 * The original license:
14281 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14282 * Code licensed under the BSD License:
14283 * http://developer.yahoo.net/yui/license.txt
14288 var Event=Roo.EventManager;
14289 var Dom=Roo.lib.Dom;
14292 * @class Roo.dd.DragDrop
14293 * Defines the interface and base operation of items that that can be
14294 * dragged or can be drop targets. It was designed to be extended, overriding
14295 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14296 * Up to three html elements can be associated with a DragDrop instance:
14298 * <li>linked element: the element that is passed into the constructor.
14299 * This is the element which defines the boundaries for interaction with
14300 * other DragDrop objects.</li>
14301 * <li>handle element(s): The drag operation only occurs if the element that
14302 * was clicked matches a handle element. By default this is the linked
14303 * element, but there are times that you will want only a portion of the
14304 * linked element to initiate the drag operation, and the setHandleElId()
14305 * method provides a way to define this.</li>
14306 * <li>drag element: this represents the element that would be moved along
14307 * with the cursor during a drag operation. By default, this is the linked
14308 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14309 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14312 * This class should not be instantiated until the onload event to ensure that
14313 * the associated elements are available.
14314 * The following would define a DragDrop obj that would interact with any
14315 * other DragDrop obj in the "group1" group:
14317 * dd = new Roo.dd.DragDrop("div1", "group1");
14319 * Since none of the event handlers have been implemented, nothing would
14320 * actually happen if you were to run the code above. Normally you would
14321 * override this class or one of the default implementations, but you can
14322 * also override the methods you want on an instance of the class...
14324 * dd.onDragDrop = function(e, id) {
14325 * alert("dd was dropped on " + id);
14329 * @param {String} id of the element that is linked to this instance
14330 * @param {String} sGroup the group of related DragDrop objects
14331 * @param {object} config an object containing configurable attributes
14332 * Valid properties for DragDrop:
14333 * padding, isTarget, maintainOffset, primaryButtonOnly
14335 Roo.dd.DragDrop = function(id, sGroup, config) {
14337 this.init(id, sGroup, config);
14341 Roo.dd.DragDrop.prototype = {
14344 * The id of the element associated with this object. This is what we
14345 * refer to as the "linked element" because the size and position of
14346 * this element is used to determine when the drag and drop objects have
14354 * Configuration attributes passed into the constructor
14361 * The id of the element that will be dragged. By default this is same
14362 * as the linked element , but could be changed to another element. Ex:
14364 * @property dragElId
14371 * the id of the element that initiates the drag operation. By default
14372 * this is the linked element, but could be changed to be a child of this
14373 * element. This lets us do things like only starting the drag when the
14374 * header element within the linked html element is clicked.
14375 * @property handleElId
14382 * An associative array of HTML tags that will be ignored if clicked.
14383 * @property invalidHandleTypes
14384 * @type {string: string}
14386 invalidHandleTypes: null,
14389 * An associative array of ids for elements that will be ignored if clicked
14390 * @property invalidHandleIds
14391 * @type {string: string}
14393 invalidHandleIds: null,
14396 * An indexted array of css class names for elements that will be ignored
14398 * @property invalidHandleClasses
14401 invalidHandleClasses: null,
14404 * The linked element's absolute X position at the time the drag was
14406 * @property startPageX
14413 * The linked element's absolute X position at the time the drag was
14415 * @property startPageY
14422 * The group defines a logical collection of DragDrop objects that are
14423 * related. Instances only get events when interacting with other
14424 * DragDrop object in the same group. This lets us define multiple
14425 * groups using a single DragDrop subclass if we want.
14427 * @type {string: string}
14432 * Individual drag/drop instances can be locked. This will prevent
14433 * onmousedown start drag.
14441 * Lock this instance
14444 lock: function() { this.locked = true; },
14447 * Unlock this instace
14450 unlock: function() { this.locked = false; },
14453 * By default, all insances can be a drop target. This can be disabled by
14454 * setting isTarget to false.
14461 * The padding configured for this drag and drop object for calculating
14462 * the drop zone intersection with this object.
14469 * Cached reference to the linked element
14470 * @property _domRef
14476 * Internal typeof flag
14477 * @property __ygDragDrop
14480 __ygDragDrop: true,
14483 * Set to true when horizontal contraints are applied
14484 * @property constrainX
14491 * Set to true when vertical contraints are applied
14492 * @property constrainY
14499 * The left constraint
14507 * The right constraint
14515 * The up constraint
14524 * The down constraint
14532 * Maintain offsets when we resetconstraints. Set to true when you want
14533 * the position of the element relative to its parent to stay the same
14534 * when the page changes
14536 * @property maintainOffset
14539 maintainOffset: false,
14542 * Array of pixel locations the element will snap to if we specified a
14543 * horizontal graduation/interval. This array is generated automatically
14544 * when you define a tick interval.
14551 * Array of pixel locations the element will snap to if we specified a
14552 * vertical graduation/interval. This array is generated automatically
14553 * when you define a tick interval.
14560 * By default the drag and drop instance will only respond to the primary
14561 * button click (left button for a right-handed mouse). Set to true to
14562 * allow drag and drop to start with any mouse click that is propogated
14564 * @property primaryButtonOnly
14567 primaryButtonOnly: true,
14570 * The availabe property is false until the linked dom element is accessible.
14571 * @property available
14577 * By default, drags can only be initiated if the mousedown occurs in the
14578 * region the linked element is. This is done in part to work around a
14579 * bug in some browsers that mis-report the mousedown if the previous
14580 * mouseup happened outside of the window. This property is set to true
14581 * if outer handles are defined.
14583 * @property hasOuterHandles
14587 hasOuterHandles: false,
14590 * Code that executes immediately before the startDrag event
14591 * @method b4StartDrag
14594 b4StartDrag: function(x, y) { },
14597 * Abstract method called after a drag/drop object is clicked
14598 * and the drag or mousedown time thresholds have beeen met.
14599 * @method startDrag
14600 * @param {int} X click location
14601 * @param {int} Y click location
14603 startDrag: function(x, y) { /* override this */ },
14606 * Code that executes immediately before the onDrag event
14610 b4Drag: function(e) { },
14613 * Abstract method called during the onMouseMove event while dragging an
14616 * @param {Event} e the mousemove event
14618 onDrag: function(e) { /* override this */ },
14621 * Abstract method called when this element fist begins hovering over
14622 * another DragDrop obj
14623 * @method onDragEnter
14624 * @param {Event} e the mousemove event
14625 * @param {String|DragDrop[]} id In POINT mode, the element
14626 * id this is hovering over. In INTERSECT mode, an array of one or more
14627 * dragdrop items being hovered over.
14629 onDragEnter: function(e, id) { /* override this */ },
14632 * Code that executes immediately before the onDragOver event
14633 * @method b4DragOver
14636 b4DragOver: function(e) { },
14639 * Abstract method called when this element is hovering over another
14641 * @method onDragOver
14642 * @param {Event} e the mousemove event
14643 * @param {String|DragDrop[]} id In POINT mode, the element
14644 * id this is hovering over. In INTERSECT mode, an array of dd items
14645 * being hovered over.
14647 onDragOver: function(e, id) { /* override this */ },
14650 * Code that executes immediately before the onDragOut event
14651 * @method b4DragOut
14654 b4DragOut: function(e) { },
14657 * Abstract method called when we are no longer hovering over an element
14658 * @method onDragOut
14659 * @param {Event} e the mousemove event
14660 * @param {String|DragDrop[]} id In POINT mode, the element
14661 * id this was hovering over. In INTERSECT mode, an array of dd items
14662 * that the mouse is no longer over.
14664 onDragOut: function(e, id) { /* override this */ },
14667 * Code that executes immediately before the onDragDrop event
14668 * @method b4DragDrop
14671 b4DragDrop: function(e) { },
14674 * Abstract method called when this item is dropped on another DragDrop
14676 * @method onDragDrop
14677 * @param {Event} e the mouseup event
14678 * @param {String|DragDrop[]} id In POINT mode, the element
14679 * id this was dropped on. In INTERSECT mode, an array of dd items this
14682 onDragDrop: function(e, id) { /* override this */ },
14685 * Abstract method called when this item is dropped on an area with no
14687 * @method onInvalidDrop
14688 * @param {Event} e the mouseup event
14690 onInvalidDrop: function(e) { /* override this */ },
14693 * Code that executes immediately before the endDrag event
14694 * @method b4EndDrag
14697 b4EndDrag: function(e) { },
14700 * Fired when we are done dragging the object
14702 * @param {Event} e the mouseup event
14704 endDrag: function(e) { /* override this */ },
14707 * Code executed immediately before the onMouseDown event
14708 * @method b4MouseDown
14709 * @param {Event} e the mousedown event
14712 b4MouseDown: function(e) { },
14715 * Event handler that fires when a drag/drop obj gets a mousedown
14716 * @method onMouseDown
14717 * @param {Event} e the mousedown event
14719 onMouseDown: function(e) { /* override this */ },
14722 * Event handler that fires when a drag/drop obj gets a mouseup
14723 * @method onMouseUp
14724 * @param {Event} e the mouseup event
14726 onMouseUp: function(e) { /* override this */ },
14729 * Override the onAvailable method to do what is needed after the initial
14730 * position was determined.
14731 * @method onAvailable
14733 onAvailable: function () {
14737 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14740 defaultPadding : {left:0, right:0, top:0, bottom:0},
14743 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14747 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14748 { dragElId: "existingProxyDiv" });
14749 dd.startDrag = function(){
14750 this.constrainTo("parent-id");
14753 * Or you can initalize it using the {@link Roo.Element} object:
14755 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14756 startDrag : function(){
14757 this.constrainTo("parent-id");
14761 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14762 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14763 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14764 * an object containing the sides to pad. For example: {right:10, bottom:10}
14765 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14767 constrainTo : function(constrainTo, pad, inContent){
14768 if(typeof pad == "number"){
14769 pad = {left: pad, right:pad, top:pad, bottom:pad};
14771 pad = pad || this.defaultPadding;
14772 var b = Roo.get(this.getEl()).getBox();
14773 var ce = Roo.get(constrainTo);
14774 var s = ce.getScroll();
14775 var c, cd = ce.dom;
14776 if(cd == document.body){
14777 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14780 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14784 var topSpace = b.y - c.y;
14785 var leftSpace = b.x - c.x;
14787 this.resetConstraints();
14788 this.setXConstraint(leftSpace - (pad.left||0), // left
14789 c.width - leftSpace - b.width - (pad.right||0) //right
14791 this.setYConstraint(topSpace - (pad.top||0), //top
14792 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14797 * Returns a reference to the linked element
14799 * @return {HTMLElement} the html element
14801 getEl: function() {
14802 if (!this._domRef) {
14803 this._domRef = Roo.getDom(this.id);
14806 return this._domRef;
14810 * Returns a reference to the actual element to drag. By default this is
14811 * the same as the html element, but it can be assigned to another
14812 * element. An example of this can be found in Roo.dd.DDProxy
14813 * @method getDragEl
14814 * @return {HTMLElement} the html element
14816 getDragEl: function() {
14817 return Roo.getDom(this.dragElId);
14821 * Sets up the DragDrop object. Must be called in the constructor of any
14822 * Roo.dd.DragDrop subclass
14824 * @param id the id of the linked element
14825 * @param {String} sGroup the group of related items
14826 * @param {object} config configuration attributes
14828 init: function(id, sGroup, config) {
14829 this.initTarget(id, sGroup, config);
14830 Event.on(this.id, "mousedown", this.handleMouseDown, this);
14831 // Event.on(this.id, "selectstart", Event.preventDefault);
14835 * Initializes Targeting functionality only... the object does not
14836 * get a mousedown handler.
14837 * @method initTarget
14838 * @param id the id of the linked element
14839 * @param {String} sGroup the group of related items
14840 * @param {object} config configuration attributes
14842 initTarget: function(id, sGroup, config) {
14844 // configuration attributes
14845 this.config = config || {};
14847 // create a local reference to the drag and drop manager
14848 this.DDM = Roo.dd.DDM;
14849 // initialize the groups array
14852 // assume that we have an element reference instead of an id if the
14853 // parameter is not a string
14854 if (typeof id !== "string") {
14861 // add to an interaction group
14862 this.addToGroup((sGroup) ? sGroup : "default");
14864 // We don't want to register this as the handle with the manager
14865 // so we just set the id rather than calling the setter.
14866 this.handleElId = id;
14868 // the linked element is the element that gets dragged by default
14869 this.setDragElId(id);
14871 // by default, clicked anchors will not start drag operations.
14872 this.invalidHandleTypes = { A: "A" };
14873 this.invalidHandleIds = {};
14874 this.invalidHandleClasses = [];
14876 this.applyConfig();
14878 this.handleOnAvailable();
14882 * Applies the configuration parameters that were passed into the constructor.
14883 * This is supposed to happen at each level through the inheritance chain. So
14884 * a DDProxy implentation will execute apply config on DDProxy, DD, and
14885 * DragDrop in order to get all of the parameters that are available in
14887 * @method applyConfig
14889 applyConfig: function() {
14891 // configurable properties:
14892 // padding, isTarget, maintainOffset, primaryButtonOnly
14893 this.padding = this.config.padding || [0, 0, 0, 0];
14894 this.isTarget = (this.config.isTarget !== false);
14895 this.maintainOffset = (this.config.maintainOffset);
14896 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
14901 * Executed when the linked element is available
14902 * @method handleOnAvailable
14905 handleOnAvailable: function() {
14906 this.available = true;
14907 this.resetConstraints();
14908 this.onAvailable();
14912 * Configures the padding for the target zone in px. Effectively expands
14913 * (or reduces) the virtual object size for targeting calculations.
14914 * Supports css-style shorthand; if only one parameter is passed, all sides
14915 * will have that padding, and if only two are passed, the top and bottom
14916 * will have the first param, the left and right the second.
14917 * @method setPadding
14918 * @param {int} iTop Top pad
14919 * @param {int} iRight Right pad
14920 * @param {int} iBot Bot pad
14921 * @param {int} iLeft Left pad
14923 setPadding: function(iTop, iRight, iBot, iLeft) {
14924 // this.padding = [iLeft, iRight, iTop, iBot];
14925 if (!iRight && 0 !== iRight) {
14926 this.padding = [iTop, iTop, iTop, iTop];
14927 } else if (!iBot && 0 !== iBot) {
14928 this.padding = [iTop, iRight, iTop, iRight];
14930 this.padding = [iTop, iRight, iBot, iLeft];
14935 * Stores the initial placement of the linked element.
14936 * @method setInitialPosition
14937 * @param {int} diffX the X offset, default 0
14938 * @param {int} diffY the Y offset, default 0
14940 setInitPosition: function(diffX, diffY) {
14941 var el = this.getEl();
14943 if (!this.DDM.verifyEl(el)) {
14947 var dx = diffX || 0;
14948 var dy = diffY || 0;
14950 var p = Dom.getXY( el );
14952 this.initPageX = p[0] - dx;
14953 this.initPageY = p[1] - dy;
14955 this.lastPageX = p[0];
14956 this.lastPageY = p[1];
14959 this.setStartPosition(p);
14963 * Sets the start position of the element. This is set when the obj
14964 * is initialized, the reset when a drag is started.
14965 * @method setStartPosition
14966 * @param pos current position (from previous lookup)
14969 setStartPosition: function(pos) {
14970 var p = pos || Dom.getXY( this.getEl() );
14971 this.deltaSetXY = null;
14973 this.startPageX = p[0];
14974 this.startPageY = p[1];
14978 * Add this instance to a group of related drag/drop objects. All
14979 * instances belong to at least one group, and can belong to as many
14980 * groups as needed.
14981 * @method addToGroup
14982 * @param sGroup {string} the name of the group
14984 addToGroup: function(sGroup) {
14985 this.groups[sGroup] = true;
14986 this.DDM.regDragDrop(this, sGroup);
14990 * Remove's this instance from the supplied interaction group
14991 * @method removeFromGroup
14992 * @param {string} sGroup The group to drop
14994 removeFromGroup: function(sGroup) {
14995 if (this.groups[sGroup]) {
14996 delete this.groups[sGroup];
14999 this.DDM.removeDDFromGroup(this, sGroup);
15003 * Allows you to specify that an element other than the linked element
15004 * will be moved with the cursor during a drag
15005 * @method setDragElId
15006 * @param id {string} the id of the element that will be used to initiate the drag
15008 setDragElId: function(id) {
15009 this.dragElId = id;
15013 * Allows you to specify a child of the linked element that should be
15014 * used to initiate the drag operation. An example of this would be if
15015 * you have a content div with text and links. Clicking anywhere in the
15016 * content area would normally start the drag operation. Use this method
15017 * to specify that an element inside of the content div is the element
15018 * that starts the drag operation.
15019 * @method setHandleElId
15020 * @param id {string} the id of the element that will be used to
15021 * initiate the drag.
15023 setHandleElId: function(id) {
15024 if (typeof id !== "string") {
15027 this.handleElId = id;
15028 this.DDM.regHandle(this.id, id);
15032 * Allows you to set an element outside of the linked element as a drag
15034 * @method setOuterHandleElId
15035 * @param id the id of the element that will be used to initiate the drag
15037 setOuterHandleElId: function(id) {
15038 if (typeof id !== "string") {
15041 Event.on(id, "mousedown",
15042 this.handleMouseDown, this);
15043 this.setHandleElId(id);
15045 this.hasOuterHandles = true;
15049 * Remove all drag and drop hooks for this element
15052 unreg: function() {
15053 Event.un(this.id, "mousedown",
15054 this.handleMouseDown);
15055 this._domRef = null;
15056 this.DDM._remove(this);
15059 destroy : function(){
15064 * Returns true if this instance is locked, or the drag drop mgr is locked
15065 * (meaning that all drag/drop is disabled on the page.)
15067 * @return {boolean} true if this obj or all drag/drop is locked, else
15070 isLocked: function() {
15071 return (this.DDM.isLocked() || this.locked);
15075 * Fired when this object is clicked
15076 * @method handleMouseDown
15078 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15081 handleMouseDown: function(e, oDD){
15082 if (this.primaryButtonOnly && e.button != 0) {
15086 if (this.isLocked()) {
15090 this.DDM.refreshCache(this.groups);
15092 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15093 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15095 if (this.clickValidator(e)) {
15097 // set the initial element position
15098 this.setStartPosition();
15101 this.b4MouseDown(e);
15102 this.onMouseDown(e);
15104 this.DDM.handleMouseDown(e, this);
15106 this.DDM.stopEvent(e);
15114 clickValidator: function(e) {
15115 var target = e.getTarget();
15116 return ( this.isValidHandleChild(target) &&
15117 (this.id == this.handleElId ||
15118 this.DDM.handleWasClicked(target, this.id)) );
15122 * Allows you to specify a tag name that should not start a drag operation
15123 * when clicked. This is designed to facilitate embedding links within a
15124 * drag handle that do something other than start the drag.
15125 * @method addInvalidHandleType
15126 * @param {string} tagName the type of element to exclude
15128 addInvalidHandleType: function(tagName) {
15129 var type = tagName.toUpperCase();
15130 this.invalidHandleTypes[type] = type;
15134 * Lets you to specify an element id for a child of a drag handle
15135 * that should not initiate a drag
15136 * @method addInvalidHandleId
15137 * @param {string} id the element id of the element you wish to ignore
15139 addInvalidHandleId: function(id) {
15140 if (typeof id !== "string") {
15143 this.invalidHandleIds[id] = id;
15147 * Lets you specify a css class of elements that will not initiate a drag
15148 * @method addInvalidHandleClass
15149 * @param {string} cssClass the class of the elements you wish to ignore
15151 addInvalidHandleClass: function(cssClass) {
15152 this.invalidHandleClasses.push(cssClass);
15156 * Unsets an excluded tag name set by addInvalidHandleType
15157 * @method removeInvalidHandleType
15158 * @param {string} tagName the type of element to unexclude
15160 removeInvalidHandleType: function(tagName) {
15161 var type = tagName.toUpperCase();
15162 // this.invalidHandleTypes[type] = null;
15163 delete this.invalidHandleTypes[type];
15167 * Unsets an invalid handle id
15168 * @method removeInvalidHandleId
15169 * @param {string} id the id of the element to re-enable
15171 removeInvalidHandleId: function(id) {
15172 if (typeof id !== "string") {
15175 delete this.invalidHandleIds[id];
15179 * Unsets an invalid css class
15180 * @method removeInvalidHandleClass
15181 * @param {string} cssClass the class of the element(s) you wish to
15184 removeInvalidHandleClass: function(cssClass) {
15185 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15186 if (this.invalidHandleClasses[i] == cssClass) {
15187 delete this.invalidHandleClasses[i];
15193 * Checks the tag exclusion list to see if this click should be ignored
15194 * @method isValidHandleChild
15195 * @param {HTMLElement} node the HTMLElement to evaluate
15196 * @return {boolean} true if this is a valid tag type, false if not
15198 isValidHandleChild: function(node) {
15201 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15204 nodeName = node.nodeName.toUpperCase();
15206 nodeName = node.nodeName;
15208 valid = valid && !this.invalidHandleTypes[nodeName];
15209 valid = valid && !this.invalidHandleIds[node.id];
15211 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15212 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15221 * Create the array of horizontal tick marks if an interval was specified
15222 * in setXConstraint().
15223 * @method setXTicks
15226 setXTicks: function(iStartX, iTickSize) {
15228 this.xTickSize = iTickSize;
15232 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15234 this.xTicks[this.xTicks.length] = i;
15239 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15241 this.xTicks[this.xTicks.length] = i;
15246 this.xTicks.sort(this.DDM.numericSort) ;
15250 * Create the array of vertical tick marks if an interval was specified in
15251 * setYConstraint().
15252 * @method setYTicks
15255 setYTicks: function(iStartY, iTickSize) {
15257 this.yTickSize = iTickSize;
15261 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15263 this.yTicks[this.yTicks.length] = i;
15268 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15270 this.yTicks[this.yTicks.length] = i;
15275 this.yTicks.sort(this.DDM.numericSort) ;
15279 * By default, the element can be dragged any place on the screen. Use
15280 * this method to limit the horizontal travel of the element. Pass in
15281 * 0,0 for the parameters if you want to lock the drag to the y axis.
15282 * @method setXConstraint
15283 * @param {int} iLeft the number of pixels the element can move to the left
15284 * @param {int} iRight the number of pixels the element can move to the
15286 * @param {int} iTickSize optional parameter for specifying that the
15288 * should move iTickSize pixels at a time.
15290 setXConstraint: function(iLeft, iRight, iTickSize) {
15291 this.leftConstraint = iLeft;
15292 this.rightConstraint = iRight;
15294 this.minX = this.initPageX - iLeft;
15295 this.maxX = this.initPageX + iRight;
15296 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15298 this.constrainX = true;
15302 * Clears any constraints applied to this instance. Also clears ticks
15303 * since they can't exist independent of a constraint at this time.
15304 * @method clearConstraints
15306 clearConstraints: function() {
15307 this.constrainX = false;
15308 this.constrainY = false;
15313 * Clears any tick interval defined for this instance
15314 * @method clearTicks
15316 clearTicks: function() {
15317 this.xTicks = null;
15318 this.yTicks = null;
15319 this.xTickSize = 0;
15320 this.yTickSize = 0;
15324 * By default, the element can be dragged any place on the screen. Set
15325 * this to limit the vertical travel of the element. Pass in 0,0 for the
15326 * parameters if you want to lock the drag to the x axis.
15327 * @method setYConstraint
15328 * @param {int} iUp the number of pixels the element can move up
15329 * @param {int} iDown the number of pixels the element can move down
15330 * @param {int} iTickSize optional parameter for specifying that the
15331 * element should move iTickSize pixels at a time.
15333 setYConstraint: function(iUp, iDown, iTickSize) {
15334 this.topConstraint = iUp;
15335 this.bottomConstraint = iDown;
15337 this.minY = this.initPageY - iUp;
15338 this.maxY = this.initPageY + iDown;
15339 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15341 this.constrainY = true;
15346 * resetConstraints must be called if you manually reposition a dd element.
15347 * @method resetConstraints
15348 * @param {boolean} maintainOffset
15350 resetConstraints: function() {
15353 // Maintain offsets if necessary
15354 if (this.initPageX || this.initPageX === 0) {
15355 // figure out how much this thing has moved
15356 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15357 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15359 this.setInitPosition(dx, dy);
15361 // This is the first time we have detected the element's position
15363 this.setInitPosition();
15366 if (this.constrainX) {
15367 this.setXConstraint( this.leftConstraint,
15368 this.rightConstraint,
15372 if (this.constrainY) {
15373 this.setYConstraint( this.topConstraint,
15374 this.bottomConstraint,
15380 * Normally the drag element is moved pixel by pixel, but we can specify
15381 * that it move a number of pixels at a time. This method resolves the
15382 * location when we have it set up like this.
15384 * @param {int} val where we want to place the object
15385 * @param {int[]} tickArray sorted array of valid points
15386 * @return {int} the closest tick
15389 getTick: function(val, tickArray) {
15392 // If tick interval is not defined, it is effectively 1 pixel,
15393 // so we return the value passed to us.
15395 } else if (tickArray[0] >= val) {
15396 // The value is lower than the first tick, so we return the first
15398 return tickArray[0];
15400 for (var i=0, len=tickArray.length; i<len; ++i) {
15402 if (tickArray[next] && tickArray[next] >= val) {
15403 var diff1 = val - tickArray[i];
15404 var diff2 = tickArray[next] - val;
15405 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15409 // The value is larger than the last tick, so we return the last
15411 return tickArray[tickArray.length - 1];
15418 * @return {string} string representation of the dd obj
15420 toString: function() {
15421 return ("DragDrop " + this.id);
15429 * Ext JS Library 1.1.1
15430 * Copyright(c) 2006-2007, Ext JS, LLC.
15432 * Originally Released Under LGPL - original licence link has changed is not relivant.
15435 * <script type="text/javascript">
15440 * The drag and drop utility provides a framework for building drag and drop
15441 * applications. In addition to enabling drag and drop for specific elements,
15442 * the drag and drop elements are tracked by the manager class, and the
15443 * interactions between the various elements are tracked during the drag and
15444 * the implementing code is notified about these important moments.
15447 // Only load the library once. Rewriting the manager class would orphan
15448 // existing drag and drop instances.
15449 if (!Roo.dd.DragDropMgr) {
15452 * @class Roo.dd.DragDropMgr
15453 * DragDropMgr is a singleton that tracks the element interaction for
15454 * all DragDrop items in the window. Generally, you will not call
15455 * this class directly, but it does have helper methods that could
15456 * be useful in your DragDrop implementations.
15459 Roo.dd.DragDropMgr = function() {
15461 var Event = Roo.EventManager;
15466 * Two dimensional Array of registered DragDrop objects. The first
15467 * dimension is the DragDrop item group, the second the DragDrop
15470 * @type {string: string}
15477 * Array of element ids defined as drag handles. Used to determine
15478 * if the element that generated the mousedown event is actually the
15479 * handle and not the html element itself.
15480 * @property handleIds
15481 * @type {string: string}
15488 * the DragDrop object that is currently being dragged
15489 * @property dragCurrent
15497 * the DragDrop object(s) that are being hovered over
15498 * @property dragOvers
15506 * the X distance between the cursor and the object being dragged
15515 * the Y distance between the cursor and the object being dragged
15524 * Flag to determine if we should prevent the default behavior of the
15525 * events we define. By default this is true, but this can be set to
15526 * false if you need the default behavior (not recommended)
15527 * @property preventDefault
15531 preventDefault: true,
15534 * Flag to determine if we should stop the propagation of the events
15535 * we generate. This is true by default but you may want to set it to
15536 * false if the html element contains other features that require the
15538 * @property stopPropagation
15542 stopPropagation: true,
15545 * Internal flag that is set to true when drag and drop has been
15547 * @property initialized
15554 * All drag and drop can be disabled.
15562 * Called the first time an element is registered.
15568 this.initialized = true;
15572 * In point mode, drag and drop interaction is defined by the
15573 * location of the cursor during the drag/drop
15581 * In intersect mode, drag and drop interactio nis defined by the
15582 * overlap of two or more drag and drop objects.
15583 * @property INTERSECT
15590 * The current drag and drop mode. Default: POINT
15598 * Runs method on all drag and drop objects
15599 * @method _execOnAll
15603 _execOnAll: function(sMethod, args) {
15604 for (var i in this.ids) {
15605 for (var j in this.ids[i]) {
15606 var oDD = this.ids[i][j];
15607 if (! this.isTypeOfDD(oDD)) {
15610 oDD[sMethod].apply(oDD, args);
15616 * Drag and drop initialization. Sets up the global event handlers
15621 _onLoad: function() {
15626 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15627 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15628 Event.on(window, "unload", this._onUnload, this, true);
15629 Event.on(window, "resize", this._onResize, this, true);
15630 // Event.on(window, "mouseout", this._test);
15635 * Reset constraints on all drag and drop objs
15636 * @method _onResize
15640 _onResize: function(e) {
15641 this._execOnAll("resetConstraints", []);
15645 * Lock all drag and drop functionality
15649 lock: function() { this.locked = true; },
15652 * Unlock all drag and drop functionality
15656 unlock: function() { this.locked = false; },
15659 * Is drag and drop locked?
15661 * @return {boolean} True if drag and drop is locked, false otherwise.
15664 isLocked: function() { return this.locked; },
15667 * Location cache that is set for all drag drop objects when a drag is
15668 * initiated, cleared when the drag is finished.
15669 * @property locationCache
15676 * Set useCache to false if you want to force object the lookup of each
15677 * drag and drop linked element constantly during a drag.
15678 * @property useCache
15685 * The number of pixels that the mouse needs to move after the
15686 * mousedown before the drag is initiated. Default=3;
15687 * @property clickPixelThresh
15691 clickPixelThresh: 3,
15694 * The number of milliseconds after the mousedown event to initiate the
15695 * drag if we don't get a mouseup event. Default=1000
15696 * @property clickTimeThresh
15700 clickTimeThresh: 350,
15703 * Flag that indicates that either the drag pixel threshold or the
15704 * mousdown time threshold has been met
15705 * @property dragThreshMet
15710 dragThreshMet: false,
15713 * Timeout used for the click time threshold
15714 * @property clickTimeout
15719 clickTimeout: null,
15722 * The X position of the mousedown event stored for later use when a
15723 * drag threshold is met.
15732 * The Y position of the mousedown event stored for later use when a
15733 * drag threshold is met.
15742 * Each DragDrop instance must be registered with the DragDropMgr.
15743 * This is executed in DragDrop.init()
15744 * @method regDragDrop
15745 * @param {DragDrop} oDD the DragDrop object to register
15746 * @param {String} sGroup the name of the group this element belongs to
15749 regDragDrop: function(oDD, sGroup) {
15750 if (!this.initialized) { this.init(); }
15752 if (!this.ids[sGroup]) {
15753 this.ids[sGroup] = {};
15755 this.ids[sGroup][oDD.id] = oDD;
15759 * Removes the supplied dd instance from the supplied group. Executed
15760 * by DragDrop.removeFromGroup, so don't call this function directly.
15761 * @method removeDDFromGroup
15765 removeDDFromGroup: function(oDD, sGroup) {
15766 if (!this.ids[sGroup]) {
15767 this.ids[sGroup] = {};
15770 var obj = this.ids[sGroup];
15771 if (obj && obj[oDD.id]) {
15772 delete obj[oDD.id];
15777 * Unregisters a drag and drop item. This is executed in
15778 * DragDrop.unreg, use that method instead of calling this directly.
15783 _remove: function(oDD) {
15784 for (var g in oDD.groups) {
15785 if (g && this.ids[g][oDD.id]) {
15786 delete this.ids[g][oDD.id];
15789 delete this.handleIds[oDD.id];
15793 * Each DragDrop handle element must be registered. This is done
15794 * automatically when executing DragDrop.setHandleElId()
15795 * @method regHandle
15796 * @param {String} sDDId the DragDrop id this element is a handle for
15797 * @param {String} sHandleId the id of the element that is the drag
15801 regHandle: function(sDDId, sHandleId) {
15802 if (!this.handleIds[sDDId]) {
15803 this.handleIds[sDDId] = {};
15805 this.handleIds[sDDId][sHandleId] = sHandleId;
15809 * Utility function to determine if a given element has been
15810 * registered as a drag drop item.
15811 * @method isDragDrop
15812 * @param {String} id the element id to check
15813 * @return {boolean} true if this element is a DragDrop item,
15817 isDragDrop: function(id) {
15818 return ( this.getDDById(id) ) ? true : false;
15822 * Returns the drag and drop instances that are in all groups the
15823 * passed in instance belongs to.
15824 * @method getRelated
15825 * @param {DragDrop} p_oDD the obj to get related data for
15826 * @param {boolean} bTargetsOnly if true, only return targetable objs
15827 * @return {DragDrop[]} the related instances
15830 getRelated: function(p_oDD, bTargetsOnly) {
15832 for (var i in p_oDD.groups) {
15833 for (j in this.ids[i]) {
15834 var dd = this.ids[i][j];
15835 if (! this.isTypeOfDD(dd)) {
15838 if (!bTargetsOnly || dd.isTarget) {
15839 oDDs[oDDs.length] = dd;
15848 * Returns true if the specified dd target is a legal target for
15849 * the specifice drag obj
15850 * @method isLegalTarget
15851 * @param {DragDrop} the drag obj
15852 * @param {DragDrop} the target
15853 * @return {boolean} true if the target is a legal target for the
15857 isLegalTarget: function (oDD, oTargetDD) {
15858 var targets = this.getRelated(oDD, true);
15859 for (var i=0, len=targets.length;i<len;++i) {
15860 if (targets[i].id == oTargetDD.id) {
15869 * My goal is to be able to transparently determine if an object is
15870 * typeof DragDrop, and the exact subclass of DragDrop. typeof
15871 * returns "object", oDD.constructor.toString() always returns
15872 * "DragDrop" and not the name of the subclass. So for now it just
15873 * evaluates a well-known variable in DragDrop.
15874 * @method isTypeOfDD
15875 * @param {Object} the object to evaluate
15876 * @return {boolean} true if typeof oDD = DragDrop
15879 isTypeOfDD: function (oDD) {
15880 return (oDD && oDD.__ygDragDrop);
15884 * Utility function to determine if a given element has been
15885 * registered as a drag drop handle for the given Drag Drop object.
15887 * @param {String} id the element id to check
15888 * @return {boolean} true if this element is a DragDrop handle, false
15892 isHandle: function(sDDId, sHandleId) {
15893 return ( this.handleIds[sDDId] &&
15894 this.handleIds[sDDId][sHandleId] );
15898 * Returns the DragDrop instance for a given id
15899 * @method getDDById
15900 * @param {String} id the id of the DragDrop object
15901 * @return {DragDrop} the drag drop object, null if it is not found
15904 getDDById: function(id) {
15905 for (var i in this.ids) {
15906 if (this.ids[i][id]) {
15907 return this.ids[i][id];
15914 * Fired after a registered DragDrop object gets the mousedown event.
15915 * Sets up the events required to track the object being dragged
15916 * @method handleMouseDown
15917 * @param {Event} e the event
15918 * @param oDD the DragDrop object being dragged
15922 handleMouseDown: function(e, oDD) {
15924 Roo.QuickTips.disable();
15926 this.currentTarget = e.getTarget();
15928 this.dragCurrent = oDD;
15930 var el = oDD.getEl();
15932 // track start position
15933 this.startX = e.getPageX();
15934 this.startY = e.getPageY();
15936 this.deltaX = this.startX - el.offsetLeft;
15937 this.deltaY = this.startY - el.offsetTop;
15939 this.dragThreshMet = false;
15941 this.clickTimeout = setTimeout(
15943 var DDM = Roo.dd.DDM;
15944 DDM.startDrag(DDM.startX, DDM.startY);
15946 this.clickTimeThresh );
15950 * Fired when either the drag pixel threshol or the mousedown hold
15951 * time threshold has been met.
15952 * @method startDrag
15953 * @param x {int} the X position of the original mousedown
15954 * @param y {int} the Y position of the original mousedown
15957 startDrag: function(x, y) {
15958 clearTimeout(this.clickTimeout);
15959 if (this.dragCurrent) {
15960 this.dragCurrent.b4StartDrag(x, y);
15961 this.dragCurrent.startDrag(x, y);
15963 this.dragThreshMet = true;
15967 * Internal function to handle the mouseup event. Will be invoked
15968 * from the context of the document.
15969 * @method handleMouseUp
15970 * @param {Event} e the event
15974 handleMouseUp: function(e) {
15977 Roo.QuickTips.enable();
15979 if (! this.dragCurrent) {
15983 clearTimeout(this.clickTimeout);
15985 if (this.dragThreshMet) {
15986 this.fireEvents(e, true);
15996 * Utility to stop event propagation and event default, if these
15997 * features are turned on.
15998 * @method stopEvent
15999 * @param {Event} e the event as returned by this.getEvent()
16002 stopEvent: function(e){
16003 if(this.stopPropagation) {
16004 e.stopPropagation();
16007 if (this.preventDefault) {
16008 e.preventDefault();
16013 * Internal function to clean up event handlers after the drag
16014 * operation is complete
16016 * @param {Event} e the event
16020 stopDrag: function(e) {
16021 // Fire the drag end event for the item that was dragged
16022 if (this.dragCurrent) {
16023 if (this.dragThreshMet) {
16024 this.dragCurrent.b4EndDrag(e);
16025 this.dragCurrent.endDrag(e);
16028 this.dragCurrent.onMouseUp(e);
16031 this.dragCurrent = null;
16032 this.dragOvers = {};
16036 * Internal function to handle the mousemove event. Will be invoked
16037 * from the context of the html element.
16039 * @TODO figure out what we can do about mouse events lost when the
16040 * user drags objects beyond the window boundary. Currently we can
16041 * detect this in internet explorer by verifying that the mouse is
16042 * down during the mousemove event. Firefox doesn't give us the
16043 * button state on the mousemove event.
16044 * @method handleMouseMove
16045 * @param {Event} e the event
16049 handleMouseMove: function(e) {
16050 if (! this.dragCurrent) {
16054 // var button = e.which || e.button;
16056 // check for IE mouseup outside of page boundary
16057 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16059 return this.handleMouseUp(e);
16062 if (!this.dragThreshMet) {
16063 var diffX = Math.abs(this.startX - e.getPageX());
16064 var diffY = Math.abs(this.startY - e.getPageY());
16065 if (diffX > this.clickPixelThresh ||
16066 diffY > this.clickPixelThresh) {
16067 this.startDrag(this.startX, this.startY);
16071 if (this.dragThreshMet) {
16072 this.dragCurrent.b4Drag(e);
16073 this.dragCurrent.onDrag(e);
16074 if(!this.dragCurrent.moveOnly){
16075 this.fireEvents(e, false);
16085 * Iterates over all of the DragDrop elements to find ones we are
16086 * hovering over or dropping on
16087 * @method fireEvents
16088 * @param {Event} e the event
16089 * @param {boolean} isDrop is this a drop op or a mouseover op?
16093 fireEvents: function(e, isDrop) {
16094 var dc = this.dragCurrent;
16096 // If the user did the mouse up outside of the window, we could
16097 // get here even though we have ended the drag.
16098 if (!dc || dc.isLocked()) {
16102 var pt = e.getPoint();
16104 // cache the previous dragOver array
16110 var enterEvts = [];
16112 // Check to see if the object(s) we were hovering over is no longer
16113 // being hovered over so we can fire the onDragOut event
16114 for (var i in this.dragOvers) {
16116 var ddo = this.dragOvers[i];
16118 if (! this.isTypeOfDD(ddo)) {
16122 if (! this.isOverTarget(pt, ddo, this.mode)) {
16123 outEvts.push( ddo );
16126 oldOvers[i] = true;
16127 delete this.dragOvers[i];
16130 for (var sGroup in dc.groups) {
16132 if ("string" != typeof sGroup) {
16136 for (i in this.ids[sGroup]) {
16137 var oDD = this.ids[sGroup][i];
16138 if (! this.isTypeOfDD(oDD)) {
16142 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16143 if (this.isOverTarget(pt, oDD, this.mode)) {
16144 // look for drop interactions
16146 dropEvts.push( oDD );
16147 // look for drag enter and drag over interactions
16150 // initial drag over: dragEnter fires
16151 if (!oldOvers[oDD.id]) {
16152 enterEvts.push( oDD );
16153 // subsequent drag overs: dragOver fires
16155 overEvts.push( oDD );
16158 this.dragOvers[oDD.id] = oDD;
16166 if (outEvts.length) {
16167 dc.b4DragOut(e, outEvts);
16168 dc.onDragOut(e, outEvts);
16171 if (enterEvts.length) {
16172 dc.onDragEnter(e, enterEvts);
16175 if (overEvts.length) {
16176 dc.b4DragOver(e, overEvts);
16177 dc.onDragOver(e, overEvts);
16180 if (dropEvts.length) {
16181 dc.b4DragDrop(e, dropEvts);
16182 dc.onDragDrop(e, dropEvts);
16186 // fire dragout events
16188 for (i=0, len=outEvts.length; i<len; ++i) {
16189 dc.b4DragOut(e, outEvts[i].id);
16190 dc.onDragOut(e, outEvts[i].id);
16193 // fire enter events
16194 for (i=0,len=enterEvts.length; i<len; ++i) {
16195 // dc.b4DragEnter(e, oDD.id);
16196 dc.onDragEnter(e, enterEvts[i].id);
16199 // fire over events
16200 for (i=0,len=overEvts.length; i<len; ++i) {
16201 dc.b4DragOver(e, overEvts[i].id);
16202 dc.onDragOver(e, overEvts[i].id);
16205 // fire drop events
16206 for (i=0, len=dropEvts.length; i<len; ++i) {
16207 dc.b4DragDrop(e, dropEvts[i].id);
16208 dc.onDragDrop(e, dropEvts[i].id);
16213 // notify about a drop that did not find a target
16214 if (isDrop && !dropEvts.length) {
16215 dc.onInvalidDrop(e);
16221 * Helper function for getting the best match from the list of drag
16222 * and drop objects returned by the drag and drop events when we are
16223 * in INTERSECT mode. It returns either the first object that the
16224 * cursor is over, or the object that has the greatest overlap with
16225 * the dragged element.
16226 * @method getBestMatch
16227 * @param {DragDrop[]} dds The array of drag and drop objects
16229 * @return {DragDrop} The best single match
16232 getBestMatch: function(dds) {
16234 // Return null if the input is not what we expect
16235 //if (!dds || !dds.length || dds.length == 0) {
16237 // If there is only one item, it wins
16238 //} else if (dds.length == 1) {
16240 var len = dds.length;
16245 // Loop through the targeted items
16246 for (var i=0; i<len; ++i) {
16248 // If the cursor is over the object, it wins. If the
16249 // cursor is over multiple matches, the first one we come
16251 if (dd.cursorIsOver) {
16254 // Otherwise the object with the most overlap wins
16257 winner.overlap.getArea() < dd.overlap.getArea()) {
16268 * Refreshes the cache of the top-left and bottom-right points of the
16269 * drag and drop objects in the specified group(s). This is in the
16270 * format that is stored in the drag and drop instance, so typical
16273 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16277 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16279 * @TODO this really should be an indexed array. Alternatively this
16280 * method could accept both.
16281 * @method refreshCache
16282 * @param {Object} groups an associative array of groups to refresh
16285 refreshCache: function(groups) {
16286 for (var sGroup in groups) {
16287 if ("string" != typeof sGroup) {
16290 for (var i in this.ids[sGroup]) {
16291 var oDD = this.ids[sGroup][i];
16293 if (this.isTypeOfDD(oDD)) {
16294 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16295 var loc = this.getLocation(oDD);
16297 this.locationCache[oDD.id] = loc;
16299 delete this.locationCache[oDD.id];
16300 // this will unregister the drag and drop object if
16301 // the element is not in a usable state
16310 * This checks to make sure an element exists and is in the DOM. The
16311 * main purpose is to handle cases where innerHTML is used to remove
16312 * drag and drop objects from the DOM. IE provides an 'unspecified
16313 * error' when trying to access the offsetParent of such an element
16315 * @param {HTMLElement} el the element to check
16316 * @return {boolean} true if the element looks usable
16319 verifyEl: function(el) {
16324 parent = el.offsetParent;
16327 parent = el.offsetParent;
16338 * Returns a Region object containing the drag and drop element's position
16339 * and size, including the padding configured for it
16340 * @method getLocation
16341 * @param {DragDrop} oDD the drag and drop object to get the
16343 * @return {Roo.lib.Region} a Region object representing the total area
16344 * the element occupies, including any padding
16345 * the instance is configured for.
16348 getLocation: function(oDD) {
16349 if (! this.isTypeOfDD(oDD)) {
16353 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16356 pos= Roo.lib.Dom.getXY(el);
16364 x2 = x1 + el.offsetWidth;
16366 y2 = y1 + el.offsetHeight;
16368 t = y1 - oDD.padding[0];
16369 r = x2 + oDD.padding[1];
16370 b = y2 + oDD.padding[2];
16371 l = x1 - oDD.padding[3];
16373 return new Roo.lib.Region( t, r, b, l );
16377 * Checks the cursor location to see if it over the target
16378 * @method isOverTarget
16379 * @param {Roo.lib.Point} pt The point to evaluate
16380 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16381 * @return {boolean} true if the mouse is over the target
16385 isOverTarget: function(pt, oTarget, intersect) {
16386 // use cache if available
16387 var loc = this.locationCache[oTarget.id];
16388 if (!loc || !this.useCache) {
16389 loc = this.getLocation(oTarget);
16390 this.locationCache[oTarget.id] = loc;
16398 oTarget.cursorIsOver = loc.contains( pt );
16400 // DragDrop is using this as a sanity check for the initial mousedown
16401 // in this case we are done. In POINT mode, if the drag obj has no
16402 // contraints, we are also done. Otherwise we need to evaluate the
16403 // location of the target as related to the actual location of the
16404 // dragged element.
16405 var dc = this.dragCurrent;
16406 if (!dc || !dc.getTargetCoord ||
16407 (!intersect && !dc.constrainX && !dc.constrainY)) {
16408 return oTarget.cursorIsOver;
16411 oTarget.overlap = null;
16413 // Get the current location of the drag element, this is the
16414 // location of the mouse event less the delta that represents
16415 // where the original mousedown happened on the element. We
16416 // need to consider constraints and ticks as well.
16417 var pos = dc.getTargetCoord(pt.x, pt.y);
16419 var el = dc.getDragEl();
16420 var curRegion = new Roo.lib.Region( pos.y,
16421 pos.x + el.offsetWidth,
16422 pos.y + el.offsetHeight,
16425 var overlap = curRegion.intersect(loc);
16428 oTarget.overlap = overlap;
16429 return (intersect) ? true : oTarget.cursorIsOver;
16436 * unload event handler
16437 * @method _onUnload
16441 _onUnload: function(e, me) {
16442 Roo.dd.DragDropMgr.unregAll();
16446 * Cleans up the drag and drop events and objects.
16451 unregAll: function() {
16453 if (this.dragCurrent) {
16455 this.dragCurrent = null;
16458 this._execOnAll("unreg", []);
16460 for (i in this.elementCache) {
16461 delete this.elementCache[i];
16464 this.elementCache = {};
16469 * A cache of DOM elements
16470 * @property elementCache
16477 * Get the wrapper for the DOM element specified
16478 * @method getElWrapper
16479 * @param {String} id the id of the element to get
16480 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16482 * @deprecated This wrapper isn't that useful
16485 getElWrapper: function(id) {
16486 var oWrapper = this.elementCache[id];
16487 if (!oWrapper || !oWrapper.el) {
16488 oWrapper = this.elementCache[id] =
16489 new this.ElementWrapper(Roo.getDom(id));
16495 * Returns the actual DOM element
16496 * @method getElement
16497 * @param {String} id the id of the elment to get
16498 * @return {Object} The element
16499 * @deprecated use Roo.getDom instead
16502 getElement: function(id) {
16503 return Roo.getDom(id);
16507 * Returns the style property for the DOM element (i.e.,
16508 * document.getElById(id).style)
16510 * @param {String} id the id of the elment to get
16511 * @return {Object} The style property of the element
16512 * @deprecated use Roo.getDom instead
16515 getCss: function(id) {
16516 var el = Roo.getDom(id);
16517 return (el) ? el.style : null;
16521 * Inner class for cached elements
16522 * @class DragDropMgr.ElementWrapper
16527 ElementWrapper: function(el) {
16532 this.el = el || null;
16537 this.id = this.el && el.id;
16539 * A reference to the style property
16542 this.css = this.el && el.style;
16546 * Returns the X position of an html element
16548 * @param el the element for which to get the position
16549 * @return {int} the X coordinate
16551 * @deprecated use Roo.lib.Dom.getX instead
16554 getPosX: function(el) {
16555 return Roo.lib.Dom.getX(el);
16559 * Returns the Y position of an html element
16561 * @param el the element for which to get the position
16562 * @return {int} the Y coordinate
16563 * @deprecated use Roo.lib.Dom.getY instead
16566 getPosY: function(el) {
16567 return Roo.lib.Dom.getY(el);
16571 * Swap two nodes. In IE, we use the native method, for others we
16572 * emulate the IE behavior
16574 * @param n1 the first node to swap
16575 * @param n2 the other node to swap
16578 swapNode: function(n1, n2) {
16582 var p = n2.parentNode;
16583 var s = n2.nextSibling;
16586 p.insertBefore(n1, n2);
16587 } else if (n2 == n1.nextSibling) {
16588 p.insertBefore(n2, n1);
16590 n1.parentNode.replaceChild(n2, n1);
16591 p.insertBefore(n1, s);
16597 * Returns the current scroll position
16598 * @method getScroll
16602 getScroll: function () {
16603 var t, l, dde=document.documentElement, db=document.body;
16604 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16606 l = dde.scrollLeft;
16613 return { top: t, left: l };
16617 * Returns the specified element style property
16619 * @param {HTMLElement} el the element
16620 * @param {string} styleProp the style property
16621 * @return {string} The value of the style property
16622 * @deprecated use Roo.lib.Dom.getStyle
16625 getStyle: function(el, styleProp) {
16626 return Roo.fly(el).getStyle(styleProp);
16630 * Gets the scrollTop
16631 * @method getScrollTop
16632 * @return {int} the document's scrollTop
16635 getScrollTop: function () { return this.getScroll().top; },
16638 * Gets the scrollLeft
16639 * @method getScrollLeft
16640 * @return {int} the document's scrollTop
16643 getScrollLeft: function () { return this.getScroll().left; },
16646 * Sets the x/y position of an element to the location of the
16649 * @param {HTMLElement} moveEl The element to move
16650 * @param {HTMLElement} targetEl The position reference element
16653 moveToEl: function (moveEl, targetEl) {
16654 var aCoord = Roo.lib.Dom.getXY(targetEl);
16655 Roo.lib.Dom.setXY(moveEl, aCoord);
16659 * Numeric array sort function
16660 * @method numericSort
16663 numericSort: function(a, b) { return (a - b); },
16667 * @property _timeoutCount
16674 * Trying to make the load order less important. Without this we get
16675 * an error if this file is loaded before the Event Utility.
16676 * @method _addListeners
16680 _addListeners: function() {
16681 var DDM = Roo.dd.DDM;
16682 if ( Roo.lib.Event && document ) {
16685 if (DDM._timeoutCount > 2000) {
16687 setTimeout(DDM._addListeners, 10);
16688 if (document && document.body) {
16689 DDM._timeoutCount += 1;
16696 * Recursively searches the immediate parent and all child nodes for
16697 * the handle element in order to determine wheter or not it was
16699 * @method handleWasClicked
16700 * @param node the html element to inspect
16703 handleWasClicked: function(node, id) {
16704 if (this.isHandle(id, node.id)) {
16707 // check to see if this is a text node child of the one we want
16708 var p = node.parentNode;
16711 if (this.isHandle(id, p.id)) {
16726 // shorter alias, save a few bytes
16727 Roo.dd.DDM = Roo.dd.DragDropMgr;
16728 Roo.dd.DDM._addListeners();
16732 * Ext JS Library 1.1.1
16733 * Copyright(c) 2006-2007, Ext JS, LLC.
16735 * Originally Released Under LGPL - original licence link has changed is not relivant.
16738 * <script type="text/javascript">
16743 * A DragDrop implementation where the linked element follows the
16744 * mouse cursor during a drag.
16745 * @extends Roo.dd.DragDrop
16747 * @param {String} id the id of the linked element
16748 * @param {String} sGroup the group of related DragDrop items
16749 * @param {object} config an object containing configurable attributes
16750 * Valid properties for DD:
16753 Roo.dd.DD = function(id, sGroup, config) {
16755 this.init(id, sGroup, config);
16759 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16762 * When set to true, the utility automatically tries to scroll the browser
16763 * window wehn a drag and drop element is dragged near the viewport boundary.
16764 * Defaults to true.
16771 * Sets the pointer offset to the distance between the linked element's top
16772 * left corner and the location the element was clicked
16773 * @method autoOffset
16774 * @param {int} iPageX the X coordinate of the click
16775 * @param {int} iPageY the Y coordinate of the click
16777 autoOffset: function(iPageX, iPageY) {
16778 var x = iPageX - this.startPageX;
16779 var y = iPageY - this.startPageY;
16780 this.setDelta(x, y);
16784 * Sets the pointer offset. You can call this directly to force the
16785 * offset to be in a particular location (e.g., pass in 0,0 to set it
16786 * to the center of the object)
16788 * @param {int} iDeltaX the distance from the left
16789 * @param {int} iDeltaY the distance from the top
16791 setDelta: function(iDeltaX, iDeltaY) {
16792 this.deltaX = iDeltaX;
16793 this.deltaY = iDeltaY;
16797 * Sets the drag element to the location of the mousedown or click event,
16798 * maintaining the cursor location relative to the location on the element
16799 * that was clicked. Override this if you want to place the element in a
16800 * location other than where the cursor is.
16801 * @method setDragElPos
16802 * @param {int} iPageX the X coordinate of the mousedown or drag event
16803 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16805 setDragElPos: function(iPageX, iPageY) {
16806 // the first time we do this, we are going to check to make sure
16807 // the element has css positioning
16809 var el = this.getDragEl();
16810 this.alignElWithMouse(el, iPageX, iPageY);
16814 * Sets the element to the location of the mousedown or click event,
16815 * maintaining the cursor location relative to the location on the element
16816 * that was clicked. Override this if you want to place the element in a
16817 * location other than where the cursor is.
16818 * @method alignElWithMouse
16819 * @param {HTMLElement} el the element to move
16820 * @param {int} iPageX the X coordinate of the mousedown or drag event
16821 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16823 alignElWithMouse: function(el, iPageX, iPageY) {
16824 var oCoord = this.getTargetCoord(iPageX, iPageY);
16825 var fly = el.dom ? el : Roo.fly(el);
16826 if (!this.deltaSetXY) {
16827 var aCoord = [oCoord.x, oCoord.y];
16829 var newLeft = fly.getLeft(true);
16830 var newTop = fly.getTop(true);
16831 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
16833 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
16836 this.cachePosition(oCoord.x, oCoord.y);
16837 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
16842 * Saves the most recent position so that we can reset the constraints and
16843 * tick marks on-demand. We need to know this so that we can calculate the
16844 * number of pixels the element is offset from its original position.
16845 * @method cachePosition
16846 * @param iPageX the current x position (optional, this just makes it so we
16847 * don't have to look it up again)
16848 * @param iPageY the current y position (optional, this just makes it so we
16849 * don't have to look it up again)
16851 cachePosition: function(iPageX, iPageY) {
16853 this.lastPageX = iPageX;
16854 this.lastPageY = iPageY;
16856 var aCoord = Roo.lib.Dom.getXY(this.getEl());
16857 this.lastPageX = aCoord[0];
16858 this.lastPageY = aCoord[1];
16863 * Auto-scroll the window if the dragged object has been moved beyond the
16864 * visible window boundary.
16865 * @method autoScroll
16866 * @param {int} x the drag element's x position
16867 * @param {int} y the drag element's y position
16868 * @param {int} h the height of the drag element
16869 * @param {int} w the width of the drag element
16872 autoScroll: function(x, y, h, w) {
16875 // The client height
16876 var clientH = Roo.lib.Dom.getViewWidth();
16878 // The client width
16879 var clientW = Roo.lib.Dom.getViewHeight();
16881 // The amt scrolled down
16882 var st = this.DDM.getScrollTop();
16884 // The amt scrolled right
16885 var sl = this.DDM.getScrollLeft();
16887 // Location of the bottom of the element
16890 // Location of the right of the element
16893 // The distance from the cursor to the bottom of the visible area,
16894 // adjusted so that we don't scroll if the cursor is beyond the
16895 // element drag constraints
16896 var toBot = (clientH + st - y - this.deltaY);
16898 // The distance from the cursor to the right of the visible area
16899 var toRight = (clientW + sl - x - this.deltaX);
16902 // How close to the edge the cursor must be before we scroll
16903 // var thresh = (document.all) ? 100 : 40;
16906 // How many pixels to scroll per autoscroll op. This helps to reduce
16907 // clunky scrolling. IE is more sensitive about this ... it needs this
16908 // value to be higher.
16909 var scrAmt = (document.all) ? 80 : 30;
16911 // Scroll down if we are near the bottom of the visible page and the
16912 // obj extends below the crease
16913 if ( bot > clientH && toBot < thresh ) {
16914 window.scrollTo(sl, st + scrAmt);
16917 // Scroll up if the window is scrolled down and the top of the object
16918 // goes above the top border
16919 if ( y < st && st > 0 && y - st < thresh ) {
16920 window.scrollTo(sl, st - scrAmt);
16923 // Scroll right if the obj is beyond the right border and the cursor is
16924 // near the border.
16925 if ( right > clientW && toRight < thresh ) {
16926 window.scrollTo(sl + scrAmt, st);
16929 // Scroll left if the window has been scrolled to the right and the obj
16930 // extends past the left border
16931 if ( x < sl && sl > 0 && x - sl < thresh ) {
16932 window.scrollTo(sl - scrAmt, st);
16938 * Finds the location the element should be placed if we want to move
16939 * it to where the mouse location less the click offset would place us.
16940 * @method getTargetCoord
16941 * @param {int} iPageX the X coordinate of the click
16942 * @param {int} iPageY the Y coordinate of the click
16943 * @return an object that contains the coordinates (Object.x and Object.y)
16946 getTargetCoord: function(iPageX, iPageY) {
16949 var x = iPageX - this.deltaX;
16950 var y = iPageY - this.deltaY;
16952 if (this.constrainX) {
16953 if (x < this.minX) { x = this.minX; }
16954 if (x > this.maxX) { x = this.maxX; }
16957 if (this.constrainY) {
16958 if (y < this.minY) { y = this.minY; }
16959 if (y > this.maxY) { y = this.maxY; }
16962 x = this.getTick(x, this.xTicks);
16963 y = this.getTick(y, this.yTicks);
16970 * Sets up config options specific to this class. Overrides
16971 * Roo.dd.DragDrop, but all versions of this method through the
16972 * inheritance chain are called
16974 applyConfig: function() {
16975 Roo.dd.DD.superclass.applyConfig.call(this);
16976 this.scroll = (this.config.scroll !== false);
16980 * Event that fires prior to the onMouseDown event. Overrides
16983 b4MouseDown: function(e) {
16984 // this.resetConstraints();
16985 this.autoOffset(e.getPageX(),
16990 * Event that fires prior to the onDrag event. Overrides
16993 b4Drag: function(e) {
16994 this.setDragElPos(e.getPageX(),
16998 toString: function() {
16999 return ("DD " + this.id);
17002 //////////////////////////////////////////////////////////////////////////
17003 // Debugging ygDragDrop events that can be overridden
17004 //////////////////////////////////////////////////////////////////////////
17006 startDrag: function(x, y) {
17009 onDrag: function(e) {
17012 onDragEnter: function(e, id) {
17015 onDragOver: function(e, id) {
17018 onDragOut: function(e, id) {
17021 onDragDrop: function(e, id) {
17024 endDrag: function(e) {
17031 * Ext JS Library 1.1.1
17032 * Copyright(c) 2006-2007, Ext JS, LLC.
17034 * Originally Released Under LGPL - original licence link has changed is not relivant.
17037 * <script type="text/javascript">
17041 * @class Roo.dd.DDProxy
17042 * A DragDrop implementation that inserts an empty, bordered div into
17043 * the document that follows the cursor during drag operations. At the time of
17044 * the click, the frame div is resized to the dimensions of the linked html
17045 * element, and moved to the exact location of the linked element.
17047 * References to the "frame" element refer to the single proxy element that
17048 * was created to be dragged in place of all DDProxy elements on the
17051 * @extends Roo.dd.DD
17053 * @param {String} id the id of the linked html element
17054 * @param {String} sGroup the group of related DragDrop objects
17055 * @param {object} config an object containing configurable attributes
17056 * Valid properties for DDProxy in addition to those in DragDrop:
17057 * resizeFrame, centerFrame, dragElId
17059 Roo.dd.DDProxy = function(id, sGroup, config) {
17061 this.init(id, sGroup, config);
17067 * The default drag frame div id
17068 * @property Roo.dd.DDProxy.dragElId
17072 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17074 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17077 * By default we resize the drag frame to be the same size as the element
17078 * we want to drag (this is to get the frame effect). We can turn it off
17079 * if we want a different behavior.
17080 * @property resizeFrame
17086 * By default the frame is positioned exactly where the drag element is, so
17087 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17088 * you do not have constraints on the obj is to have the drag frame centered
17089 * around the cursor. Set centerFrame to true for this effect.
17090 * @property centerFrame
17093 centerFrame: false,
17096 * Creates the proxy element if it does not yet exist
17097 * @method createFrame
17099 createFrame: function() {
17101 var body = document.body;
17103 if (!body || !body.firstChild) {
17104 setTimeout( function() { self.createFrame(); }, 50 );
17108 var div = this.getDragEl();
17111 div = document.createElement("div");
17112 div.id = this.dragElId;
17115 s.position = "absolute";
17116 s.visibility = "hidden";
17118 s.border = "2px solid #aaa";
17121 // appendChild can blow up IE if invoked prior to the window load event
17122 // while rendering a table. It is possible there are other scenarios
17123 // that would cause this to happen as well.
17124 body.insertBefore(div, body.firstChild);
17129 * Initialization for the drag frame element. Must be called in the
17130 * constructor of all subclasses
17131 * @method initFrame
17133 initFrame: function() {
17134 this.createFrame();
17137 applyConfig: function() {
17138 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17140 this.resizeFrame = (this.config.resizeFrame !== false);
17141 this.centerFrame = (this.config.centerFrame);
17142 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17146 * Resizes the drag frame to the dimensions of the clicked object, positions
17147 * it over the object, and finally displays it
17148 * @method showFrame
17149 * @param {int} iPageX X click position
17150 * @param {int} iPageY Y click position
17153 showFrame: function(iPageX, iPageY) {
17154 var el = this.getEl();
17155 var dragEl = this.getDragEl();
17156 var s = dragEl.style;
17158 this._resizeProxy();
17160 if (this.centerFrame) {
17161 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17162 Math.round(parseInt(s.height, 10)/2) );
17165 this.setDragElPos(iPageX, iPageY);
17167 Roo.fly(dragEl).show();
17171 * The proxy is automatically resized to the dimensions of the linked
17172 * element when a drag is initiated, unless resizeFrame is set to false
17173 * @method _resizeProxy
17176 _resizeProxy: function() {
17177 if (this.resizeFrame) {
17178 var el = this.getEl();
17179 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17183 // overrides Roo.dd.DragDrop
17184 b4MouseDown: function(e) {
17185 var x = e.getPageX();
17186 var y = e.getPageY();
17187 this.autoOffset(x, y);
17188 this.setDragElPos(x, y);
17191 // overrides Roo.dd.DragDrop
17192 b4StartDrag: function(x, y) {
17193 // show the drag frame
17194 this.showFrame(x, y);
17197 // overrides Roo.dd.DragDrop
17198 b4EndDrag: function(e) {
17199 Roo.fly(this.getDragEl()).hide();
17202 // overrides Roo.dd.DragDrop
17203 // By default we try to move the element to the last location of the frame.
17204 // This is so that the default behavior mirrors that of Roo.dd.DD.
17205 endDrag: function(e) {
17207 var lel = this.getEl();
17208 var del = this.getDragEl();
17210 // Show the drag frame briefly so we can get its position
17211 del.style.visibility = "";
17214 // Hide the linked element before the move to get around a Safari
17216 lel.style.visibility = "hidden";
17217 Roo.dd.DDM.moveToEl(lel, del);
17218 del.style.visibility = "hidden";
17219 lel.style.visibility = "";
17224 beforeMove : function(){
17228 afterDrag : function(){
17232 toString: function() {
17233 return ("DDProxy " + this.id);
17239 * Ext JS Library 1.1.1
17240 * Copyright(c) 2006-2007, Ext JS, LLC.
17242 * Originally Released Under LGPL - original licence link has changed is not relivant.
17245 * <script type="text/javascript">
17249 * @class Roo.dd.DDTarget
17250 * A DragDrop implementation that does not move, but can be a drop
17251 * target. You would get the same result by simply omitting implementation
17252 * for the event callbacks, but this way we reduce the processing cost of the
17253 * event listener and the callbacks.
17254 * @extends Roo.dd.DragDrop
17256 * @param {String} id the id of the element that is a drop target
17257 * @param {String} sGroup the group of related DragDrop objects
17258 * @param {object} config an object containing configurable attributes
17259 * Valid properties for DDTarget in addition to those in
17263 Roo.dd.DDTarget = function(id, sGroup, config) {
17265 this.initTarget(id, sGroup, config);
17269 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17270 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17271 toString: function() {
17272 return ("DDTarget " + this.id);
17277 * Ext JS Library 1.1.1
17278 * Copyright(c) 2006-2007, Ext JS, LLC.
17280 * Originally Released Under LGPL - original licence link has changed is not relivant.
17283 * <script type="text/javascript">
17288 * @class Roo.dd.ScrollManager
17289 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17290 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17293 Roo.dd.ScrollManager = function(){
17294 var ddm = Roo.dd.DragDropMgr;
17299 var onStop = function(e){
17304 var triggerRefresh = function(){
17305 if(ddm.dragCurrent){
17306 ddm.refreshCache(ddm.dragCurrent.groups);
17310 var doScroll = function(){
17311 if(ddm.dragCurrent){
17312 var dds = Roo.dd.ScrollManager;
17314 if(proc.el.scroll(proc.dir, dds.increment)){
17318 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17323 var clearProc = function(){
17325 clearInterval(proc.id);
17332 var startProc = function(el, dir){
17336 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17339 var onFire = function(e, isDrop){
17340 if(isDrop || !ddm.dragCurrent){ return; }
17341 var dds = Roo.dd.ScrollManager;
17342 if(!dragEl || dragEl != ddm.dragCurrent){
17343 dragEl = ddm.dragCurrent;
17344 // refresh regions on drag start
17345 dds.refreshCache();
17348 var xy = Roo.lib.Event.getXY(e);
17349 var pt = new Roo.lib.Point(xy[0], xy[1]);
17350 for(var id in els){
17351 var el = els[id], r = el._region;
17352 if(r && r.contains(pt) && el.isScrollable()){
17353 if(r.bottom - pt.y <= dds.thresh){
17355 startProc(el, "down");
17358 }else if(r.right - pt.x <= dds.thresh){
17360 startProc(el, "left");
17363 }else if(pt.y - r.top <= dds.thresh){
17365 startProc(el, "up");
17368 }else if(pt.x - r.left <= dds.thresh){
17370 startProc(el, "right");
17379 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17380 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17384 * Registers new overflow element(s) to auto scroll
17385 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17387 register : function(el){
17388 if(el instanceof Array){
17389 for(var i = 0, len = el.length; i < len; i++) {
17390 this.register(el[i]);
17399 * Unregisters overflow element(s) so they are no longer scrolled
17400 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17402 unregister : function(el){
17403 if(el instanceof Array){
17404 for(var i = 0, len = el.length; i < len; i++) {
17405 this.unregister(el[i]);
17414 * The number of pixels from the edge of a container the pointer needs to be to
17415 * trigger scrolling (defaults to 25)
17421 * The number of pixels to scroll in each scroll increment (defaults to 50)
17427 * The frequency of scrolls in milliseconds (defaults to 500)
17433 * True to animate the scroll (defaults to true)
17439 * The animation duration in seconds -
17440 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17446 * Manually trigger a cache refresh.
17448 refreshCache : function(){
17449 for(var id in els){
17450 if(typeof els[id] == 'object'){ // for people extending the object prototype
17451 els[id]._region = els[id].getRegion();
17458 * Ext JS Library 1.1.1
17459 * Copyright(c) 2006-2007, Ext JS, LLC.
17461 * Originally Released Under LGPL - original licence link has changed is not relivant.
17464 * <script type="text/javascript">
17469 * @class Roo.dd.Registry
17470 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17471 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17474 Roo.dd.Registry = function(){
17477 var autoIdSeed = 0;
17479 var getId = function(el, autogen){
17480 if(typeof el == "string"){
17484 if(!id && autogen !== false){
17485 id = "roodd-" + (++autoIdSeed);
17493 * Register a drag drop element
17494 * @param {String|HTMLElement} element The id or DOM node to register
17495 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17496 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17497 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17498 * populated in the data object (if applicable):
17500 Value Description<br />
17501 --------- ------------------------------------------<br />
17502 handles Array of DOM nodes that trigger dragging<br />
17503 for the element being registered<br />
17504 isHandle True if the element passed in triggers<br />
17505 dragging itself, else false
17508 register : function(el, data){
17510 if(typeof el == "string"){
17511 el = document.getElementById(el);
17514 elements[getId(el)] = data;
17515 if(data.isHandle !== false){
17516 handles[data.ddel.id] = data;
17519 var hs = data.handles;
17520 for(var i = 0, len = hs.length; i < len; i++){
17521 handles[getId(hs[i])] = data;
17527 * Unregister a drag drop element
17528 * @param {String|HTMLElement} element The id or DOM node to unregister
17530 unregister : function(el){
17531 var id = getId(el, false);
17532 var data = elements[id];
17534 delete elements[id];
17536 var hs = data.handles;
17537 for(var i = 0, len = hs.length; i < len; i++){
17538 delete handles[getId(hs[i], false)];
17545 * Returns the handle registered for a DOM Node by id
17546 * @param {String|HTMLElement} id The DOM node or id to look up
17547 * @return {Object} handle The custom handle data
17549 getHandle : function(id){
17550 if(typeof id != "string"){ // must be element?
17553 return handles[id];
17557 * Returns the handle that is registered for the DOM node that is the target of the event
17558 * @param {Event} e The event
17559 * @return {Object} handle The custom handle data
17561 getHandleFromEvent : function(e){
17562 var t = Roo.lib.Event.getTarget(e);
17563 return t ? handles[t.id] : null;
17567 * Returns a custom data object that is registered for a DOM node by id
17568 * @param {String|HTMLElement} id The DOM node or id to look up
17569 * @return {Object} data The custom data
17571 getTarget : function(id){
17572 if(typeof id != "string"){ // must be element?
17575 return elements[id];
17579 * Returns a custom data object that is registered for the DOM node that is the target of the event
17580 * @param {Event} e The event
17581 * @return {Object} data The custom data
17583 getTargetFromEvent : function(e){
17584 var t = Roo.lib.Event.getTarget(e);
17585 return t ? elements[t.id] || handles[t.id] : null;
17590 * Ext JS Library 1.1.1
17591 * Copyright(c) 2006-2007, Ext JS, LLC.
17593 * Originally Released Under LGPL - original licence link has changed is not relivant.
17596 * <script type="text/javascript">
17601 * @class Roo.dd.StatusProxy
17602 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17603 * default drag proxy used by all Roo.dd components.
17605 * @param {Object} config
17607 Roo.dd.StatusProxy = function(config){
17608 Roo.apply(this, config);
17609 this.id = this.id || Roo.id();
17610 this.el = new Roo.Layer({
17612 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17613 {tag: "div", cls: "x-dd-drop-icon"},
17614 {tag: "div", cls: "x-dd-drag-ghost"}
17617 shadow: !config || config.shadow !== false
17619 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17620 this.dropStatus = this.dropNotAllowed;
17623 Roo.dd.StatusProxy.prototype = {
17625 * @cfg {String} dropAllowed
17626 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17628 dropAllowed : "x-dd-drop-ok",
17630 * @cfg {String} dropNotAllowed
17631 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17633 dropNotAllowed : "x-dd-drop-nodrop",
17636 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17637 * over the current target element.
17638 * @param {String} cssClass The css class for the new drop status indicator image
17640 setStatus : function(cssClass){
17641 cssClass = cssClass || this.dropNotAllowed;
17642 if(this.dropStatus != cssClass){
17643 this.el.replaceClass(this.dropStatus, cssClass);
17644 this.dropStatus = cssClass;
17649 * Resets the status indicator to the default dropNotAllowed value
17650 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17652 reset : function(clearGhost){
17653 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17654 this.dropStatus = this.dropNotAllowed;
17656 this.ghost.update("");
17661 * Updates the contents of the ghost element
17662 * @param {String} html The html that will replace the current innerHTML of the ghost element
17664 update : function(html){
17665 if(typeof html == "string"){
17666 this.ghost.update(html);
17668 this.ghost.update("");
17669 html.style.margin = "0";
17670 this.ghost.dom.appendChild(html);
17672 // ensure float = none set?? cant remember why though.
17673 var el = this.ghost.dom.firstChild;
17675 Roo.fly(el).setStyle('float', 'none');
17680 * Returns the underlying proxy {@link Roo.Layer}
17681 * @return {Roo.Layer} el
17683 getEl : function(){
17688 * Returns the ghost element
17689 * @return {Roo.Element} el
17691 getGhost : function(){
17697 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17699 hide : function(clear){
17707 * Stops the repair animation if it's currently running
17710 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17716 * Displays this proxy
17723 * Force the Layer to sync its shadow and shim positions to the element
17730 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17731 * invalid drop operation by the item being dragged.
17732 * @param {Array} xy The XY position of the element ([x, y])
17733 * @param {Function} callback The function to call after the repair is complete
17734 * @param {Object} scope The scope in which to execute the callback
17736 repair : function(xy, callback, scope){
17737 this.callback = callback;
17738 this.scope = scope;
17739 if(xy && this.animRepair !== false){
17740 this.el.addClass("x-dd-drag-repair");
17741 this.el.hideUnders(true);
17742 this.anim = this.el.shift({
17743 duration: this.repairDuration || .5,
17747 callback: this.afterRepair,
17751 this.afterRepair();
17756 afterRepair : function(){
17758 if(typeof this.callback == "function"){
17759 this.callback.call(this.scope || this);
17761 this.callback = null;
17766 * Ext JS Library 1.1.1
17767 * Copyright(c) 2006-2007, Ext JS, LLC.
17769 * Originally Released Under LGPL - original licence link has changed is not relivant.
17772 * <script type="text/javascript">
17776 * @class Roo.dd.DragSource
17777 * @extends Roo.dd.DDProxy
17778 * A simple class that provides the basic implementation needed to make any element draggable.
17780 * @param {String/HTMLElement/Element} el The container element
17781 * @param {Object} config
17783 Roo.dd.DragSource = function(el, config){
17784 this.el = Roo.get(el);
17785 this.dragData = {};
17787 Roo.apply(this, config);
17790 this.proxy = new Roo.dd.StatusProxy();
17793 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17794 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17796 this.dragging = false;
17799 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17801 * @cfg {String} dropAllowed
17802 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17804 dropAllowed : "x-dd-drop-ok",
17806 * @cfg {String} dropNotAllowed
17807 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17809 dropNotAllowed : "x-dd-drop-nodrop",
17812 * Returns the data object associated with this drag source
17813 * @return {Object} data An object containing arbitrary data
17815 getDragData : function(e){
17816 return this.dragData;
17820 onDragEnter : function(e, id){
17821 var target = Roo.dd.DragDropMgr.getDDById(id);
17822 this.cachedTarget = target;
17823 if(this.beforeDragEnter(target, e, id) !== false){
17824 if(target.isNotifyTarget){
17825 var status = target.notifyEnter(this, e, this.dragData);
17826 this.proxy.setStatus(status);
17828 this.proxy.setStatus(this.dropAllowed);
17831 if(this.afterDragEnter){
17833 * An empty function by default, but provided so that you can perform a custom action
17834 * when the dragged item enters the drop target by providing an implementation.
17835 * @param {Roo.dd.DragDrop} target The drop target
17836 * @param {Event} e The event object
17837 * @param {String} id The id of the dragged element
17838 * @method afterDragEnter
17840 this.afterDragEnter(target, e, id);
17846 * An empty function by default, but provided so that you can perform a custom action
17847 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
17848 * @param {Roo.dd.DragDrop} target The drop target
17849 * @param {Event} e The event object
17850 * @param {String} id The id of the dragged element
17851 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17853 beforeDragEnter : function(target, e, id){
17858 alignElWithMouse: function() {
17859 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
17864 onDragOver : function(e, id){
17865 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17866 if(this.beforeDragOver(target, e, id) !== false){
17867 if(target.isNotifyTarget){
17868 var status = target.notifyOver(this, e, this.dragData);
17869 this.proxy.setStatus(status);
17872 if(this.afterDragOver){
17874 * An empty function by default, but provided so that you can perform a custom action
17875 * while the dragged item is over the drop target by providing an implementation.
17876 * @param {Roo.dd.DragDrop} target The drop target
17877 * @param {Event} e The event object
17878 * @param {String} id The id of the dragged element
17879 * @method afterDragOver
17881 this.afterDragOver(target, e, id);
17887 * An empty function by default, but provided so that you can perform a custom action
17888 * while the dragged item is over the drop target and optionally cancel the onDragOver.
17889 * @param {Roo.dd.DragDrop} target The drop target
17890 * @param {Event} e The event object
17891 * @param {String} id The id of the dragged element
17892 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17894 beforeDragOver : function(target, e, id){
17899 onDragOut : function(e, id){
17900 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17901 if(this.beforeDragOut(target, e, id) !== false){
17902 if(target.isNotifyTarget){
17903 target.notifyOut(this, e, this.dragData);
17905 this.proxy.reset();
17906 if(this.afterDragOut){
17908 * An empty function by default, but provided so that you can perform a custom action
17909 * after the dragged item is dragged out of the target without dropping.
17910 * @param {Roo.dd.DragDrop} target The drop target
17911 * @param {Event} e The event object
17912 * @param {String} id The id of the dragged element
17913 * @method afterDragOut
17915 this.afterDragOut(target, e, id);
17918 this.cachedTarget = null;
17922 * An empty function by default, but provided so that you can perform a custom action before the dragged
17923 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
17924 * @param {Roo.dd.DragDrop} target The drop target
17925 * @param {Event} e The event object
17926 * @param {String} id The id of the dragged element
17927 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17929 beforeDragOut : function(target, e, id){
17934 onDragDrop : function(e, id){
17935 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17936 if(this.beforeDragDrop(target, e, id) !== false){
17937 if(target.isNotifyTarget){
17938 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
17939 this.onValidDrop(target, e, id);
17941 this.onInvalidDrop(target, e, id);
17944 this.onValidDrop(target, e, id);
17947 if(this.afterDragDrop){
17949 * An empty function by default, but provided so that you can perform a custom action
17950 * after a valid drag drop has occurred by providing an implementation.
17951 * @param {Roo.dd.DragDrop} target The drop target
17952 * @param {Event} e The event object
17953 * @param {String} id The id of the dropped element
17954 * @method afterDragDrop
17956 this.afterDragDrop(target, e, id);
17959 delete this.cachedTarget;
17963 * An empty function by default, but provided so that you can perform a custom action before the dragged
17964 * item is dropped onto the target and optionally cancel the onDragDrop.
17965 * @param {Roo.dd.DragDrop} target The drop target
17966 * @param {Event} e The event object
17967 * @param {String} id The id of the dragged element
17968 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
17970 beforeDragDrop : function(target, e, id){
17975 onValidDrop : function(target, e, id){
17977 if(this.afterValidDrop){
17979 * An empty function by default, but provided so that you can perform a custom action
17980 * after a valid drop has occurred by providing an implementation.
17981 * @param {Object} target The target DD
17982 * @param {Event} e The event object
17983 * @param {String} id The id of the dropped element
17984 * @method afterInvalidDrop
17986 this.afterValidDrop(target, e, id);
17991 getRepairXY : function(e, data){
17992 return this.el.getXY();
17996 onInvalidDrop : function(target, e, id){
17997 this.beforeInvalidDrop(target, e, id);
17998 if(this.cachedTarget){
17999 if(this.cachedTarget.isNotifyTarget){
18000 this.cachedTarget.notifyOut(this, e, this.dragData);
18002 this.cacheTarget = null;
18004 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18006 if(this.afterInvalidDrop){
18008 * An empty function by default, but provided so that you can perform a custom action
18009 * after an invalid drop has occurred by providing an implementation.
18010 * @param {Event} e The event object
18011 * @param {String} id The id of the dropped element
18012 * @method afterInvalidDrop
18014 this.afterInvalidDrop(e, id);
18019 afterRepair : function(){
18021 this.el.highlight(this.hlColor || "c3daf9");
18023 this.dragging = false;
18027 * An empty function by default, but provided so that you can perform a custom action after an invalid
18028 * drop has occurred.
18029 * @param {Roo.dd.DragDrop} target The drop target
18030 * @param {Event} e The event object
18031 * @param {String} id The id of the dragged element
18032 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18034 beforeInvalidDrop : function(target, e, id){
18039 handleMouseDown : function(e){
18040 if(this.dragging) {
18043 var data = this.getDragData(e);
18044 if(data && this.onBeforeDrag(data, e) !== false){
18045 this.dragData = data;
18047 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18052 * An empty function by default, but provided so that you can perform a custom action before the initial
18053 * drag event begins and optionally cancel it.
18054 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18055 * @param {Event} e The event object
18056 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18058 onBeforeDrag : function(data, e){
18063 * An empty function by default, but provided so that you can perform a custom action once the initial
18064 * drag event has begun. The drag cannot be canceled from this function.
18065 * @param {Number} x The x position of the click on the dragged object
18066 * @param {Number} y The y position of the click on the dragged object
18068 onStartDrag : Roo.emptyFn,
18070 // private - YUI override
18071 startDrag : function(x, y){
18072 this.proxy.reset();
18073 this.dragging = true;
18074 this.proxy.update("");
18075 this.onInitDrag(x, y);
18080 onInitDrag : function(x, y){
18081 var clone = this.el.dom.cloneNode(true);
18082 clone.id = Roo.id(); // prevent duplicate ids
18083 this.proxy.update(clone);
18084 this.onStartDrag(x, y);
18089 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18090 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18092 getProxy : function(){
18097 * Hides the drag source's {@link Roo.dd.StatusProxy}
18099 hideProxy : function(){
18101 this.proxy.reset(true);
18102 this.dragging = false;
18106 triggerCacheRefresh : function(){
18107 Roo.dd.DDM.refreshCache(this.groups);
18110 // private - override to prevent hiding
18111 b4EndDrag: function(e) {
18114 // private - override to prevent moving
18115 endDrag : function(e){
18116 this.onEndDrag(this.dragData, e);
18120 onEndDrag : function(data, e){
18123 // private - pin to cursor
18124 autoOffset : function(x, y) {
18125 this.setDelta(-12, -20);
18129 * Ext JS Library 1.1.1
18130 * Copyright(c) 2006-2007, Ext JS, LLC.
18132 * Originally Released Under LGPL - original licence link has changed is not relivant.
18135 * <script type="text/javascript">
18140 * @class Roo.dd.DropTarget
18141 * @extends Roo.dd.DDTarget
18142 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18143 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18145 * @param {String/HTMLElement/Element} el The container element
18146 * @param {Object} config
18148 Roo.dd.DropTarget = function(el, config){
18149 this.el = Roo.get(el);
18151 Roo.apply(this, config);
18153 if(this.containerScroll){
18154 Roo.dd.ScrollManager.register(this.el);
18157 Roo.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18162 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18164 * @cfg {String} overClass
18165 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18168 * @cfg {String} dropAllowed
18169 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18171 dropAllowed : "x-dd-drop-ok",
18173 * @cfg {String} dropNotAllowed
18174 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18176 dropNotAllowed : "x-dd-drop-nodrop",
18182 isNotifyTarget : true,
18185 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18186 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18187 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18188 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18189 * @param {Event} e The event
18190 * @param {Object} data An object containing arbitrary data supplied by the drag source
18191 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18192 * underlying {@link Roo.dd.StatusProxy} can be updated
18194 notifyEnter : function(dd, e, data){
18195 if(this.overClass){
18196 this.el.addClass(this.overClass);
18198 return this.dropAllowed;
18202 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18203 * This method will be called on every mouse movement while the drag source is over the drop target.
18204 * This default implementation simply returns the dropAllowed config value.
18205 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18206 * @param {Event} e The event
18207 * @param {Object} data An object containing arbitrary data supplied by the drag source
18208 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18209 * underlying {@link Roo.dd.StatusProxy} can be updated
18211 notifyOver : function(dd, e, data){
18212 return this.dropAllowed;
18216 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18217 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18218 * overClass (if any) from the drop element.
18219 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18220 * @param {Event} e The event
18221 * @param {Object} data An object containing arbitrary data supplied by the drag source
18223 notifyOut : function(dd, e, data){
18224 if(this.overClass){
18225 this.el.removeClass(this.overClass);
18230 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18231 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18232 * implementation that does something to process the drop event and returns true so that the drag source's
18233 * repair action does not run.
18234 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18235 * @param {Event} e The event
18236 * @param {Object} data An object containing arbitrary data supplied by the drag source
18237 * @return {Boolean} True if the drop was valid, else false
18239 notifyDrop : function(dd, e, data){
18244 * Ext JS Library 1.1.1
18245 * Copyright(c) 2006-2007, Ext JS, LLC.
18247 * Originally Released Under LGPL - original licence link has changed is not relivant.
18250 * <script type="text/javascript">
18255 * @class Roo.dd.DragZone
18256 * @extends Roo.dd.DragSource
18257 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18258 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18260 * @param {String/HTMLElement/Element} el The container element
18261 * @param {Object} config
18263 Roo.dd.DragZone = function(el, config){
18264 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18265 if(this.containerScroll){
18266 Roo.dd.ScrollManager.register(this.el);
18270 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18272 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18273 * for auto scrolling during drag operations.
18276 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18277 * method after a failed drop (defaults to "c3daf9" - light blue)
18281 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18282 * for a valid target to drag based on the mouse down. Override this method
18283 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18284 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18285 * @param {EventObject} e The mouse down event
18286 * @return {Object} The dragData
18288 getDragData : function(e){
18289 return Roo.dd.Registry.getHandleFromEvent(e);
18293 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18294 * this.dragData.ddel
18295 * @param {Number} x The x position of the click on the dragged object
18296 * @param {Number} y The y position of the click on the dragged object
18297 * @return {Boolean} true to continue the drag, false to cancel
18299 onInitDrag : function(x, y){
18300 this.proxy.update(this.dragData.ddel.cloneNode(true));
18301 this.onStartDrag(x, y);
18306 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18308 afterRepair : function(){
18310 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18312 this.dragging = false;
18316 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18317 * the XY of this.dragData.ddel
18318 * @param {EventObject} e The mouse up event
18319 * @return {Array} The xy location (e.g. [100, 200])
18321 getRepairXY : function(e){
18322 return Roo.Element.fly(this.dragData.ddel).getXY();
18326 * Ext JS Library 1.1.1
18327 * Copyright(c) 2006-2007, Ext JS, LLC.
18329 * Originally Released Under LGPL - original licence link has changed is not relivant.
18332 * <script type="text/javascript">
18335 * @class Roo.dd.DropZone
18336 * @extends Roo.dd.DropTarget
18337 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18338 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18340 * @param {String/HTMLElement/Element} el The container element
18341 * @param {Object} config
18343 Roo.dd.DropZone = function(el, config){
18344 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18347 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18349 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18350 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18351 * provide your own custom lookup.
18352 * @param {Event} e The event
18353 * @return {Object} data The custom data
18355 getTargetFromEvent : function(e){
18356 return Roo.dd.Registry.getTargetFromEvent(e);
18360 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18361 * that it has registered. This method has no default implementation and should be overridden to provide
18362 * node-specific processing if necessary.
18363 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18364 * {@link #getTargetFromEvent} for this node)
18365 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18366 * @param {Event} e The event
18367 * @param {Object} data An object containing arbitrary data supplied by the drag source
18369 onNodeEnter : function(n, dd, e, data){
18374 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18375 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18376 * overridden to provide the proper feedback.
18377 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18378 * {@link #getTargetFromEvent} for this node)
18379 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18380 * @param {Event} e The event
18381 * @param {Object} data An object containing arbitrary data supplied by the drag source
18382 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18383 * underlying {@link Roo.dd.StatusProxy} can be updated
18385 onNodeOver : function(n, dd, e, data){
18386 return this.dropAllowed;
18390 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18391 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18392 * node-specific processing if necessary.
18393 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18394 * {@link #getTargetFromEvent} for this node)
18395 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18396 * @param {Event} e The event
18397 * @param {Object} data An object containing arbitrary data supplied by the drag source
18399 onNodeOut : function(n, dd, e, data){
18404 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18405 * the drop node. The default implementation returns false, so it should be overridden to provide the
18406 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18407 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18408 * {@link #getTargetFromEvent} for this node)
18409 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18410 * @param {Event} e The event
18411 * @param {Object} data An object containing arbitrary data supplied by the drag source
18412 * @return {Boolean} True if the drop was valid, else false
18414 onNodeDrop : function(n, dd, e, data){
18419 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18420 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18421 * it should be overridden to provide the proper feedback if necessary.
18422 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18423 * @param {Event} e The event
18424 * @param {Object} data An object containing arbitrary data supplied by the drag source
18425 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18426 * underlying {@link Roo.dd.StatusProxy} can be updated
18428 onContainerOver : function(dd, e, data){
18429 return this.dropNotAllowed;
18433 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18434 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18435 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18436 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18437 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18438 * @param {Event} e The event
18439 * @param {Object} data An object containing arbitrary data supplied by the drag source
18440 * @return {Boolean} True if the drop was valid, else false
18442 onContainerDrop : function(dd, e, data){
18447 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18448 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18449 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18450 * you should override this method and provide a custom implementation.
18451 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18452 * @param {Event} e The event
18453 * @param {Object} data An object containing arbitrary data supplied by the drag source
18454 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18455 * underlying {@link Roo.dd.StatusProxy} can be updated
18457 notifyEnter : function(dd, e, data){
18458 return this.dropNotAllowed;
18462 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18463 * This method will be called on every mouse movement while the drag source is over the drop zone.
18464 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18465 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18466 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18467 * registered node, it will call {@link #onContainerOver}.
18468 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18469 * @param {Event} e The event
18470 * @param {Object} data An object containing arbitrary data supplied by the drag source
18471 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18472 * underlying {@link Roo.dd.StatusProxy} can be updated
18474 notifyOver : function(dd, e, data){
18475 var n = this.getTargetFromEvent(e);
18476 if(!n){ // not over valid drop target
18477 if(this.lastOverNode){
18478 this.onNodeOut(this.lastOverNode, dd, e, data);
18479 this.lastOverNode = null;
18481 return this.onContainerOver(dd, e, data);
18483 if(this.lastOverNode != n){
18484 if(this.lastOverNode){
18485 this.onNodeOut(this.lastOverNode, dd, e, data);
18487 this.onNodeEnter(n, dd, e, data);
18488 this.lastOverNode = n;
18490 return this.onNodeOver(n, dd, e, data);
18494 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18495 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18496 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18497 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18498 * @param {Event} e The event
18499 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18501 notifyOut : function(dd, e, data){
18502 if(this.lastOverNode){
18503 this.onNodeOut(this.lastOverNode, dd, e, data);
18504 this.lastOverNode = null;
18509 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18510 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18511 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18512 * otherwise it will call {@link #onContainerDrop}.
18513 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18514 * @param {Event} e The event
18515 * @param {Object} data An object containing arbitrary data supplied by the drag source
18516 * @return {Boolean} True if the drop was valid, else false
18518 notifyDrop : function(dd, e, data){
18519 if(this.lastOverNode){
18520 this.onNodeOut(this.lastOverNode, dd, e, data);
18521 this.lastOverNode = null;
18523 var n = this.getTargetFromEvent(e);
18525 this.onNodeDrop(n, dd, e, data) :
18526 this.onContainerDrop(dd, e, data);
18530 triggerCacheRefresh : function(){
18531 Roo.dd.DDM.refreshCache(this.groups);
18535 * Ext JS Library 1.1.1
18536 * Copyright(c) 2006-2007, Ext JS, LLC.
18538 * Originally Released Under LGPL - original licence link has changed is not relivant.
18541 * <script type="text/javascript">
18546 * @class Roo.data.SortTypes
18548 * Defines the default sorting (casting?) comparison functions used when sorting data.
18550 Roo.data.SortTypes = {
18552 * Default sort that does nothing
18553 * @param {Mixed} s The value being converted
18554 * @return {Mixed} The comparison value
18556 none : function(s){
18561 * The regular expression used to strip tags
18565 stripTagsRE : /<\/?[^>]+>/gi,
18568 * Strips all HTML tags to sort on text only
18569 * @param {Mixed} s The value being converted
18570 * @return {String} The comparison value
18572 asText : function(s){
18573 return String(s).replace(this.stripTagsRE, "");
18577 * Strips all HTML tags to sort on text only - Case insensitive
18578 * @param {Mixed} s The value being converted
18579 * @return {String} The comparison value
18581 asUCText : function(s){
18582 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18586 * Case insensitive string
18587 * @param {Mixed} s The value being converted
18588 * @return {String} The comparison value
18590 asUCString : function(s) {
18591 return String(s).toUpperCase();
18596 * @param {Mixed} s The value being converted
18597 * @return {Number} The comparison value
18599 asDate : function(s) {
18603 if(s instanceof Date){
18604 return s.getTime();
18606 return Date.parse(String(s));
18611 * @param {Mixed} s The value being converted
18612 * @return {Float} The comparison value
18614 asFloat : function(s) {
18615 var val = parseFloat(String(s).replace(/,/g, ""));
18616 if(isNaN(val)) val = 0;
18622 * @param {Mixed} s The value being converted
18623 * @return {Number} The comparison value
18625 asInt : function(s) {
18626 var val = parseInt(String(s).replace(/,/g, ""));
18627 if(isNaN(val)) val = 0;
18632 * Ext JS Library 1.1.1
18633 * Copyright(c) 2006-2007, Ext JS, LLC.
18635 * Originally Released Under LGPL - original licence link has changed is not relivant.
18638 * <script type="text/javascript">
18642 * @class Roo.data.Record
18643 * Instances of this class encapsulate both record <em>definition</em> information, and record
18644 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18645 * to access Records cached in an {@link Roo.data.Store} object.<br>
18647 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18648 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18651 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18653 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18654 * {@link #create}. The parameters are the same.
18655 * @param {Array} data An associative Array of data values keyed by the field name.
18656 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18657 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18658 * not specified an integer id is generated.
18660 Roo.data.Record = function(data, id){
18661 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18666 * Generate a constructor for a specific record layout.
18667 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18668 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18669 * Each field definition object may contain the following properties: <ul>
18670 * <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,
18671 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18672 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18673 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18674 * is being used, then this is a string containing the javascript expression to reference the data relative to
18675 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18676 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18677 * this may be omitted.</p></li>
18678 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18679 * <ul><li>auto (Default, implies no conversion)</li>
18684 * <li>date</li></ul></p></li>
18685 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18686 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18687 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18688 * by the Reader into an object that will be stored in the Record. It is passed the
18689 * following parameters:<ul>
18690 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18692 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18694 * <br>usage:<br><pre><code>
18695 var TopicRecord = Roo.data.Record.create(
18696 {name: 'title', mapping: 'topic_title'},
18697 {name: 'author', mapping: 'username'},
18698 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18699 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18700 {name: 'lastPoster', mapping: 'user2'},
18701 {name: 'excerpt', mapping: 'post_text'}
18704 var myNewRecord = new TopicRecord({
18705 title: 'Do my job please',
18708 lastPost: new Date(),
18709 lastPoster: 'Animal',
18710 excerpt: 'No way dude!'
18712 myStore.add(myNewRecord);
18717 Roo.data.Record.create = function(o){
18718 var f = function(){
18719 f.superclass.constructor.apply(this, arguments);
18721 Roo.extend(f, Roo.data.Record);
18722 var p = f.prototype;
18723 p.fields = new Roo.util.MixedCollection(false, function(field){
18726 for(var i = 0, len = o.length; i < len; i++){
18727 p.fields.add(new Roo.data.Field(o[i]));
18729 f.getField = function(name){
18730 return p.fields.get(name);
18735 Roo.data.Record.AUTO_ID = 1000;
18736 Roo.data.Record.EDIT = 'edit';
18737 Roo.data.Record.REJECT = 'reject';
18738 Roo.data.Record.COMMIT = 'commit';
18740 Roo.data.Record.prototype = {
18742 * Readonly flag - true if this record has been modified.
18751 join : function(store){
18752 this.store = store;
18756 * Set the named field to the specified value.
18757 * @param {String} name The name of the field to set.
18758 * @param {Object} value The value to set the field to.
18760 set : function(name, value){
18761 if(this.data[name] == value){
18765 if(!this.modified){
18766 this.modified = {};
18768 if(typeof this.modified[name] == 'undefined'){
18769 this.modified[name] = this.data[name];
18771 this.data[name] = value;
18773 this.store.afterEdit(this);
18778 * Get the value of the named field.
18779 * @param {String} name The name of the field to get the value of.
18780 * @return {Object} The value of the field.
18782 get : function(name){
18783 return this.data[name];
18787 beginEdit : function(){
18788 this.editing = true;
18789 this.modified = {};
18793 cancelEdit : function(){
18794 this.editing = false;
18795 delete this.modified;
18799 endEdit : function(){
18800 this.editing = false;
18801 if(this.dirty && this.store){
18802 this.store.afterEdit(this);
18807 * Usually called by the {@link Roo.data.Store} which owns the Record.
18808 * Rejects all changes made to the Record since either creation, or the last commit operation.
18809 * Modified fields are reverted to their original values.
18811 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18812 * of reject operations.
18814 reject : function(){
18815 var m = this.modified;
18817 if(typeof m[n] != "function"){
18818 this.data[n] = m[n];
18821 this.dirty = false;
18822 delete this.modified;
18823 this.editing = false;
18825 this.store.afterReject(this);
18830 * Usually called by the {@link Roo.data.Store} which owns the Record.
18831 * Commits all changes made to the Record since either creation, or the last commit operation.
18833 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18834 * of commit operations.
18836 commit : function(){
18837 this.dirty = false;
18838 delete this.modified;
18839 this.editing = false;
18841 this.store.afterCommit(this);
18846 hasError : function(){
18847 return this.error != null;
18851 clearError : function(){
18856 * Creates a copy of this record.
18857 * @param {String} id (optional) A new record id if you don't want to use this record's id
18860 copy : function(newId) {
18861 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
18865 * Ext JS Library 1.1.1
18866 * Copyright(c) 2006-2007, Ext JS, LLC.
18868 * Originally Released Under LGPL - original licence link has changed is not relivant.
18871 * <script type="text/javascript">
18877 * @class Roo.data.Store
18878 * @extends Roo.util.Observable
18879 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
18880 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
18882 * 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
18883 * has no knowledge of the format of the data returned by the Proxy.<br>
18885 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
18886 * instances from the data object. These records are cached and made available through accessor functions.
18888 * Creates a new Store.
18889 * @param {Object} config A config object containing the objects needed for the Store to access data,
18890 * and read the data into Records.
18892 Roo.data.Store = function(config){
18893 this.data = new Roo.util.MixedCollection(false);
18894 this.data.getKey = function(o){
18897 this.baseParams = {};
18899 this.paramNames = {
18906 if(config && config.data){
18907 this.inlineData = config.data;
18908 delete config.data;
18911 Roo.apply(this, config);
18913 if(this.reader){ // reader passed
18914 this.reader = Roo.factory(this.reader, Roo.data);
18915 this.reader.xmodule = this.xmodule || false;
18916 if(!this.recordType){
18917 this.recordType = this.reader.recordType;
18919 if(this.reader.onMetaChange){
18920 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
18924 if(this.recordType){
18925 this.fields = this.recordType.prototype.fields;
18927 this.modified = [];
18931 * @event datachanged
18932 * Fires when the data cache has changed, and a widget which is using this Store
18933 * as a Record cache should refresh its view.
18934 * @param {Store} this
18936 datachanged : true,
18938 * @event metachange
18939 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
18940 * @param {Store} this
18941 * @param {Object} meta The JSON metadata
18946 * Fires when Records have been added to the Store
18947 * @param {Store} this
18948 * @param {Roo.data.Record[]} records The array of Records added
18949 * @param {Number} index The index at which the record(s) were added
18954 * Fires when a Record has been removed from the Store
18955 * @param {Store} this
18956 * @param {Roo.data.Record} record The Record that was removed
18957 * @param {Number} index The index at which the record was removed
18962 * Fires when a Record has been updated
18963 * @param {Store} this
18964 * @param {Roo.data.Record} record The Record that was updated
18965 * @param {String} operation The update operation being performed. Value may be one of:
18967 Roo.data.Record.EDIT
18968 Roo.data.Record.REJECT
18969 Roo.data.Record.COMMIT
18975 * Fires when the data cache has been cleared.
18976 * @param {Store} this
18980 * @event beforeload
18981 * Fires before a request is made for a new data object. If the beforeload handler returns false
18982 * the load action will be canceled.
18983 * @param {Store} this
18984 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18989 * Fires after a new set of Records has been loaded.
18990 * @param {Store} this
18991 * @param {Roo.data.Record[]} records The Records that were loaded
18992 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18996 * @event loadexception
18997 * Fires if an exception occurs in the Proxy during loading.
18998 * Called with the signature of the Proxy's "loadexception" event.
18999 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19002 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19003 * @param {Object} load options
19004 * @param {Object} jsonData from your request (normally this contains the Exception)
19006 loadexception : true
19010 this.proxy = Roo.factory(this.proxy, Roo.data);
19011 this.proxy.xmodule = this.xmodule || false;
19012 this.relayEvents(this.proxy, ["loadexception"]);
19014 this.sortToggle = {};
19016 Roo.data.Store.superclass.constructor.call(this);
19018 if(this.inlineData){
19019 this.loadData(this.inlineData);
19020 delete this.inlineData;
19023 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19025 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19026 * without a remote query - used by combo/forms at present.
19030 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19033 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19036 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19037 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19040 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19041 * on any HTTP request
19044 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19047 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19048 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19050 remoteSort : false,
19053 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19054 * loaded or when a record is removed. (defaults to false).
19056 pruneModifiedRecords : false,
19059 lastOptions : null,
19062 * Add Records to the Store and fires the add event.
19063 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19065 add : function(records){
19066 records = [].concat(records);
19067 for(var i = 0, len = records.length; i < len; i++){
19068 records[i].join(this);
19070 var index = this.data.length;
19071 this.data.addAll(records);
19072 this.fireEvent("add", this, records, index);
19076 * Remove a Record from the Store and fires the remove event.
19077 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19079 remove : function(record){
19080 var index = this.data.indexOf(record);
19081 this.data.removeAt(index);
19082 if(this.pruneModifiedRecords){
19083 this.modified.remove(record);
19085 this.fireEvent("remove", this, record, index);
19089 * Remove all Records from the Store and fires the clear event.
19091 removeAll : function(){
19093 if(this.pruneModifiedRecords){
19094 this.modified = [];
19096 this.fireEvent("clear", this);
19100 * Inserts Records to the Store at the given index and fires the add event.
19101 * @param {Number} index The start index at which to insert the passed Records.
19102 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19104 insert : function(index, records){
19105 records = [].concat(records);
19106 for(var i = 0, len = records.length; i < len; i++){
19107 this.data.insert(index, records[i]);
19108 records[i].join(this);
19110 this.fireEvent("add", this, records, index);
19114 * Get the index within the cache of the passed Record.
19115 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19116 * @return {Number} The index of the passed Record. Returns -1 if not found.
19118 indexOf : function(record){
19119 return this.data.indexOf(record);
19123 * Get the index within the cache of the Record with the passed id.
19124 * @param {String} id The id of the Record to find.
19125 * @return {Number} The index of the Record. Returns -1 if not found.
19127 indexOfId : function(id){
19128 return this.data.indexOfKey(id);
19132 * Get the Record with the specified id.
19133 * @param {String} id The id of the Record to find.
19134 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19136 getById : function(id){
19137 return this.data.key(id);
19141 * Get the Record at the specified index.
19142 * @param {Number} index The index of the Record to find.
19143 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19145 getAt : function(index){
19146 return this.data.itemAt(index);
19150 * Returns a range of Records between specified indices.
19151 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19152 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19153 * @return {Roo.data.Record[]} An array of Records
19155 getRange : function(start, end){
19156 return this.data.getRange(start, end);
19160 storeOptions : function(o){
19161 o = Roo.apply({}, o);
19164 this.lastOptions = o;
19168 * Loads the Record cache from the configured Proxy using the configured Reader.
19170 * If using remote paging, then the first load call must specify the <em>start</em>
19171 * and <em>limit</em> properties in the options.params property to establish the initial
19172 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19174 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19175 * and this call will return before the new data has been loaded. Perform any post-processing
19176 * in a callback function, or in a "load" event handler.</strong>
19178 * @param {Object} options An object containing properties which control loading options:<ul>
19179 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19180 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19181 * passed the following arguments:<ul>
19182 * <li>r : Roo.data.Record[]</li>
19183 * <li>options: Options object from the load call</li>
19184 * <li>success: Boolean success indicator</li></ul></li>
19185 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19186 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19189 load : function(options){
19190 options = options || {};
19191 if(this.fireEvent("beforeload", this, options) !== false){
19192 this.storeOptions(options);
19193 var p = Roo.apply(options.params || {}, this.baseParams);
19194 if(this.sortInfo && this.remoteSort){
19195 var pn = this.paramNames;
19196 p[pn["sort"]] = this.sortInfo.field;
19197 p[pn["dir"]] = this.sortInfo.direction;
19199 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19204 * Reloads the Record cache from the configured Proxy using the configured Reader and
19205 * the options from the last load operation performed.
19206 * @param {Object} options (optional) An object containing properties which may override the options
19207 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19208 * the most recently used options are reused).
19210 reload : function(options){
19211 this.load(Roo.applyIf(options||{}, this.lastOptions));
19215 // Called as a callback by the Reader during a load operation.
19216 loadRecords : function(o, options, success){
19217 if(!o || success === false){
19218 if(success !== false){
19219 this.fireEvent("load", this, [], options);
19221 if(options.callback){
19222 options.callback.call(options.scope || this, [], options, false);
19226 // if data returned failure - throw an exception.
19227 if (o.success === false) {
19228 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19231 var r = o.records, t = o.totalRecords || r.length;
19232 if(!options || options.add !== true){
19233 if(this.pruneModifiedRecords){
19234 this.modified = [];
19236 for(var i = 0, len = r.length; i < len; i++){
19240 this.data = this.snapshot;
19241 delete this.snapshot;
19244 this.data.addAll(r);
19245 this.totalLength = t;
19247 this.fireEvent("datachanged", this);
19249 this.totalLength = Math.max(t, this.data.length+r.length);
19252 this.fireEvent("load", this, r, options);
19253 if(options.callback){
19254 options.callback.call(options.scope || this, r, options, true);
19259 * Loads data from a passed data block. A Reader which understands the format of the data
19260 * must have been configured in the constructor.
19261 * @param {Object} data The data block from which to read the Records. The format of the data expected
19262 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19263 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19265 loadData : function(o, append){
19266 var r = this.reader.readRecords(o);
19267 this.loadRecords(r, {add: append}, true);
19271 * Gets the number of cached records.
19273 * <em>If using paging, this may not be the total size of the dataset. If the data object
19274 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19275 * the data set size</em>
19277 getCount : function(){
19278 return this.data.length || 0;
19282 * Gets the total number of records in the dataset as returned by the server.
19284 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19285 * the dataset size</em>
19287 getTotalCount : function(){
19288 return this.totalLength || 0;
19292 * Returns the sort state of the Store as an object with two properties:
19294 field {String} The name of the field by which the Records are sorted
19295 direction {String} The sort order, "ASC" or "DESC"
19298 getSortState : function(){
19299 return this.sortInfo;
19303 applySort : function(){
19304 if(this.sortInfo && !this.remoteSort){
19305 var s = this.sortInfo, f = s.field;
19306 var st = this.fields.get(f).sortType;
19307 var fn = function(r1, r2){
19308 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19309 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19311 this.data.sort(s.direction, fn);
19312 if(this.snapshot && this.snapshot != this.data){
19313 this.snapshot.sort(s.direction, fn);
19319 * Sets the default sort column and order to be used by the next load operation.
19320 * @param {String} fieldName The name of the field to sort by.
19321 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19323 setDefaultSort : function(field, dir){
19324 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19328 * Sort the Records.
19329 * If remote sorting is used, the sort is performed on the server, and the cache is
19330 * reloaded. If local sorting is used, the cache is sorted internally.
19331 * @param {String} fieldName The name of the field to sort by.
19332 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19334 sort : function(fieldName, dir){
19335 var f = this.fields.get(fieldName);
19337 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19338 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19343 this.sortToggle[f.name] = dir;
19344 this.sortInfo = {field: f.name, direction: dir};
19345 if(!this.remoteSort){
19347 this.fireEvent("datachanged", this);
19349 this.load(this.lastOptions);
19354 * Calls the specified function for each of the Records in the cache.
19355 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19356 * Returning <em>false</em> aborts and exits the iteration.
19357 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19359 each : function(fn, scope){
19360 this.data.each(fn, scope);
19364 * Gets all records modified since the last commit. Modified records are persisted across load operations
19365 * (e.g., during paging).
19366 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19368 getModifiedRecords : function(){
19369 return this.modified;
19373 createFilterFn : function(property, value, anyMatch){
19374 if(!value.exec){ // not a regex
19375 value = String(value);
19376 if(value.length == 0){
19379 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19381 return function(r){
19382 return value.test(r.data[property]);
19387 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19388 * @param {String} property A field on your records
19389 * @param {Number} start The record index to start at (defaults to 0)
19390 * @param {Number} end The last record index to include (defaults to length - 1)
19391 * @return {Number} The sum
19393 sum : function(property, start, end){
19394 var rs = this.data.items, v = 0;
19395 start = start || 0;
19396 end = (end || end === 0) ? end : rs.length-1;
19398 for(var i = start; i <= end; i++){
19399 v += (rs[i].data[property] || 0);
19405 * Filter the records by a specified property.
19406 * @param {String} field A field on your records
19407 * @param {String/RegExp} value Either a string that the field
19408 * should start with or a RegExp to test against the field
19409 * @param {Boolean} anyMatch True to match any part not just the beginning
19411 filter : function(property, value, anyMatch){
19412 var fn = this.createFilterFn(property, value, anyMatch);
19413 return fn ? this.filterBy(fn) : this.clearFilter();
19417 * Filter by a function. The specified function will be called with each
19418 * record in this data source. If the function returns true the record is included,
19419 * otherwise it is filtered.
19420 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19421 * @param {Object} scope (optional) The scope of the function (defaults to this)
19423 filterBy : function(fn, scope){
19424 this.snapshot = this.snapshot || this.data;
19425 this.data = this.queryBy(fn, scope||this);
19426 this.fireEvent("datachanged", this);
19430 * Query the records by a specified property.
19431 * @param {String} field A field on your records
19432 * @param {String/RegExp} value Either a string that the field
19433 * should start with or a RegExp to test against the field
19434 * @param {Boolean} anyMatch True to match any part not just the beginning
19435 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19437 query : function(property, value, anyMatch){
19438 var fn = this.createFilterFn(property, value, anyMatch);
19439 return fn ? this.queryBy(fn) : this.data.clone();
19443 * Query by a function. The specified function will be called with each
19444 * record in this data source. If the function returns true the record is included
19446 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19447 * @param {Object} scope (optional) The scope of the function (defaults to this)
19448 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19450 queryBy : function(fn, scope){
19451 var data = this.snapshot || this.data;
19452 return data.filterBy(fn, scope||this);
19456 * Collects unique values for a particular dataIndex from this store.
19457 * @param {String} dataIndex The property to collect
19458 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19459 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19460 * @return {Array} An array of the unique values
19462 collect : function(dataIndex, allowNull, bypassFilter){
19463 var d = (bypassFilter === true && this.snapshot) ?
19464 this.snapshot.items : this.data.items;
19465 var v, sv, r = [], l = {};
19466 for(var i = 0, len = d.length; i < len; i++){
19467 v = d[i].data[dataIndex];
19469 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19478 * Revert to a view of the Record cache with no filtering applied.
19479 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19481 clearFilter : function(suppressEvent){
19482 if(this.snapshot && this.snapshot != this.data){
19483 this.data = this.snapshot;
19484 delete this.snapshot;
19485 if(suppressEvent !== true){
19486 this.fireEvent("datachanged", this);
19492 afterEdit : function(record){
19493 if(this.modified.indexOf(record) == -1){
19494 this.modified.push(record);
19496 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19500 afterReject : function(record){
19501 this.modified.remove(record);
19502 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19506 afterCommit : function(record){
19507 this.modified.remove(record);
19508 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19512 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19513 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19515 commitChanges : function(){
19516 var m = this.modified.slice(0);
19517 this.modified = [];
19518 for(var i = 0, len = m.length; i < len; i++){
19524 * Cancel outstanding changes on all changed records.
19526 rejectChanges : function(){
19527 var m = this.modified.slice(0);
19528 this.modified = [];
19529 for(var i = 0, len = m.length; i < len; i++){
19534 onMetaChange : function(meta, rtype, o){
19535 this.recordType = rtype;
19536 this.fields = rtype.prototype.fields;
19537 delete this.snapshot;
19538 this.sortInfo = meta.sortInfo;
19539 this.modified = [];
19540 this.fireEvent('metachange', this, this.reader.meta);
19544 * Ext JS Library 1.1.1
19545 * Copyright(c) 2006-2007, Ext JS, LLC.
19547 * Originally Released Under LGPL - original licence link has changed is not relivant.
19550 * <script type="text/javascript">
19554 * @class Roo.data.SimpleStore
19555 * @extends Roo.data.Store
19556 * Small helper class to make creating Stores from Array data easier.
19557 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19558 * @cfg {Array} fields An array of field definition objects, or field name strings.
19559 * @cfg {Array} data The multi-dimensional array of data
19561 * @param {Object} config
19563 Roo.data.SimpleStore = function(config){
19564 Roo.data.SimpleStore.superclass.constructor.call(this, {
19566 reader: new Roo.data.ArrayReader({
19569 Roo.data.Record.create(config.fields)
19571 proxy : new Roo.data.MemoryProxy(config.data)
19575 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19577 * Ext JS Library 1.1.1
19578 * Copyright(c) 2006-2007, Ext JS, LLC.
19580 * Originally Released Under LGPL - original licence link has changed is not relivant.
19583 * <script type="text/javascript">
19588 * @extends Roo.data.Store
19589 * @class Roo.data.JsonStore
19590 * Small helper class to make creating Stores for JSON data easier. <br/>
19592 var store = new Roo.data.JsonStore({
19593 url: 'get-images.php',
19595 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19598 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19599 * JsonReader and HttpProxy (unless inline data is provided).</b>
19600 * @cfg {Array} fields An array of field definition objects, or field name strings.
19602 * @param {Object} config
19604 Roo.data.JsonStore = function(c){
19605 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19606 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19607 reader: new Roo.data.JsonReader(c, c.fields)
19610 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19612 * Ext JS Library 1.1.1
19613 * Copyright(c) 2006-2007, Ext JS, LLC.
19615 * Originally Released Under LGPL - original licence link has changed is not relivant.
19618 * <script type="text/javascript">
19622 Roo.data.Field = function(config){
19623 if(typeof config == "string"){
19624 config = {name: config};
19626 Roo.apply(this, config);
19629 this.type = "auto";
19632 var st = Roo.data.SortTypes;
19633 // named sortTypes are supported, here we look them up
19634 if(typeof this.sortType == "string"){
19635 this.sortType = st[this.sortType];
19638 // set default sortType for strings and dates
19639 if(!this.sortType){
19642 this.sortType = st.asUCString;
19645 this.sortType = st.asDate;
19648 this.sortType = st.none;
19653 var stripRe = /[\$,%]/g;
19655 // prebuilt conversion function for this field, instead of
19656 // switching every time we're reading a value
19658 var cv, dateFormat = this.dateFormat;
19663 cv = function(v){ return v; };
19666 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19670 return v !== undefined && v !== null && v !== '' ?
19671 parseInt(String(v).replace(stripRe, ""), 10) : '';
19676 return v !== undefined && v !== null && v !== '' ?
19677 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19682 cv = function(v){ return v === true || v === "true" || v == 1; };
19689 if(v instanceof Date){
19693 if(dateFormat == "timestamp"){
19694 return new Date(v*1000);
19696 return Date.parseDate(v, dateFormat);
19698 var parsed = Date.parse(v);
19699 return parsed ? new Date(parsed) : null;
19708 Roo.data.Field.prototype = {
19716 * Ext JS Library 1.1.1
19717 * Copyright(c) 2006-2007, Ext JS, LLC.
19719 * Originally Released Under LGPL - original licence link has changed is not relivant.
19722 * <script type="text/javascript">
19725 // Base class for reading structured data from a data source. This class is intended to be
19726 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19729 * @class Roo.data.DataReader
19730 * Base class for reading structured data from a data source. This class is intended to be
19731 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19734 Roo.data.DataReader = function(meta, recordType){
19738 this.recordType = recordType instanceof Array ?
19739 Roo.data.Record.create(recordType) : recordType;
19742 Roo.data.DataReader.prototype = {
19744 * Create an empty record
19745 * @param {Object} data (optional) - overlay some values
19746 * @return {Roo.data.Record} record created.
19748 newRow : function(d) {
19750 this.recordType.prototype.fields.each(function(c) {
19752 case 'int' : da[c.name] = 0; break;
19753 case 'date' : da[c.name] = new Date(); break;
19754 case 'float' : da[c.name] = 0.0; break;
19755 case 'boolean' : da[c.name] = false; break;
19756 default : da[c.name] = ""; break;
19760 return new this.recordType(Roo.apply(da, d));
19765 * Ext JS Library 1.1.1
19766 * Copyright(c) 2006-2007, Ext JS, LLC.
19768 * Originally Released Under LGPL - original licence link has changed is not relivant.
19771 * <script type="text/javascript">
19775 * @class Roo.data.DataProxy
19776 * @extends Roo.data.Observable
19777 * This class is an abstract base class for implementations which provide retrieval of
19778 * unformatted data objects.<br>
19780 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19781 * (of the appropriate type which knows how to parse the data object) to provide a block of
19782 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19784 * Custom implementations must implement the load method as described in
19785 * {@link Roo.data.HttpProxy#load}.
19787 Roo.data.DataProxy = function(){
19790 * @event beforeload
19791 * Fires before a network request is made to retrieve a data object.
19792 * @param {Object} This DataProxy object.
19793 * @param {Object} params The params parameter to the load function.
19798 * Fires before the load method's callback is called.
19799 * @param {Object} This DataProxy object.
19800 * @param {Object} o The data object.
19801 * @param {Object} arg The callback argument object passed to the load function.
19805 * @event loadexception
19806 * Fires if an Exception occurs during data retrieval.
19807 * @param {Object} This DataProxy object.
19808 * @param {Object} o The data object.
19809 * @param {Object} arg The callback argument object passed to the load function.
19810 * @param {Object} e The Exception.
19812 loadexception : true
19814 Roo.data.DataProxy.superclass.constructor.call(this);
19817 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
19820 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
19824 * Ext JS Library 1.1.1
19825 * Copyright(c) 2006-2007, Ext JS, LLC.
19827 * Originally Released Under LGPL - original licence link has changed is not relivant.
19830 * <script type="text/javascript">
19833 * @class Roo.data.MemoryProxy
19834 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
19835 * to the Reader when its load method is called.
19837 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
19839 Roo.data.MemoryProxy = function(data){
19843 Roo.data.MemoryProxy.superclass.constructor.call(this);
19847 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
19849 * Load data from the requested source (in this case an in-memory
19850 * data object passed to the constructor), read the data object into
19851 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
19852 * process that block using the passed callback.
19853 * @param {Object} params This parameter is not used by the MemoryProxy class.
19854 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19855 * object into a block of Roo.data.Records.
19856 * @param {Function} callback The function into which to pass the block of Roo.data.records.
19857 * The function must be passed <ul>
19858 * <li>The Record block object</li>
19859 * <li>The "arg" argument from the load function</li>
19860 * <li>A boolean success indicator</li>
19862 * @param {Object} scope The scope in which to call the callback
19863 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19865 load : function(params, reader, callback, scope, arg){
19866 params = params || {};
19869 result = reader.readRecords(this.data);
19871 this.fireEvent("loadexception", this, arg, null, e);
19872 callback.call(scope, null, arg, false);
19875 callback.call(scope, result, arg, true);
19879 update : function(params, records){
19884 * Ext JS Library 1.1.1
19885 * Copyright(c) 2006-2007, Ext JS, LLC.
19887 * Originally Released Under LGPL - original licence link has changed is not relivant.
19890 * <script type="text/javascript">
19893 * @class Roo.data.HttpProxy
19894 * @extends Roo.data.DataProxy
19895 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
19896 * configured to reference a certain URL.<br><br>
19898 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
19899 * from which the running page was served.<br><br>
19901 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
19903 * Be aware that to enable the browser to parse an XML document, the server must set
19904 * the Content-Type header in the HTTP response to "text/xml".
19906 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
19907 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
19908 * will be used to make the request.
19910 Roo.data.HttpProxy = function(conn){
19911 Roo.data.HttpProxy.superclass.constructor.call(this);
19912 // is conn a conn config or a real conn?
19914 this.useAjax = !conn || !conn.events;
19918 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
19919 // thse are take from connection...
19922 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
19925 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
19926 * extra parameters to each request made by this object. (defaults to undefined)
19929 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
19930 * to each request made by this object. (defaults to undefined)
19933 * @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)
19936 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
19939 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
19945 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
19949 * Return the {@link Roo.data.Connection} object being used by this Proxy.
19950 * @return {Connection} The Connection object. This object may be used to subscribe to events on
19951 * a finer-grained basis than the DataProxy events.
19953 getConnection : function(){
19954 return this.useAjax ? Roo.Ajax : this.conn;
19958 * Load data from the configured {@link Roo.data.Connection}, read the data object into
19959 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
19960 * process that block using the passed callback.
19961 * @param {Object} params An object containing properties which are to be used as HTTP parameters
19962 * for the request to the remote server.
19963 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19964 * object into a block of Roo.data.Records.
19965 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
19966 * The function must be passed <ul>
19967 * <li>The Record block object</li>
19968 * <li>The "arg" argument from the load function</li>
19969 * <li>A boolean success indicator</li>
19971 * @param {Object} scope The scope in which to call the callback
19972 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19974 load : function(params, reader, callback, scope, arg){
19975 if(this.fireEvent("beforeload", this, params) !== false){
19977 params : params || {},
19979 callback : callback,
19984 callback : this.loadResponse,
19988 Roo.applyIf(o, this.conn);
19989 if(this.activeRequest){
19990 Roo.Ajax.abort(this.activeRequest);
19992 this.activeRequest = Roo.Ajax.request(o);
19994 this.conn.request(o);
19997 callback.call(scope||this, null, arg, false);
20002 loadResponse : function(o, success, response){
20003 delete this.activeRequest;
20005 this.fireEvent("loadexception", this, o, response);
20006 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20011 result = o.reader.read(response);
20013 this.fireEvent("loadexception", this, o, response, e);
20014 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20018 this.fireEvent("load", this, o, o.request.arg);
20019 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20023 update : function(dataSet){
20028 updateResponse : function(dataSet){
20033 * Ext JS Library 1.1.1
20034 * Copyright(c) 2006-2007, Ext JS, LLC.
20036 * Originally Released Under LGPL - original licence link has changed is not relivant.
20039 * <script type="text/javascript">
20043 * @class Roo.data.ScriptTagProxy
20044 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20045 * other than the originating domain of the running page.<br><br>
20047 * <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
20048 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20050 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20051 * source code that is used as the source inside a <script> tag.<br><br>
20053 * In order for the browser to process the returned data, the server must wrap the data object
20054 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20055 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20056 * depending on whether the callback name was passed:
20059 boolean scriptTag = false;
20060 String cb = request.getParameter("callback");
20063 response.setContentType("text/javascript");
20065 response.setContentType("application/x-json");
20067 Writer out = response.getWriter();
20069 out.write(cb + "(");
20071 out.print(dataBlock.toJsonString());
20078 * @param {Object} config A configuration object.
20080 Roo.data.ScriptTagProxy = function(config){
20081 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20082 Roo.apply(this, config);
20083 this.head = document.getElementsByTagName("head")[0];
20086 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20088 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20090 * @cfg {String} url The URL from which to request the data object.
20093 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20097 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20098 * the server the name of the callback function set up by the load call to process the returned data object.
20099 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20100 * javascript output which calls this named function passing the data object as its only parameter.
20102 callbackParam : "callback",
20104 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20105 * name to the request.
20110 * Load data from the configured URL, read the data object into
20111 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20112 * process that block using the passed callback.
20113 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20114 * for the request to the remote server.
20115 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20116 * object into a block of Roo.data.Records.
20117 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20118 * The function must be passed <ul>
20119 * <li>The Record block object</li>
20120 * <li>The "arg" argument from the load function</li>
20121 * <li>A boolean success indicator</li>
20123 * @param {Object} scope The scope in which to call the callback
20124 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20126 load : function(params, reader, callback, scope, arg){
20127 if(this.fireEvent("beforeload", this, params) !== false){
20129 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20131 var url = this.url;
20132 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20134 url += "&_dc=" + (new Date().getTime());
20136 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20139 cb : "stcCallback"+transId,
20140 scriptId : "stcScript"+transId,
20144 callback : callback,
20150 window[trans.cb] = function(o){
20151 conn.handleResponse(o, trans);
20154 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20156 if(this.autoAbort !== false){
20160 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20162 var script = document.createElement("script");
20163 script.setAttribute("src", url);
20164 script.setAttribute("type", "text/javascript");
20165 script.setAttribute("id", trans.scriptId);
20166 this.head.appendChild(script);
20168 this.trans = trans;
20170 callback.call(scope||this, null, arg, false);
20175 isLoading : function(){
20176 return this.trans ? true : false;
20180 * Abort the current server request.
20182 abort : function(){
20183 if(this.isLoading()){
20184 this.destroyTrans(this.trans);
20189 destroyTrans : function(trans, isLoaded){
20190 this.head.removeChild(document.getElementById(trans.scriptId));
20191 clearTimeout(trans.timeoutId);
20193 window[trans.cb] = undefined;
20195 delete window[trans.cb];
20198 // if hasn't been loaded, wait for load to remove it to prevent script error
20199 window[trans.cb] = function(){
20200 window[trans.cb] = undefined;
20202 delete window[trans.cb];
20209 handleResponse : function(o, trans){
20210 this.trans = false;
20211 this.destroyTrans(trans, true);
20214 result = trans.reader.readRecords(o);
20216 this.fireEvent("loadexception", this, o, trans.arg, e);
20217 trans.callback.call(trans.scope||window, null, trans.arg, false);
20220 this.fireEvent("load", this, o, trans.arg);
20221 trans.callback.call(trans.scope||window, result, trans.arg, true);
20225 handleFailure : function(trans){
20226 this.trans = false;
20227 this.destroyTrans(trans, false);
20228 this.fireEvent("loadexception", this, null, trans.arg);
20229 trans.callback.call(trans.scope||window, null, trans.arg, false);
20233 * Ext JS Library 1.1.1
20234 * Copyright(c) 2006-2007, Ext JS, LLC.
20236 * Originally Released Under LGPL - original licence link has changed is not relivant.
20239 * <script type="text/javascript">
20243 * @class Roo.data.JsonReader
20244 * @extends Roo.data.DataReader
20245 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20246 * based on mappings in a provided Roo.data.Record constructor.
20250 var RecordDef = Roo.data.Record.create([
20251 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20252 {name: 'occupation'} // This field will use "occupation" as the mapping.
20254 var myReader = new Roo.data.JsonReader({
20255 totalProperty: "results", // The property which contains the total dataset size (optional)
20256 root: "rows", // The property which contains an Array of row objects
20257 id: "id" // The property within each row object that provides an ID for the record (optional)
20261 * This would consume a JSON file like this:
20263 { 'results': 2, 'rows': [
20264 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20265 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20268 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20269 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20270 * paged from the remote server.
20271 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20272 * @cfg {String} root name of the property which contains the Array of row objects.
20273 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20275 * Create a new JsonReader
20276 * @param {Object} meta Metadata configuration options
20277 * @param {Object} recordType Either an Array of field definition objects,
20278 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20280 Roo.data.JsonReader = function(meta, recordType){
20283 // set some defaults:
20284 Roo.applyIf(meta, {
20285 totalProperty: 'total',
20286 successProperty : 'success',
20291 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20293 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20295 * This method is only used by a DataProxy which has retrieved data from a remote server.
20296 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20297 * @return {Object} data A data block which is used by an Roo.data.Store object as
20298 * a cache of Roo.data.Records.
20300 read : function(response){
20301 var json = response.responseText;
20303 var o = eval("("+json+")");
20305 throw {message: "JsonReader.read: Json object not found"};
20310 this.meta = o.metaData;
20311 this.recordType = Roo.data.Record.create(o.metaData.fields);
20312 this.onMetaChange(this.meta, this.recordType, o);
20314 return this.readRecords(o);
20317 // private function a store will implement
20318 onMetaChange : function(meta, recordType, o){
20325 simpleAccess: function(obj, subsc) {
20332 getJsonAccessor: function(){
20334 return function(expr) {
20336 return(re.test(expr))
20337 ? new Function("obj", "return obj." + expr)
20342 return Roo.emptyFn;
20347 * Create a data block containing Roo.data.Records from an XML document.
20348 * @param {Object} o An object which contains an Array of row objects in the property specified
20349 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20350 * which contains the total size of the dataset.
20351 * @return {Object} data A data block which is used by an Roo.data.Store object as
20352 * a cache of Roo.data.Records.
20354 readRecords : function(o){
20356 * After any data loads, the raw JSON data is available for further custom processing.
20360 var s = this.meta, Record = this.recordType,
20361 f = Record.prototype.fields, fi = f.items, fl = f.length;
20363 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20365 if(s.totalProperty) {
20366 this.getTotal = this.getJsonAccessor(s.totalProperty);
20368 if(s.successProperty) {
20369 this.getSuccess = this.getJsonAccessor(s.successProperty);
20371 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20373 var g = this.getJsonAccessor(s.id);
20374 this.getId = function(rec) {
20376 return (r === undefined || r === "") ? null : r;
20379 this.getId = function(){return null;};
20382 for(var i = 0; i < fl; i++){
20384 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20385 this.ef[i] = this.getJsonAccessor(map);
20389 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20390 if(s.totalProperty){
20391 var v = parseInt(this.getTotal(o), 10);
20396 if(s.successProperty){
20397 var v = this.getSuccess(o);
20398 if(v === false || v === 'false'){
20403 for(var i = 0; i < c; i++){
20406 var id = this.getId(n);
20407 for(var j = 0; j < fl; j++){
20409 var v = this.ef[j](n);
20410 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20412 var record = new Record(values, id);
20414 records[i] = record;
20419 totalRecords : totalRecords
20424 * Ext JS Library 1.1.1
20425 * Copyright(c) 2006-2007, Ext JS, LLC.
20427 * Originally Released Under LGPL - original licence link has changed is not relivant.
20430 * <script type="text/javascript">
20434 * @class Roo.data.XmlReader
20435 * @extends Roo.data.DataReader
20436 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20437 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20439 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20440 * header in the HTTP response must be set to "text/xml".</em>
20444 var RecordDef = Roo.data.Record.create([
20445 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20446 {name: 'occupation'} // This field will use "occupation" as the mapping.
20448 var myReader = new Roo.data.XmlReader({
20449 totalRecords: "results", // The element which contains the total dataset size (optional)
20450 record: "row", // The repeated element which contains row information
20451 id: "id" // The element within the row that provides an ID for the record (optional)
20455 * This would consume an XML file like this:
20459 <results>2</results>
20462 <name>Bill</name>
20463 <occupation>Gardener</occupation>
20467 <name>Ben</name>
20468 <occupation>Horticulturalist</occupation>
20472 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20473 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20474 * paged from the remote server.
20475 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20476 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20477 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20478 * a record identifier value.
20480 * Create a new XmlReader
20481 * @param {Object} meta Metadata configuration options
20482 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20483 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20484 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20486 Roo.data.XmlReader = function(meta, recordType){
20488 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20490 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20492 * This method is only used by a DataProxy which has retrieved data from a remote server.
20493 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20494 * to contain a method called 'responseXML' that returns an XML document object.
20495 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20496 * a cache of Roo.data.Records.
20498 read : function(response){
20499 var doc = response.responseXML;
20501 throw {message: "XmlReader.read: XML Document not available"};
20503 return this.readRecords(doc);
20507 * Create a data block containing Roo.data.Records from an XML document.
20508 * @param {Object} doc A parsed XML document.
20509 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20510 * a cache of Roo.data.Records.
20512 readRecords : function(doc){
20514 * After any data loads/reads, the raw XML Document is available for further custom processing.
20515 * @type XMLDocument
20517 this.xmlData = doc;
20518 var root = doc.documentElement || doc;
20519 var q = Roo.DomQuery;
20520 var recordType = this.recordType, fields = recordType.prototype.fields;
20521 var sid = this.meta.id;
20522 var totalRecords = 0, success = true;
20523 if(this.meta.totalRecords){
20524 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20527 if(this.meta.success){
20528 var sv = q.selectValue(this.meta.success, root, true);
20529 success = sv !== false && sv !== 'false';
20532 var ns = q.select(this.meta.record, root);
20533 for(var i = 0, len = ns.length; i < len; i++) {
20536 var id = sid ? q.selectValue(sid, n) : undefined;
20537 for(var j = 0, jlen = fields.length; j < jlen; j++){
20538 var f = fields.items[j];
20539 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20541 values[f.name] = v;
20543 var record = new recordType(values, id);
20545 records[records.length] = record;
20551 totalRecords : totalRecords || records.length
20556 * Ext JS Library 1.1.1
20557 * Copyright(c) 2006-2007, Ext JS, LLC.
20559 * Originally Released Under LGPL - original licence link has changed is not relivant.
20562 * <script type="text/javascript">
20566 * @class Roo.data.ArrayReader
20567 * @extends Roo.data.DataReader
20568 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20569 * Each element of that Array represents a row of data fields. The
20570 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20571 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20575 var RecordDef = Roo.data.Record.create([
20576 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20577 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20579 var myReader = new Roo.data.ArrayReader({
20580 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20584 * This would consume an Array like this:
20586 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20588 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20590 * Create a new JsonReader
20591 * @param {Object} meta Metadata configuration options.
20592 * @param {Object} recordType Either an Array of field definition objects
20593 * as specified to {@link Roo.data.Record#create},
20594 * or an {@link Roo.data.Record} object
20595 * created using {@link Roo.data.Record#create}.
20597 Roo.data.ArrayReader = function(meta, recordType){
20598 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20601 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20603 * Create a data block containing Roo.data.Records from an XML document.
20604 * @param {Object} o An Array of row objects which represents the dataset.
20605 * @return {Object} data A data block which is used by an Roo.data.Store object as
20606 * a cache of Roo.data.Records.
20608 readRecords : function(o){
20609 var sid = this.meta ? this.meta.id : null;
20610 var recordType = this.recordType, fields = recordType.prototype.fields;
20613 for(var i = 0; i < root.length; i++){
20616 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20617 for(var j = 0, jlen = fields.length; j < jlen; j++){
20618 var f = fields.items[j];
20619 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20620 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20622 values[f.name] = v;
20624 var record = new recordType(values, id);
20626 records[records.length] = record;
20630 totalRecords : records.length
20635 * Ext JS Library 1.1.1
20636 * Copyright(c) 2006-2007, Ext JS, LLC.
20638 * Originally Released Under LGPL - original licence link has changed is not relivant.
20641 * <script type="text/javascript">
20646 * @class Roo.data.Tree
20647 * @extends Roo.util.Observable
20648 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20649 * in the tree have most standard DOM functionality.
20651 * @param {Node} root (optional) The root node
20653 Roo.data.Tree = function(root){
20654 this.nodeHash = {};
20656 * The root node for this tree
20661 this.setRootNode(root);
20666 * Fires when a new child node is appended to a node in this tree.
20667 * @param {Tree} tree The owner tree
20668 * @param {Node} parent The parent node
20669 * @param {Node} node The newly appended node
20670 * @param {Number} index The index of the newly appended node
20675 * Fires when a child node is removed from a node in this tree.
20676 * @param {Tree} tree The owner tree
20677 * @param {Node} parent The parent node
20678 * @param {Node} node The child node removed
20683 * Fires when a node is moved to a new location in the tree
20684 * @param {Tree} tree The owner tree
20685 * @param {Node} node The node moved
20686 * @param {Node} oldParent The old parent of this node
20687 * @param {Node} newParent The new parent of this node
20688 * @param {Number} index The index it was moved to
20693 * Fires when a new child node is inserted in a node in this tree.
20694 * @param {Tree} tree The owner tree
20695 * @param {Node} parent The parent node
20696 * @param {Node} node The child node inserted
20697 * @param {Node} refNode The child node the node was inserted before
20701 * @event beforeappend
20702 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20703 * @param {Tree} tree The owner tree
20704 * @param {Node} parent The parent node
20705 * @param {Node} node The child node to be appended
20707 "beforeappend" : true,
20709 * @event beforeremove
20710 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20711 * @param {Tree} tree The owner tree
20712 * @param {Node} parent The parent node
20713 * @param {Node} node The child node to be removed
20715 "beforeremove" : true,
20717 * @event beforemove
20718 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20719 * @param {Tree} tree The owner tree
20720 * @param {Node} node The node being moved
20721 * @param {Node} oldParent The parent of the node
20722 * @param {Node} newParent The new parent the node is moving to
20723 * @param {Number} index The index it is being moved to
20725 "beforemove" : true,
20727 * @event beforeinsert
20728 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20729 * @param {Tree} tree The owner tree
20730 * @param {Node} parent The parent node
20731 * @param {Node} node The child node to be inserted
20732 * @param {Node} refNode The child node the node is being inserted before
20734 "beforeinsert" : true
20737 Roo.data.Tree.superclass.constructor.call(this);
20740 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20741 pathSeparator: "/",
20743 proxyNodeEvent : function(){
20744 return this.fireEvent.apply(this, arguments);
20748 * Returns the root node for this tree.
20751 getRootNode : function(){
20756 * Sets the root node for this tree.
20757 * @param {Node} node
20760 setRootNode : function(node){
20762 node.ownerTree = this;
20763 node.isRoot = true;
20764 this.registerNode(node);
20769 * Gets a node in this tree by its id.
20770 * @param {String} id
20773 getNodeById : function(id){
20774 return this.nodeHash[id];
20777 registerNode : function(node){
20778 this.nodeHash[node.id] = node;
20781 unregisterNode : function(node){
20782 delete this.nodeHash[node.id];
20785 toString : function(){
20786 return "[Tree"+(this.id?" "+this.id:"")+"]";
20791 * @class Roo.data.Node
20792 * @extends Roo.util.Observable
20793 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
20794 * @cfg {String} id The id for this node. If one is not specified, one is generated.
20796 * @param {Object} attributes The attributes/config for the node
20798 Roo.data.Node = function(attributes){
20800 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
20803 this.attributes = attributes || {};
20804 this.leaf = this.attributes.leaf;
20806 * The node id. @type String
20808 this.id = this.attributes.id;
20810 this.id = Roo.id(null, "ynode-");
20811 this.attributes.id = this.id;
20814 * All child nodes of this node. @type Array
20816 this.childNodes = [];
20817 if(!this.childNodes.indexOf){ // indexOf is a must
20818 this.childNodes.indexOf = function(o){
20819 for(var i = 0, len = this.length; i < len; i++){
20820 if(this[i] == o) return i;
20826 * The parent node for this node. @type Node
20828 this.parentNode = null;
20830 * The first direct child node of this node, or null if this node has no child nodes. @type Node
20832 this.firstChild = null;
20834 * The last direct child node of this node, or null if this node has no child nodes. @type Node
20836 this.lastChild = null;
20838 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
20840 this.previousSibling = null;
20842 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
20844 this.nextSibling = null;
20849 * Fires when a new child node is appended
20850 * @param {Tree} tree The owner tree
20851 * @param {Node} this This node
20852 * @param {Node} node The newly appended node
20853 * @param {Number} index The index of the newly appended node
20858 * Fires when a child node is removed
20859 * @param {Tree} tree The owner tree
20860 * @param {Node} this This node
20861 * @param {Node} node The removed node
20866 * Fires when this node is moved to a new location in the tree
20867 * @param {Tree} tree The owner tree
20868 * @param {Node} this This node
20869 * @param {Node} oldParent The old parent of this node
20870 * @param {Node} newParent The new parent of this node
20871 * @param {Number} index The index it was moved to
20876 * Fires when a new child node is inserted.
20877 * @param {Tree} tree The owner tree
20878 * @param {Node} this This node
20879 * @param {Node} node The child node inserted
20880 * @param {Node} refNode The child node the node was inserted before
20884 * @event beforeappend
20885 * Fires before a new child is appended, return false to cancel the append.
20886 * @param {Tree} tree The owner tree
20887 * @param {Node} this This node
20888 * @param {Node} node The child node to be appended
20890 "beforeappend" : true,
20892 * @event beforeremove
20893 * Fires before a child is removed, return false to cancel the remove.
20894 * @param {Tree} tree The owner tree
20895 * @param {Node} this This node
20896 * @param {Node} node The child node to be removed
20898 "beforeremove" : true,
20900 * @event beforemove
20901 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
20902 * @param {Tree} tree The owner tree
20903 * @param {Node} this This node
20904 * @param {Node} oldParent The parent of this node
20905 * @param {Node} newParent The new parent this node is moving to
20906 * @param {Number} index The index it is being moved to
20908 "beforemove" : true,
20910 * @event beforeinsert
20911 * Fires before a new child is inserted, return false to cancel the insert.
20912 * @param {Tree} tree The owner tree
20913 * @param {Node} this This node
20914 * @param {Node} node The child node to be inserted
20915 * @param {Node} refNode The child node the node is being inserted before
20917 "beforeinsert" : true
20919 this.listeners = this.attributes.listeners;
20920 Roo.data.Node.superclass.constructor.call(this);
20923 Roo.extend(Roo.data.Node, Roo.util.Observable, {
20924 fireEvent : function(evtName){
20925 // first do standard event for this node
20926 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
20929 // then bubble it up to the tree if the event wasn't cancelled
20930 var ot = this.getOwnerTree();
20932 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
20940 * Returns true if this node is a leaf
20941 * @return {Boolean}
20943 isLeaf : function(){
20944 return this.leaf === true;
20948 setFirstChild : function(node){
20949 this.firstChild = node;
20953 setLastChild : function(node){
20954 this.lastChild = node;
20959 * Returns true if this node is the last child of its parent
20960 * @return {Boolean}
20962 isLast : function(){
20963 return (!this.parentNode ? true : this.parentNode.lastChild == this);
20967 * Returns true if this node is the first child of its parent
20968 * @return {Boolean}
20970 isFirst : function(){
20971 return (!this.parentNode ? true : this.parentNode.firstChild == this);
20974 hasChildNodes : function(){
20975 return !this.isLeaf() && this.childNodes.length > 0;
20979 * Insert node(s) as the last child node of this node.
20980 * @param {Node/Array} node The node or Array of nodes to append
20981 * @return {Node} The appended node if single append, or null if an array was passed
20983 appendChild : function(node){
20985 if(node instanceof Array){
20987 }else if(arguments.length > 1){
20990 // if passed an array or multiple args do them one by one
20992 for(var i = 0, len = multi.length; i < len; i++) {
20993 this.appendChild(multi[i]);
20996 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
20999 var index = this.childNodes.length;
21000 var oldParent = node.parentNode;
21001 // it's a move, make sure we move it cleanly
21003 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21006 oldParent.removeChild(node);
21008 index = this.childNodes.length;
21010 this.setFirstChild(node);
21012 this.childNodes.push(node);
21013 node.parentNode = this;
21014 var ps = this.childNodes[index-1];
21016 node.previousSibling = ps;
21017 ps.nextSibling = node;
21019 node.previousSibling = null;
21021 node.nextSibling = null;
21022 this.setLastChild(node);
21023 node.setOwnerTree(this.getOwnerTree());
21024 this.fireEvent("append", this.ownerTree, this, node, index);
21026 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21033 * Removes a child node from this node.
21034 * @param {Node} node The node to remove
21035 * @return {Node} The removed node
21037 removeChild : function(node){
21038 var index = this.childNodes.indexOf(node);
21042 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21046 // remove it from childNodes collection
21047 this.childNodes.splice(index, 1);
21050 if(node.previousSibling){
21051 node.previousSibling.nextSibling = node.nextSibling;
21053 if(node.nextSibling){
21054 node.nextSibling.previousSibling = node.previousSibling;
21057 // update child refs
21058 if(this.firstChild == node){
21059 this.setFirstChild(node.nextSibling);
21061 if(this.lastChild == node){
21062 this.setLastChild(node.previousSibling);
21065 node.setOwnerTree(null);
21066 // clear any references from the node
21067 node.parentNode = null;
21068 node.previousSibling = null;
21069 node.nextSibling = null;
21070 this.fireEvent("remove", this.ownerTree, this, node);
21075 * Inserts the first node before the second node in this nodes childNodes collection.
21076 * @param {Node} node The node to insert
21077 * @param {Node} refNode The node to insert before (if null the node is appended)
21078 * @return {Node} The inserted node
21080 insertBefore : function(node, refNode){
21081 if(!refNode){ // like standard Dom, refNode can be null for append
21082 return this.appendChild(node);
21085 if(node == refNode){
21089 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21092 var index = this.childNodes.indexOf(refNode);
21093 var oldParent = node.parentNode;
21094 var refIndex = index;
21096 // when moving internally, indexes will change after remove
21097 if(oldParent == this && this.childNodes.indexOf(node) < index){
21101 // it's a move, make sure we move it cleanly
21103 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21106 oldParent.removeChild(node);
21109 this.setFirstChild(node);
21111 this.childNodes.splice(refIndex, 0, node);
21112 node.parentNode = this;
21113 var ps = this.childNodes[refIndex-1];
21115 node.previousSibling = ps;
21116 ps.nextSibling = node;
21118 node.previousSibling = null;
21120 node.nextSibling = refNode;
21121 refNode.previousSibling = node;
21122 node.setOwnerTree(this.getOwnerTree());
21123 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21125 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21131 * Returns the child node at the specified index.
21132 * @param {Number} index
21135 item : function(index){
21136 return this.childNodes[index];
21140 * Replaces one child node in this node with another.
21141 * @param {Node} newChild The replacement node
21142 * @param {Node} oldChild The node to replace
21143 * @return {Node} The replaced node
21145 replaceChild : function(newChild, oldChild){
21146 this.insertBefore(newChild, oldChild);
21147 this.removeChild(oldChild);
21152 * Returns the index of a child node
21153 * @param {Node} node
21154 * @return {Number} The index of the node or -1 if it was not found
21156 indexOf : function(child){
21157 return this.childNodes.indexOf(child);
21161 * Returns the tree this node is in.
21164 getOwnerTree : function(){
21165 // if it doesn't have one, look for one
21166 if(!this.ownerTree){
21170 this.ownerTree = p.ownerTree;
21176 return this.ownerTree;
21180 * Returns depth of this node (the root node has a depth of 0)
21183 getDepth : function(){
21186 while(p.parentNode){
21194 setOwnerTree : function(tree){
21195 // if it's move, we need to update everyone
21196 if(tree != this.ownerTree){
21197 if(this.ownerTree){
21198 this.ownerTree.unregisterNode(this);
21200 this.ownerTree = tree;
21201 var cs = this.childNodes;
21202 for(var i = 0, len = cs.length; i < len; i++) {
21203 cs[i].setOwnerTree(tree);
21206 tree.registerNode(this);
21212 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21213 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21214 * @return {String} The path
21216 getPath : function(attr){
21217 attr = attr || "id";
21218 var p = this.parentNode;
21219 var b = [this.attributes[attr]];
21221 b.unshift(p.attributes[attr]);
21224 var sep = this.getOwnerTree().pathSeparator;
21225 return sep + b.join(sep);
21229 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21230 * function call will be the scope provided or the current node. The arguments to the function
21231 * will be the args provided or the current node. If the function returns false at any point,
21232 * the bubble is stopped.
21233 * @param {Function} fn The function to call
21234 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21235 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21237 bubble : function(fn, scope, args){
21240 if(fn.call(scope || p, args || p) === false){
21248 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21249 * function call will be the scope provided or the current node. The arguments to the function
21250 * will be the args provided or the current node. If the function returns false at any point,
21251 * the cascade is stopped on that branch.
21252 * @param {Function} fn The function to call
21253 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21254 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21256 cascade : function(fn, scope, args){
21257 if(fn.call(scope || this, args || this) !== false){
21258 var cs = this.childNodes;
21259 for(var i = 0, len = cs.length; i < len; i++) {
21260 cs[i].cascade(fn, scope, args);
21266 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21267 * function call will be the scope provided or the current node. The arguments to the function
21268 * will be the args provided or the current node. If the function returns false at any point,
21269 * the iteration stops.
21270 * @param {Function} fn The function to call
21271 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21272 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21274 eachChild : function(fn, scope, args){
21275 var cs = this.childNodes;
21276 for(var i = 0, len = cs.length; i < len; i++) {
21277 if(fn.call(scope || this, args || cs[i]) === false){
21284 * Finds the first child that has the attribute with the specified value.
21285 * @param {String} attribute The attribute name
21286 * @param {Mixed} value The value to search for
21287 * @return {Node} The found child or null if none was found
21289 findChild : function(attribute, value){
21290 var cs = this.childNodes;
21291 for(var i = 0, len = cs.length; i < len; i++) {
21292 if(cs[i].attributes[attribute] == value){
21300 * Finds the first child by a custom function. The child matches if the function passed
21302 * @param {Function} fn
21303 * @param {Object} scope (optional)
21304 * @return {Node} The found child or null if none was found
21306 findChildBy : function(fn, scope){
21307 var cs = this.childNodes;
21308 for(var i = 0, len = cs.length; i < len; i++) {
21309 if(fn.call(scope||cs[i], cs[i]) === true){
21317 * Sorts this nodes children using the supplied sort function
21318 * @param {Function} fn
21319 * @param {Object} scope (optional)
21321 sort : function(fn, scope){
21322 var cs = this.childNodes;
21323 var len = cs.length;
21325 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21327 for(var i = 0; i < len; i++){
21329 n.previousSibling = cs[i-1];
21330 n.nextSibling = cs[i+1];
21332 this.setFirstChild(n);
21335 this.setLastChild(n);
21342 * Returns true if this node is an ancestor (at any point) of the passed node.
21343 * @param {Node} node
21344 * @return {Boolean}
21346 contains : function(node){
21347 return node.isAncestor(this);
21351 * Returns true if the passed node is an ancestor (at any point) of this node.
21352 * @param {Node} node
21353 * @return {Boolean}
21355 isAncestor : function(node){
21356 var p = this.parentNode;
21366 toString : function(){
21367 return "[Node"+(this.id?" "+this.id:"")+"]";
21371 * Ext JS Library 1.1.1
21372 * Copyright(c) 2006-2007, Ext JS, LLC.
21374 * Originally Released Under LGPL - original licence link has changed is not relivant.
21377 * <script type="text/javascript">
21382 * @class Roo.ComponentMgr
21383 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21386 Roo.ComponentMgr = function(){
21387 var all = new Roo.util.MixedCollection();
21391 * Registers a component.
21392 * @param {Roo.Component} c The component
21394 register : function(c){
21399 * Unregisters a component.
21400 * @param {Roo.Component} c The component
21402 unregister : function(c){
21407 * Returns a component by id
21408 * @param {String} id The component id
21410 get : function(id){
21411 return all.get(id);
21415 * Registers a function that will be called when a specified component is added to ComponentMgr
21416 * @param {String} id The component id
21417 * @param {Funtction} fn The callback function
21418 * @param {Object} scope The scope of the callback
21420 onAvailable : function(id, fn, scope){
21421 all.on("add", function(index, o){
21423 fn.call(scope || o, o);
21424 all.un("add", fn, scope);
21431 * Ext JS Library 1.1.1
21432 * Copyright(c) 2006-2007, Ext JS, LLC.
21434 * Originally Released Under LGPL - original licence link has changed is not relivant.
21437 * <script type="text/javascript">
21441 * @class Roo.Component
21442 * @extends Roo.util.Observable
21443 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21444 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21445 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21446 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21447 * All visual components (widgets) that require rendering into a layout should subclass Component.
21449 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21450 * 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
21451 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21453 Roo.Component = function(config){
21454 config = config || {};
21455 if(config.tagName || config.dom || typeof config == "string"){ // element object
21456 config = {el: config, id: config.id || config};
21458 this.initialConfig = config;
21460 Roo.apply(this, config);
21464 * Fires after the component is disabled.
21465 * @param {Roo.Component} this
21470 * Fires after the component is enabled.
21471 * @param {Roo.Component} this
21475 * @event beforeshow
21476 * Fires before the component is shown. Return false to stop the show.
21477 * @param {Roo.Component} this
21482 * Fires after the component is shown.
21483 * @param {Roo.Component} this
21487 * @event beforehide
21488 * Fires before the component is hidden. Return false to stop the hide.
21489 * @param {Roo.Component} this
21494 * Fires after the component is hidden.
21495 * @param {Roo.Component} this
21499 * @event beforerender
21500 * Fires before the component is rendered. Return false to stop the render.
21501 * @param {Roo.Component} this
21503 beforerender : true,
21506 * Fires after the component is rendered.
21507 * @param {Roo.Component} this
21511 * @event beforedestroy
21512 * Fires before the component is destroyed. Return false to stop the destroy.
21513 * @param {Roo.Component} this
21515 beforedestroy : true,
21518 * Fires after the component is destroyed.
21519 * @param {Roo.Component} this
21524 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21526 Roo.ComponentMgr.register(this);
21527 Roo.Component.superclass.constructor.call(this);
21528 this.initComponent();
21529 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21530 this.render(this.renderTo);
21531 delete this.renderTo;
21536 Roo.Component.AUTO_ID = 1000;
21538 Roo.extend(Roo.Component, Roo.util.Observable, {
21540 * @property {Boolean} hidden
21541 * true if this component is hidden. Read-only.
21545 * true if this component is disabled. Read-only.
21549 * true if this component has been rendered. Read-only.
21553 /** @cfg {String} disableClass
21554 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21556 disabledClass : "x-item-disabled",
21557 /** @cfg {Boolean} allowDomMove
21558 * Whether the component can move the Dom node when rendering (defaults to true).
21560 allowDomMove : true,
21561 /** @cfg {String} hideMode
21562 * How this component should hidden. Supported values are
21563 * "visibility" (css visibility), "offsets" (negative offset position) and
21564 * "display" (css display) - defaults to "display".
21566 hideMode: 'display',
21569 ctype : "Roo.Component",
21571 /** @cfg {String} actionMode
21572 * which property holds the element that used for hide() / show() / disable() / enable()
21578 getActionEl : function(){
21579 return this[this.actionMode];
21582 initComponent : Roo.emptyFn,
21584 * If this is a lazy rendering component, render it to its container element.
21585 * @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.
21587 render : function(container, position){
21588 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21589 if(!container && this.el){
21590 this.el = Roo.get(this.el);
21591 container = this.el.dom.parentNode;
21592 this.allowDomMove = false;
21594 this.container = Roo.get(container);
21595 this.rendered = true;
21596 if(position !== undefined){
21597 if(typeof position == 'number'){
21598 position = this.container.dom.childNodes[position];
21600 position = Roo.getDom(position);
21603 this.onRender(this.container, position || null);
21605 this.el.addClass(this.cls);
21609 this.el.applyStyles(this.style);
21612 this.fireEvent("render", this);
21613 this.afterRender(this.container);
21625 // default function is not really useful
21626 onRender : function(ct, position){
21628 this.el = Roo.get(this.el);
21629 if(this.allowDomMove !== false){
21630 ct.dom.insertBefore(this.el.dom, position);
21636 getAutoCreate : function(){
21637 var cfg = typeof this.autoCreate == "object" ?
21638 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21639 if(this.id && !cfg.id){
21646 afterRender : Roo.emptyFn,
21649 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21650 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21652 destroy : function(){
21653 if(this.fireEvent("beforedestroy", this) !== false){
21654 this.purgeListeners();
21655 this.beforeDestroy();
21657 this.el.removeAllListeners();
21659 if(this.actionMode == "container"){
21660 this.container.remove();
21664 Roo.ComponentMgr.unregister(this);
21665 this.fireEvent("destroy", this);
21670 beforeDestroy : function(){
21675 onDestroy : function(){
21680 * Returns the underlying {@link Roo.Element}.
21681 * @return {Roo.Element} The element
21683 getEl : function(){
21688 * Returns the id of this component.
21691 getId : function(){
21696 * Try to focus this component.
21697 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21698 * @return {Roo.Component} this
21700 focus : function(selectText){
21703 if(selectText === true){
21704 this.el.dom.select();
21719 * Disable this component.
21720 * @return {Roo.Component} this
21722 disable : function(){
21726 this.disabled = true;
21727 this.fireEvent("disable", this);
21732 onDisable : function(){
21733 this.getActionEl().addClass(this.disabledClass);
21734 this.el.dom.disabled = true;
21738 * Enable this component.
21739 * @return {Roo.Component} this
21741 enable : function(){
21745 this.disabled = false;
21746 this.fireEvent("enable", this);
21751 onEnable : function(){
21752 this.getActionEl().removeClass(this.disabledClass);
21753 this.el.dom.disabled = false;
21757 * Convenience function for setting disabled/enabled by boolean.
21758 * @param {Boolean} disabled
21760 setDisabled : function(disabled){
21761 this[disabled ? "disable" : "enable"]();
21765 * Show this component.
21766 * @return {Roo.Component} this
21769 if(this.fireEvent("beforeshow", this) !== false){
21770 this.hidden = false;
21774 this.fireEvent("show", this);
21780 onShow : function(){
21781 var ae = this.getActionEl();
21782 if(this.hideMode == 'visibility'){
21783 ae.dom.style.visibility = "visible";
21784 }else if(this.hideMode == 'offsets'){
21785 ae.removeClass('x-hidden');
21787 ae.dom.style.display = "";
21792 * Hide this component.
21793 * @return {Roo.Component} this
21796 if(this.fireEvent("beforehide", this) !== false){
21797 this.hidden = true;
21801 this.fireEvent("hide", this);
21807 onHide : function(){
21808 var ae = this.getActionEl();
21809 if(this.hideMode == 'visibility'){
21810 ae.dom.style.visibility = "hidden";
21811 }else if(this.hideMode == 'offsets'){
21812 ae.addClass('x-hidden');
21814 ae.dom.style.display = "none";
21819 * Convenience function to hide or show this component by boolean.
21820 * @param {Boolean} visible True to show, false to hide
21821 * @return {Roo.Component} this
21823 setVisible: function(visible){
21833 * Returns true if this component is visible.
21835 isVisible : function(){
21836 return this.getActionEl().isVisible();
21839 cloneConfig : function(overrides){
21840 overrides = overrides || {};
21841 var id = overrides.id || Roo.id();
21842 var cfg = Roo.applyIf(overrides, this.initialConfig);
21843 cfg.id = id; // prevent dup id
21844 return new this.constructor(cfg);
21848 * Ext JS Library 1.1.1
21849 * Copyright(c) 2006-2007, Ext JS, LLC.
21851 * Originally Released Under LGPL - original licence link has changed is not relivant.
21854 * <script type="text/javascript">
21859 * @extends Roo.Element
21860 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
21861 * automatic maintaining of shadow/shim positions.
21862 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
21863 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
21864 * you can pass a string with a CSS class name. False turns off the shadow.
21865 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
21866 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
21867 * @cfg {String} cls CSS class to add to the element
21868 * @cfg {Number} zindex Starting z-index (defaults to 11000)
21869 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
21871 * @param {Object} config An object with config options.
21872 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
21875 Roo.Layer = function(config, existingEl){
21876 config = config || {};
21877 var dh = Roo.DomHelper;
21878 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
21880 this.dom = Roo.getDom(existingEl);
21883 var o = config.dh || {tag: "div", cls: "x-layer"};
21884 this.dom = dh.append(pel, o);
21887 this.addClass(config.cls);
21889 this.constrain = config.constrain !== false;
21890 this.visibilityMode = Roo.Element.VISIBILITY;
21892 this.id = this.dom.id = config.id;
21894 this.id = Roo.id(this.dom);
21896 this.zindex = config.zindex || this.getZIndex();
21897 this.position("absolute", this.zindex);
21899 this.shadowOffset = config.shadowOffset || 4;
21900 this.shadow = new Roo.Shadow({
21901 offset : this.shadowOffset,
21902 mode : config.shadow
21905 this.shadowOffset = 0;
21907 this.useShim = config.shim !== false && Roo.useShims;
21908 this.useDisplay = config.useDisplay;
21912 var supr = Roo.Element.prototype;
21914 // shims are shared among layer to keep from having 100 iframes
21917 Roo.extend(Roo.Layer, Roo.Element, {
21919 getZIndex : function(){
21920 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
21923 getShim : function(){
21930 var shim = shims.shift();
21932 shim = this.createShim();
21933 shim.enableDisplayMode('block');
21934 shim.dom.style.display = 'none';
21935 shim.dom.style.visibility = 'visible';
21937 var pn = this.dom.parentNode;
21938 if(shim.dom.parentNode != pn){
21939 pn.insertBefore(shim.dom, this.dom);
21941 shim.setStyle('z-index', this.getZIndex()-2);
21946 hideShim : function(){
21948 this.shim.setDisplayed(false);
21949 shims.push(this.shim);
21954 disableShadow : function(){
21956 this.shadowDisabled = true;
21957 this.shadow.hide();
21958 this.lastShadowOffset = this.shadowOffset;
21959 this.shadowOffset = 0;
21963 enableShadow : function(show){
21965 this.shadowDisabled = false;
21966 this.shadowOffset = this.lastShadowOffset;
21967 delete this.lastShadowOffset;
21975 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
21976 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
21977 sync : function(doShow){
21978 var sw = this.shadow;
21979 if(!this.updating && this.isVisible() && (sw || this.useShim)){
21980 var sh = this.getShim();
21982 var w = this.getWidth(),
21983 h = this.getHeight();
21985 var l = this.getLeft(true),
21986 t = this.getTop(true);
21988 if(sw && !this.shadowDisabled){
21989 if(doShow && !sw.isVisible()){
21992 sw.realign(l, t, w, h);
21998 // fit the shim behind the shadow, so it is shimmed too
21999 var a = sw.adjusts, s = sh.dom.style;
22000 s.left = (Math.min(l, l+a.l))+"px";
22001 s.top = (Math.min(t, t+a.t))+"px";
22002 s.width = (w+a.w)+"px";
22003 s.height = (h+a.h)+"px";
22010 sh.setLeftTop(l, t);
22017 destroy : function(){
22020 this.shadow.hide();
22022 this.removeAllListeners();
22023 var pn = this.dom.parentNode;
22025 pn.removeChild(this.dom);
22027 Roo.Element.uncache(this.id);
22030 remove : function(){
22035 beginUpdate : function(){
22036 this.updating = true;
22040 endUpdate : function(){
22041 this.updating = false;
22046 hideUnders : function(negOffset){
22048 this.shadow.hide();
22054 constrainXY : function(){
22055 if(this.constrain){
22056 var vw = Roo.lib.Dom.getViewWidth(),
22057 vh = Roo.lib.Dom.getViewHeight();
22058 var s = Roo.get(document).getScroll();
22060 var xy = this.getXY();
22061 var x = xy[0], y = xy[1];
22062 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22063 // only move it if it needs it
22065 // first validate right/bottom
22066 if((x + w) > vw+s.left){
22067 x = vw - w - this.shadowOffset;
22070 if((y + h) > vh+s.top){
22071 y = vh - h - this.shadowOffset;
22074 // then make sure top/left isn't negative
22085 var ay = this.avoidY;
22086 if(y <= ay && (y+h) >= ay){
22092 supr.setXY.call(this, xy);
22098 isVisible : function(){
22099 return this.visible;
22103 showAction : function(){
22104 this.visible = true; // track visibility to prevent getStyle calls
22105 if(this.useDisplay === true){
22106 this.setDisplayed("");
22107 }else if(this.lastXY){
22108 supr.setXY.call(this, this.lastXY);
22109 }else if(this.lastLT){
22110 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22115 hideAction : function(){
22116 this.visible = false;
22117 if(this.useDisplay === true){
22118 this.setDisplayed(false);
22120 this.setLeftTop(-10000,-10000);
22124 // overridden Element method
22125 setVisible : function(v, a, d, c, e){
22130 var cb = function(){
22135 }.createDelegate(this);
22136 supr.setVisible.call(this, true, true, d, cb, e);
22139 this.hideUnders(true);
22148 }.createDelegate(this);
22150 supr.setVisible.call(this, v, a, d, cb, e);
22159 storeXY : function(xy){
22160 delete this.lastLT;
22164 storeLeftTop : function(left, top){
22165 delete this.lastXY;
22166 this.lastLT = [left, top];
22170 beforeFx : function(){
22171 this.beforeAction();
22172 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22176 afterFx : function(){
22177 Roo.Layer.superclass.afterFx.apply(this, arguments);
22178 this.sync(this.isVisible());
22182 beforeAction : function(){
22183 if(!this.updating && this.shadow){
22184 this.shadow.hide();
22188 // overridden Element method
22189 setLeft : function(left){
22190 this.storeLeftTop(left, this.getTop(true));
22191 supr.setLeft.apply(this, arguments);
22195 setTop : function(top){
22196 this.storeLeftTop(this.getLeft(true), top);
22197 supr.setTop.apply(this, arguments);
22201 setLeftTop : function(left, top){
22202 this.storeLeftTop(left, top);
22203 supr.setLeftTop.apply(this, arguments);
22207 setXY : function(xy, a, d, c, e){
22209 this.beforeAction();
22211 var cb = this.createCB(c);
22212 supr.setXY.call(this, xy, a, d, cb, e);
22219 createCB : function(c){
22230 // overridden Element method
22231 setX : function(x, a, d, c, e){
22232 this.setXY([x, this.getY()], a, d, c, e);
22235 // overridden Element method
22236 setY : function(y, a, d, c, e){
22237 this.setXY([this.getX(), y], a, d, c, e);
22240 // overridden Element method
22241 setSize : function(w, h, a, d, c, e){
22242 this.beforeAction();
22243 var cb = this.createCB(c);
22244 supr.setSize.call(this, w, h, a, d, cb, e);
22250 // overridden Element method
22251 setWidth : function(w, a, d, c, e){
22252 this.beforeAction();
22253 var cb = this.createCB(c);
22254 supr.setWidth.call(this, w, a, d, cb, e);
22260 // overridden Element method
22261 setHeight : function(h, a, d, c, e){
22262 this.beforeAction();
22263 var cb = this.createCB(c);
22264 supr.setHeight.call(this, h, a, d, cb, e);
22270 // overridden Element method
22271 setBounds : function(x, y, w, h, a, d, c, e){
22272 this.beforeAction();
22273 var cb = this.createCB(c);
22275 this.storeXY([x, y]);
22276 supr.setXY.call(this, [x, y]);
22277 supr.setSize.call(this, w, h, a, d, cb, e);
22280 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22286 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22287 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22288 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22289 * @param {Number} zindex The new z-index to set
22290 * @return {this} The Layer
22292 setZIndex : function(zindex){
22293 this.zindex = zindex;
22294 this.setStyle("z-index", zindex + 2);
22296 this.shadow.setZIndex(zindex + 1);
22299 this.shim.setStyle("z-index", zindex);
22305 * Ext JS Library 1.1.1
22306 * Copyright(c) 2006-2007, Ext JS, LLC.
22308 * Originally Released Under LGPL - original licence link has changed is not relivant.
22311 * <script type="text/javascript">
22316 * @class Roo.Shadow
22317 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22318 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22319 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22321 * Create a new Shadow
22322 * @param {Object} config The config object
22324 Roo.Shadow = function(config){
22325 Roo.apply(this, config);
22326 if(typeof this.mode != "string"){
22327 this.mode = this.defaultMode;
22329 var o = this.offset, a = {h: 0};
22330 var rad = Math.floor(this.offset/2);
22331 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22337 a.l -= this.offset + rad;
22338 a.t -= this.offset + rad;
22349 a.l -= (this.offset - rad);
22350 a.t -= this.offset + rad;
22352 a.w -= (this.offset - rad)*2;
22363 a.l -= (this.offset - rad);
22364 a.t -= (this.offset - rad);
22366 a.w -= (this.offset + rad + 1);
22367 a.h -= (this.offset + rad);
22376 Roo.Shadow.prototype = {
22378 * @cfg {String} mode
22379 * The shadow display mode. Supports the following options:<br />
22380 * sides: Shadow displays on both sides and bottom only<br />
22381 * frame: Shadow displays equally on all four sides<br />
22382 * drop: Traditional bottom-right drop shadow (default)
22385 * @cfg {String} offset
22386 * The number of pixels to offset the shadow from the element (defaults to 4)
22391 defaultMode: "drop",
22394 * Displays the shadow under the target element
22395 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22397 show : function(target){
22398 target = Roo.get(target);
22400 this.el = Roo.Shadow.Pool.pull();
22401 if(this.el.dom.nextSibling != target.dom){
22402 this.el.insertBefore(target);
22405 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22407 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22410 target.getLeft(true),
22411 target.getTop(true),
22415 this.el.dom.style.display = "block";
22419 * Returns true if the shadow is visible, else false
22421 isVisible : function(){
22422 return this.el ? true : false;
22426 * Direct alignment when values are already available. Show must be called at least once before
22427 * calling this method to ensure it is initialized.
22428 * @param {Number} left The target element left position
22429 * @param {Number} top The target element top position
22430 * @param {Number} width The target element width
22431 * @param {Number} height The target element height
22433 realign : function(l, t, w, h){
22437 var a = this.adjusts, d = this.el.dom, s = d.style;
22439 s.left = (l+a.l)+"px";
22440 s.top = (t+a.t)+"px";
22441 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22442 if(s.width != sws || s.height != shs){
22446 var cn = d.childNodes;
22447 var sww = Math.max(0, (sw-12))+"px";
22448 cn[0].childNodes[1].style.width = sww;
22449 cn[1].childNodes[1].style.width = sww;
22450 cn[2].childNodes[1].style.width = sww;
22451 cn[1].style.height = Math.max(0, (sh-12))+"px";
22457 * Hides this shadow
22461 this.el.dom.style.display = "none";
22462 Roo.Shadow.Pool.push(this.el);
22468 * Adjust the z-index of this shadow
22469 * @param {Number} zindex The new z-index
22471 setZIndex : function(z){
22474 this.el.setStyle("z-index", z);
22479 // Private utility class that manages the internal Shadow cache
22480 Roo.Shadow.Pool = function(){
22482 var markup = Roo.isIE ?
22483 '<div class="x-ie-shadow"></div>' :
22484 '<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>';
22487 var sh = p.shift();
22489 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22490 sh.autoBoxAdjust = false;
22495 push : function(sh){
22501 * Ext JS Library 1.1.1
22502 * Copyright(c) 2006-2007, Ext JS, LLC.
22504 * Originally Released Under LGPL - original licence link has changed is not relivant.
22507 * <script type="text/javascript">
22511 * @class Roo.BoxComponent
22512 * @extends Roo.Component
22513 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22514 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22515 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22516 * layout containers.
22518 * @param {Roo.Element/String/Object} config The configuration options.
22520 Roo.BoxComponent = function(config){
22521 Roo.Component.call(this, config);
22525 * Fires after the component is resized.
22526 * @param {Roo.Component} this
22527 * @param {Number} adjWidth The box-adjusted width that was set
22528 * @param {Number} adjHeight The box-adjusted height that was set
22529 * @param {Number} rawWidth The width that was originally specified
22530 * @param {Number} rawHeight The height that was originally specified
22535 * Fires after the component is moved.
22536 * @param {Roo.Component} this
22537 * @param {Number} x The new x position
22538 * @param {Number} y The new y position
22544 Roo.extend(Roo.BoxComponent, Roo.Component, {
22545 // private, set in afterRender to signify that the component has been rendered
22547 // private, used to defer height settings to subclasses
22548 deferHeight: false,
22549 /** @cfg {Number} width
22550 * width (optional) size of component
22552 /** @cfg {Number} height
22553 * height (optional) size of component
22557 * Sets the width and height of the component. This method fires the resize event. This method can accept
22558 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22559 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22560 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22561 * @return {Roo.BoxComponent} this
22563 setSize : function(w, h){
22564 // support for standard size objects
22565 if(typeof w == 'object'){
22570 if(!this.boxReady){
22576 // prevent recalcs when not needed
22577 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22580 this.lastSize = {width: w, height: h};
22582 var adj = this.adjustSize(w, h);
22583 var aw = adj.width, ah = adj.height;
22584 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22585 var rz = this.getResizeEl();
22586 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22587 rz.setSize(aw, ah);
22588 }else if(!this.deferHeight && ah !== undefined){
22590 }else if(aw !== undefined){
22593 this.onResize(aw, ah, w, h);
22594 this.fireEvent('resize', this, aw, ah, w, h);
22600 * Gets the current size of the component's underlying element.
22601 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22603 getSize : function(){
22604 return this.el.getSize();
22608 * Gets the current XY position of the component's underlying element.
22609 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22610 * @return {Array} The XY position of the element (e.g., [100, 200])
22612 getPosition : function(local){
22613 if(local === true){
22614 return [this.el.getLeft(true), this.el.getTop(true)];
22616 return this.xy || this.el.getXY();
22620 * Gets the current box measurements of the component's underlying element.
22621 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22622 * @returns {Object} box An object in the format {x, y, width, height}
22624 getBox : function(local){
22625 var s = this.el.getSize();
22627 s.x = this.el.getLeft(true);
22628 s.y = this.el.getTop(true);
22630 var xy = this.xy || this.el.getXY();
22638 * Sets the current box measurements of the component's underlying element.
22639 * @param {Object} box An object in the format {x, y, width, height}
22640 * @returns {Roo.BoxComponent} this
22642 updateBox : function(box){
22643 this.setSize(box.width, box.height);
22644 this.setPagePosition(box.x, box.y);
22649 getResizeEl : function(){
22650 return this.resizeEl || this.el;
22654 getPositionEl : function(){
22655 return this.positionEl || this.el;
22659 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22660 * This method fires the move event.
22661 * @param {Number} left The new left
22662 * @param {Number} top The new top
22663 * @returns {Roo.BoxComponent} this
22665 setPosition : function(x, y){
22668 if(!this.boxReady){
22671 var adj = this.adjustPosition(x, y);
22672 var ax = adj.x, ay = adj.y;
22674 var el = this.getPositionEl();
22675 if(ax !== undefined || ay !== undefined){
22676 if(ax !== undefined && ay !== undefined){
22677 el.setLeftTop(ax, ay);
22678 }else if(ax !== undefined){
22680 }else if(ay !== undefined){
22683 this.onPosition(ax, ay);
22684 this.fireEvent('move', this, ax, ay);
22690 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22691 * This method fires the move event.
22692 * @param {Number} x The new x position
22693 * @param {Number} y The new y position
22694 * @returns {Roo.BoxComponent} this
22696 setPagePosition : function(x, y){
22699 if(!this.boxReady){
22702 if(x === undefined || y === undefined){ // cannot translate undefined points
22705 var p = this.el.translatePoints(x, y);
22706 this.setPosition(p.left, p.top);
22711 onRender : function(ct, position){
22712 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22714 this.resizeEl = Roo.get(this.resizeEl);
22716 if(this.positionEl){
22717 this.positionEl = Roo.get(this.positionEl);
22722 afterRender : function(){
22723 Roo.BoxComponent.superclass.afterRender.call(this);
22724 this.boxReady = true;
22725 this.setSize(this.width, this.height);
22726 if(this.x || this.y){
22727 this.setPosition(this.x, this.y);
22729 if(this.pageX || this.pageY){
22730 this.setPagePosition(this.pageX, this.pageY);
22735 * Force the component's size to recalculate based on the underlying element's current height and width.
22736 * @returns {Roo.BoxComponent} this
22738 syncSize : function(){
22739 delete this.lastSize;
22740 this.setSize(this.el.getWidth(), this.el.getHeight());
22745 * Called after the component is resized, this method is empty by default but can be implemented by any
22746 * subclass that needs to perform custom logic after a resize occurs.
22747 * @param {Number} adjWidth The box-adjusted width that was set
22748 * @param {Number} adjHeight The box-adjusted height that was set
22749 * @param {Number} rawWidth The width that was originally specified
22750 * @param {Number} rawHeight The height that was originally specified
22752 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22757 * Called after the component is moved, this method is empty by default but can be implemented by any
22758 * subclass that needs to perform custom logic after a move occurs.
22759 * @param {Number} x The new x position
22760 * @param {Number} y The new y position
22762 onPosition : function(x, y){
22767 adjustSize : function(w, h){
22768 if(this.autoWidth){
22771 if(this.autoHeight){
22774 return {width : w, height: h};
22778 adjustPosition : function(x, y){
22779 return {x : x, y: y};
22783 * Ext JS Library 1.1.1
22784 * Copyright(c) 2006-2007, Ext JS, LLC.
22786 * Originally Released Under LGPL - original licence link has changed is not relivant.
22789 * <script type="text/javascript">
22794 * @class Roo.SplitBar
22795 * @extends Roo.util.Observable
22796 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
22800 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
22801 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
22802 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
22803 split.minSize = 100;
22804 split.maxSize = 600;
22805 split.animate = true;
22806 split.on('moved', splitterMoved);
22809 * Create a new SplitBar
22810 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
22811 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
22812 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22813 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
22814 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
22815 position of the SplitBar).
22817 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
22820 this.el = Roo.get(dragElement, true);
22821 this.el.dom.unselectable = "on";
22823 this.resizingEl = Roo.get(resizingElement, true);
22827 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22828 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
22831 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
22834 * The minimum size of the resizing element. (Defaults to 0)
22840 * The maximum size of the resizing element. (Defaults to 2000)
22843 this.maxSize = 2000;
22846 * Whether to animate the transition to the new size
22849 this.animate = false;
22852 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
22855 this.useShim = false;
22860 if(!existingProxy){
22862 this.proxy = Roo.SplitBar.createProxy(this.orientation);
22864 this.proxy = Roo.get(existingProxy).dom;
22867 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
22870 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
22873 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
22876 this.dragSpecs = {};
22879 * @private The adapter to use to positon and resize elements
22881 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
22882 this.adapter.init(this);
22884 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22886 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
22887 this.el.addClass("x-splitbar-h");
22890 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
22891 this.el.addClass("x-splitbar-v");
22897 * Fires when the splitter is moved (alias for {@link #event-moved})
22898 * @param {Roo.SplitBar} this
22899 * @param {Number} newSize the new width or height
22904 * Fires when the splitter is moved
22905 * @param {Roo.SplitBar} this
22906 * @param {Number} newSize the new width or height
22910 * @event beforeresize
22911 * Fires before the splitter is dragged
22912 * @param {Roo.SplitBar} this
22914 "beforeresize" : true,
22916 "beforeapply" : true
22919 Roo.util.Observable.call(this);
22922 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
22923 onStartProxyDrag : function(x, y){
22924 this.fireEvent("beforeresize", this);
22926 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
22928 o.enableDisplayMode("block");
22929 // all splitbars share the same overlay
22930 Roo.SplitBar.prototype.overlay = o;
22932 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
22933 this.overlay.show();
22934 Roo.get(this.proxy).setDisplayed("block");
22935 var size = this.adapter.getElementSize(this);
22936 this.activeMinSize = this.getMinimumSize();;
22937 this.activeMaxSize = this.getMaximumSize();;
22938 var c1 = size - this.activeMinSize;
22939 var c2 = Math.max(this.activeMaxSize - size, 0);
22940 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22941 this.dd.resetConstraints();
22942 this.dd.setXConstraint(
22943 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
22944 this.placement == Roo.SplitBar.LEFT ? c2 : c1
22946 this.dd.setYConstraint(0, 0);
22948 this.dd.resetConstraints();
22949 this.dd.setXConstraint(0, 0);
22950 this.dd.setYConstraint(
22951 this.placement == Roo.SplitBar.TOP ? c1 : c2,
22952 this.placement == Roo.SplitBar.TOP ? c2 : c1
22955 this.dragSpecs.startSize = size;
22956 this.dragSpecs.startPoint = [x, y];
22957 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
22961 * @private Called after the drag operation by the DDProxy
22963 onEndProxyDrag : function(e){
22964 Roo.get(this.proxy).setDisplayed(false);
22965 var endPoint = Roo.lib.Event.getXY(e);
22967 this.overlay.hide();
22970 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22971 newSize = this.dragSpecs.startSize +
22972 (this.placement == Roo.SplitBar.LEFT ?
22973 endPoint[0] - this.dragSpecs.startPoint[0] :
22974 this.dragSpecs.startPoint[0] - endPoint[0]
22977 newSize = this.dragSpecs.startSize +
22978 (this.placement == Roo.SplitBar.TOP ?
22979 endPoint[1] - this.dragSpecs.startPoint[1] :
22980 this.dragSpecs.startPoint[1] - endPoint[1]
22983 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
22984 if(newSize != this.dragSpecs.startSize){
22985 if(this.fireEvent('beforeapply', this, newSize) !== false){
22986 this.adapter.setElementSize(this, newSize);
22987 this.fireEvent("moved", this, newSize);
22988 this.fireEvent("resize", this, newSize);
22994 * Get the adapter this SplitBar uses
22995 * @return The adapter object
22997 getAdapter : function(){
22998 return this.adapter;
23002 * Set the adapter this SplitBar uses
23003 * @param {Object} adapter A SplitBar adapter object
23005 setAdapter : function(adapter){
23006 this.adapter = adapter;
23007 this.adapter.init(this);
23011 * Gets the minimum size for the resizing element
23012 * @return {Number} The minimum size
23014 getMinimumSize : function(){
23015 return this.minSize;
23019 * Sets the minimum size for the resizing element
23020 * @param {Number} minSize The minimum size
23022 setMinimumSize : function(minSize){
23023 this.minSize = minSize;
23027 * Gets the maximum size for the resizing element
23028 * @return {Number} The maximum size
23030 getMaximumSize : function(){
23031 return this.maxSize;
23035 * Sets the maximum size for the resizing element
23036 * @param {Number} maxSize The maximum size
23038 setMaximumSize : function(maxSize){
23039 this.maxSize = maxSize;
23043 * Sets the initialize size for the resizing element
23044 * @param {Number} size The initial size
23046 setCurrentSize : function(size){
23047 var oldAnimate = this.animate;
23048 this.animate = false;
23049 this.adapter.setElementSize(this, size);
23050 this.animate = oldAnimate;
23054 * Destroy this splitbar.
23055 * @param {Boolean} removeEl True to remove the element
23057 destroy : function(removeEl){
23059 this.shim.remove();
23062 this.proxy.parentNode.removeChild(this.proxy);
23070 * @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.
23072 Roo.SplitBar.createProxy = function(dir){
23073 var proxy = new Roo.Element(document.createElement("div"));
23074 proxy.unselectable();
23075 var cls = 'x-splitbar-proxy';
23076 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23077 document.body.appendChild(proxy.dom);
23082 * @class Roo.SplitBar.BasicLayoutAdapter
23083 * Default Adapter. It assumes the splitter and resizing element are not positioned
23084 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23086 Roo.SplitBar.BasicLayoutAdapter = function(){
23089 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23090 // do nothing for now
23091 init : function(s){
23095 * Called before drag operations to get the current size of the resizing element.
23096 * @param {Roo.SplitBar} s The SplitBar using this adapter
23098 getElementSize : function(s){
23099 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23100 return s.resizingEl.getWidth();
23102 return s.resizingEl.getHeight();
23107 * Called after drag operations to set the size of the resizing element.
23108 * @param {Roo.SplitBar} s The SplitBar using this adapter
23109 * @param {Number} newSize The new size to set
23110 * @param {Function} onComplete A function to be invoked when resizing is complete
23112 setElementSize : function(s, newSize, onComplete){
23113 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23115 s.resizingEl.setWidth(newSize);
23117 onComplete(s, newSize);
23120 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23125 s.resizingEl.setHeight(newSize);
23127 onComplete(s, newSize);
23130 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23137 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23138 * @extends Roo.SplitBar.BasicLayoutAdapter
23139 * Adapter that moves the splitter element to align with the resized sizing element.
23140 * Used with an absolute positioned SplitBar.
23141 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23142 * document.body, make sure you assign an id to the body element.
23144 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23145 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23146 this.container = Roo.get(container);
23149 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23150 init : function(s){
23151 this.basic.init(s);
23154 getElementSize : function(s){
23155 return this.basic.getElementSize(s);
23158 setElementSize : function(s, newSize, onComplete){
23159 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23162 moveSplitter : function(s){
23163 var yes = Roo.SplitBar;
23164 switch(s.placement){
23166 s.el.setX(s.resizingEl.getRight());
23169 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23172 s.el.setY(s.resizingEl.getBottom());
23175 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23182 * Orientation constant - Create a vertical SplitBar
23186 Roo.SplitBar.VERTICAL = 1;
23189 * Orientation constant - Create a horizontal SplitBar
23193 Roo.SplitBar.HORIZONTAL = 2;
23196 * Placement constant - The resizing element is to the left of the splitter element
23200 Roo.SplitBar.LEFT = 1;
23203 * Placement constant - The resizing element is to the right of the splitter element
23207 Roo.SplitBar.RIGHT = 2;
23210 * Placement constant - The resizing element is positioned above the splitter element
23214 Roo.SplitBar.TOP = 3;
23217 * Placement constant - The resizing element is positioned under splitter element
23221 Roo.SplitBar.BOTTOM = 4;
23224 * Ext JS Library 1.1.1
23225 * Copyright(c) 2006-2007, Ext JS, LLC.
23227 * Originally Released Under LGPL - original licence link has changed is not relivant.
23230 * <script type="text/javascript">
23235 * @extends Roo.util.Observable
23236 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23237 * This class also supports single and multi selection modes. <br>
23238 * Create a data model bound view:
23240 var store = new Roo.data.Store(...);
23242 var view = new Roo.View({
23244 template : '<div id="{0}">{2} - {1}</div>', // auto create template
23246 singleSelect: true,
23247 selectedClass: "ydataview-selected",
23251 // listen for node click?
23252 view.on("click", function(vw, index, node, e){
23253 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23257 dataModel.load("foobar.xml");
23259 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23261 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23262 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23264 * Note: old style constructor is still suported (container, template, config)
23267 * Create a new View
23268 * @param {Object} config The config object
23271 Roo.View = function(config, depreciated_tpl, depreciated_config){
23273 if (typeof(depreciated_tpl) == 'undefined') {
23274 // new way.. - universal constructor.
23275 Roo.apply(this, config);
23276 this.el = Roo.get(this.el);
23279 this.el = Roo.get(config);
23280 this.tpl = depreciated_tpl;
23281 Roo.apply(this, depreciated_config);
23285 if(typeof(this.tpl) == "string"){
23286 this.tpl = new Roo.Template(this.tpl);
23290 this.tpl.compile();
23297 * @event beforeclick
23298 * Fires before a click is processed. Returns false to cancel the default action.
23299 * @param {Roo.View} this
23300 * @param {Number} index The index of the target node
23301 * @param {HTMLElement} node The target node
23302 * @param {Roo.EventObject} e The raw event object
23304 "beforeclick" : true,
23307 * Fires when a template node is clicked.
23308 * @param {Roo.View} this
23309 * @param {Number} index The index of the target node
23310 * @param {HTMLElement} node The target node
23311 * @param {Roo.EventObject} e The raw event object
23316 * Fires when a template node is double clicked.
23317 * @param {Roo.View} this
23318 * @param {Number} index The index of the target node
23319 * @param {HTMLElement} node The target node
23320 * @param {Roo.EventObject} e The raw event object
23324 * @event contextmenu
23325 * Fires when a template node is right clicked.
23326 * @param {Roo.View} this
23327 * @param {Number} index The index of the target node
23328 * @param {HTMLElement} node The target node
23329 * @param {Roo.EventObject} e The raw event object
23331 "contextmenu" : true,
23333 * @event selectionchange
23334 * Fires when the selected nodes change.
23335 * @param {Roo.View} this
23336 * @param {Array} selections Array of the selected nodes
23338 "selectionchange" : true,
23341 * @event beforeselect
23342 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23343 * @param {Roo.View} this
23344 * @param {HTMLElement} node The node to be selected
23345 * @param {Array} selections Array of currently selected nodes
23347 "beforeselect" : true
23351 "click": this.onClick,
23352 "dblclick": this.onDblClick,
23353 "contextmenu": this.onContextMenu,
23357 this.selections = [];
23359 this.cmp = new Roo.CompositeElementLite([]);
23361 this.store = Roo.factory(this.store, Roo.data);
23362 this.setStore(this.store, true);
23364 Roo.View.superclass.constructor.call(this);
23367 Roo.extend(Roo.View, Roo.util.Observable, {
23370 * @cfg {Roo.data.Store} store Data store to load data from.
23375 * @cfg {String|Roo.Element} el The container element.
23380 * @cfg {String|Roo.Template} tpl The template used by this View
23385 * @cfg {String} selectedClass The css class to add to selected nodes
23387 selectedClass : "x-view-selected",
23389 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23393 * Returns the element this view is bound to.
23394 * @return {Roo.Element}
23396 getEl : function(){
23401 * Refreshes the view.
23403 refresh : function(){
23405 this.clearSelections();
23406 this.el.update("");
23408 var records = this.store.getRange();
23409 if(records.length < 1){
23410 this.el.update(this.emptyText);
23413 for(var i = 0, len = records.length; i < len; i++){
23414 var data = this.prepareData(records[i].data, i, records[i]);
23415 html[html.length] = t.apply(data);
23417 this.el.update(html.join(""));
23418 this.nodes = this.el.dom.childNodes;
23419 this.updateIndexes(0);
23423 * Function to override to reformat the data that is sent to
23424 * the template for each node.
23425 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23426 * a JSON object for an UpdateManager bound view).
23428 prepareData : function(data){
23432 onUpdate : function(ds, record){
23433 this.clearSelections();
23434 var index = this.store.indexOf(record);
23435 var n = this.nodes[index];
23436 this.tpl.insertBefore(n, this.prepareData(record.data));
23437 n.parentNode.removeChild(n);
23438 this.updateIndexes(index, index);
23441 onAdd : function(ds, records, index){
23442 this.clearSelections();
23443 if(this.nodes.length == 0){
23447 var n = this.nodes[index];
23448 for(var i = 0, len = records.length; i < len; i++){
23449 var d = this.prepareData(records[i].data);
23451 this.tpl.insertBefore(n, d);
23453 this.tpl.append(this.el, d);
23456 this.updateIndexes(index);
23459 onRemove : function(ds, record, index){
23460 this.clearSelections();
23461 this.el.dom.removeChild(this.nodes[index]);
23462 this.updateIndexes(index);
23466 * Refresh an individual node.
23467 * @param {Number} index
23469 refreshNode : function(index){
23470 this.onUpdate(this.store, this.store.getAt(index));
23473 updateIndexes : function(startIndex, endIndex){
23474 var ns = this.nodes;
23475 startIndex = startIndex || 0;
23476 endIndex = endIndex || ns.length - 1;
23477 for(var i = startIndex; i <= endIndex; i++){
23478 ns[i].nodeIndex = i;
23483 * Changes the data store this view uses and refresh the view.
23484 * @param {Store} store
23486 setStore : function(store, initial){
23487 if(!initial && this.store){
23488 this.store.un("datachanged", this.refresh);
23489 this.store.un("add", this.onAdd);
23490 this.store.un("remove", this.onRemove);
23491 this.store.un("update", this.onUpdate);
23492 this.store.un("clear", this.refresh);
23496 store.on("datachanged", this.refresh, this);
23497 store.on("add", this.onAdd, this);
23498 store.on("remove", this.onRemove, this);
23499 store.on("update", this.onUpdate, this);
23500 store.on("clear", this.refresh, this);
23509 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23510 * @param {HTMLElement} node
23511 * @return {HTMLElement} The template node
23513 findItemFromChild : function(node){
23514 var el = this.el.dom;
23515 if(!node || node.parentNode == el){
23518 var p = node.parentNode;
23519 while(p && p != el){
23520 if(p.parentNode == el){
23529 onClick : function(e){
23530 var item = this.findItemFromChild(e.getTarget());
23532 var index = this.indexOf(item);
23533 if(this.onItemClick(item, index, e) !== false){
23534 this.fireEvent("click", this, index, item, e);
23537 this.clearSelections();
23542 onContextMenu : function(e){
23543 var item = this.findItemFromChild(e.getTarget());
23545 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23550 onDblClick : function(e){
23551 var item = this.findItemFromChild(e.getTarget());
23553 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23557 onItemClick : function(item, index, e){
23558 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23561 if(this.multiSelect || this.singleSelect){
23562 if(this.multiSelect && e.shiftKey && this.lastSelection){
23563 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23565 this.select(item, this.multiSelect && e.ctrlKey);
23566 this.lastSelection = item;
23568 e.preventDefault();
23574 * Get the number of selected nodes.
23577 getSelectionCount : function(){
23578 return this.selections.length;
23582 * Get the currently selected nodes.
23583 * @return {Array} An array of HTMLElements
23585 getSelectedNodes : function(){
23586 return this.selections;
23590 * Get the indexes of the selected nodes.
23593 getSelectedIndexes : function(){
23594 var indexes = [], s = this.selections;
23595 for(var i = 0, len = s.length; i < len; i++){
23596 indexes.push(s[i].nodeIndex);
23602 * Clear all selections
23603 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23605 clearSelections : function(suppressEvent){
23606 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23607 this.cmp.elements = this.selections;
23608 this.cmp.removeClass(this.selectedClass);
23609 this.selections = [];
23610 if(!suppressEvent){
23611 this.fireEvent("selectionchange", this, this.selections);
23617 * Returns true if the passed node is selected
23618 * @param {HTMLElement/Number} node The node or node index
23619 * @return {Boolean}
23621 isSelected : function(node){
23622 var s = this.selections;
23626 node = this.getNode(node);
23627 return s.indexOf(node) !== -1;
23632 * @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
23633 * @param {Boolean} keepExisting (optional) true to keep existing selections
23634 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23636 select : function(nodeInfo, keepExisting, suppressEvent){
23637 if(nodeInfo instanceof Array){
23639 this.clearSelections(true);
23641 for(var i = 0, len = nodeInfo.length; i < len; i++){
23642 this.select(nodeInfo[i], true, true);
23645 var node = this.getNode(nodeInfo);
23646 if(node && !this.isSelected(node)){
23648 this.clearSelections(true);
23650 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23651 Roo.fly(node).addClass(this.selectedClass);
23652 this.selections.push(node);
23653 if(!suppressEvent){
23654 this.fireEvent("selectionchange", this, this.selections);
23662 * Gets a template node.
23663 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23664 * @return {HTMLElement} The node or null if it wasn't found
23666 getNode : function(nodeInfo){
23667 if(typeof nodeInfo == "string"){
23668 return document.getElementById(nodeInfo);
23669 }else if(typeof nodeInfo == "number"){
23670 return this.nodes[nodeInfo];
23676 * Gets a range template nodes.
23677 * @param {Number} startIndex
23678 * @param {Number} endIndex
23679 * @return {Array} An array of nodes
23681 getNodes : function(start, end){
23682 var ns = this.nodes;
23683 start = start || 0;
23684 end = typeof end == "undefined" ? ns.length - 1 : end;
23687 for(var i = start; i <= end; i++){
23691 for(var i = start; i >= end; i--){
23699 * Finds the index of the passed node
23700 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23701 * @return {Number} The index of the node or -1
23703 indexOf : function(node){
23704 node = this.getNode(node);
23705 if(typeof node.nodeIndex == "number"){
23706 return node.nodeIndex;
23708 var ns = this.nodes;
23709 for(var i = 0, len = ns.length; i < len; i++){
23719 * Ext JS Library 1.1.1
23720 * Copyright(c) 2006-2007, Ext JS, LLC.
23722 * Originally Released Under LGPL - original licence link has changed is not relivant.
23725 * <script type="text/javascript">
23729 * @class Roo.JsonView
23730 * @extends Roo.View
23731 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23733 var view = new Roo.JsonView({
23734 container: "my-element",
23735 template: '<div id="{id}">{foo} - {bar}</div>', // auto create template
23740 // listen for node click?
23741 view.on("click", function(vw, index, node, e){
23742 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23745 // direct load of JSON data
23746 view.load("foobar.php");
23748 // Example from my blog list
23749 var tpl = new Roo.Template(
23750 '<div class="entry">' +
23751 '<a class="entry-title" href="{link}">{title}</a>' +
23752 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23753 "</div><hr />"
23756 var moreView = new Roo.JsonView({
23757 container : "entry-list",
23761 moreView.on("beforerender", this.sortEntries, this);
23763 url: "/blog/get-posts.php",
23764 params: "allposts=true",
23765 text: "Loading Blog Entries..."
23769 * Note: old code is supported with arguments : (container, template, config)
23773 * Create a new JsonView
23775 * @param {Object} config The config object
23778 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
23781 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
23783 var um = this.el.getUpdateManager();
23784 um.setRenderer(this);
23785 um.on("update", this.onLoad, this);
23786 um.on("failure", this.onLoadException, this);
23789 * @event beforerender
23790 * Fires before rendering of the downloaded JSON data.
23791 * @param {Roo.JsonView} this
23792 * @param {Object} data The JSON data loaded
23796 * Fires when data is loaded.
23797 * @param {Roo.JsonView} this
23798 * @param {Object} data The JSON data loaded
23799 * @param {Object} response The raw Connect response object
23802 * @event loadexception
23803 * Fires when loading fails.
23804 * @param {Roo.JsonView} this
23805 * @param {Object} response The raw Connect response object
23808 'beforerender' : true,
23810 'loadexception' : true
23813 Roo.extend(Roo.JsonView, Roo.View, {
23815 * @type {String} The root property in the loaded JSON object that contains the data
23820 * Refreshes the view.
23822 refresh : function(){
23823 this.clearSelections();
23824 this.el.update("");
23826 var o = this.jsonData;
23827 if(o && o.length > 0){
23828 for(var i = 0, len = o.length; i < len; i++){
23829 var data = this.prepareData(o[i], i, o);
23830 html[html.length] = this.tpl.apply(data);
23833 html.push(this.emptyText);
23835 this.el.update(html.join(""));
23836 this.nodes = this.el.dom.childNodes;
23837 this.updateIndexes(0);
23841 * 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.
23842 * @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:
23845 url: "your-url.php",
23846 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
23847 callback: yourFunction,
23848 scope: yourObject, //(optional scope)
23851 text: "Loading...",
23856 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
23857 * 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.
23858 * @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}
23859 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
23860 * @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.
23863 var um = this.el.getUpdateManager();
23864 um.update.apply(um, arguments);
23867 render : function(el, response){
23868 this.clearSelections();
23869 this.el.update("");
23872 o = Roo.util.JSON.decode(response.responseText);
23875 o = /** eval:var:o */ eval("o." + this.jsonRoot);
23880 * The current JSON data or null
23883 this.beforeRender();
23888 * Get the number of records in the current JSON dataset
23891 getCount : function(){
23892 return this.jsonData ? this.jsonData.length : 0;
23896 * Returns the JSON object for the specified node(s)
23897 * @param {HTMLElement/Array} node The node or an array of nodes
23898 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
23899 * you get the JSON object for the node
23901 getNodeData : function(node){
23902 if(node instanceof Array){
23904 for(var i = 0, len = node.length; i < len; i++){
23905 data.push(this.getNodeData(node[i]));
23909 return this.jsonData[this.indexOf(node)] || null;
23912 beforeRender : function(){
23913 this.snapshot = this.jsonData;
23915 this.sort.apply(this, this.sortInfo);
23917 this.fireEvent("beforerender", this, this.jsonData);
23920 onLoad : function(el, o){
23921 this.fireEvent("load", this, this.jsonData, o);
23924 onLoadException : function(el, o){
23925 this.fireEvent("loadexception", this, o);
23929 * Filter the data by a specific property.
23930 * @param {String} property A property on your JSON objects
23931 * @param {String/RegExp} value Either string that the property values
23932 * should start with, or a RegExp to test against the property
23934 filter : function(property, value){
23937 var ss = this.snapshot;
23938 if(typeof value == "string"){
23939 var vlen = value.length;
23941 this.clearFilter();
23944 value = value.toLowerCase();
23945 for(var i = 0, len = ss.length; i < len; i++){
23947 if(o[property].substr(0, vlen).toLowerCase() == value){
23951 } else if(value.exec){ // regex?
23952 for(var i = 0, len = ss.length; i < len; i++){
23954 if(value.test(o[property])){
23961 this.jsonData = data;
23967 * Filter by a function. The passed function will be called with each
23968 * object in the current dataset. If the function returns true the value is kept,
23969 * otherwise it is filtered.
23970 * @param {Function} fn
23971 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
23973 filterBy : function(fn, scope){
23976 var ss = this.snapshot;
23977 for(var i = 0, len = ss.length; i < len; i++){
23979 if(fn.call(scope || this, o)){
23983 this.jsonData = data;
23989 * Clears the current filter.
23991 clearFilter : function(){
23992 if(this.snapshot && this.jsonData != this.snapshot){
23993 this.jsonData = this.snapshot;
24000 * Sorts the data for this view and refreshes it.
24001 * @param {String} property A property on your JSON objects to sort on
24002 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24003 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24005 sort : function(property, dir, sortType){
24006 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24009 var dsc = dir && dir.toLowerCase() == "desc";
24010 var f = function(o1, o2){
24011 var v1 = sortType ? sortType(o1[p]) : o1[p];
24012 var v2 = sortType ? sortType(o2[p]) : o2[p];
24015 return dsc ? +1 : -1;
24016 } else if(v1 > v2){
24017 return dsc ? -1 : +1;
24022 this.jsonData.sort(f);
24024 if(this.jsonData != this.snapshot){
24025 this.snapshot.sort(f);
24031 * Ext JS Library 1.1.1
24032 * Copyright(c) 2006-2007, Ext JS, LLC.
24034 * Originally Released Under LGPL - original licence link has changed is not relivant.
24037 * <script type="text/javascript">
24042 * @class Roo.ColorPalette
24043 * @extends Roo.Component
24044 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24045 * Here's an example of typical usage:
24047 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24048 cp.render('my-div');
24050 cp.on('select', function(palette, selColor){
24051 // do something with selColor
24055 * Create a new ColorPalette
24056 * @param {Object} config The config object
24058 Roo.ColorPalette = function(config){
24059 Roo.ColorPalette.superclass.constructor.call(this, config);
24063 * Fires when a color is selected
24064 * @param {ColorPalette} this
24065 * @param {String} color The 6-digit color hex code (without the # symbol)
24071 this.on("select", this.handler, this.scope, true);
24074 Roo.extend(Roo.ColorPalette, Roo.Component, {
24076 * @cfg {String} itemCls
24077 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24079 itemCls : "x-color-palette",
24081 * @cfg {String} value
24082 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24083 * the hex codes are case-sensitive.
24086 clickEvent:'click',
24088 ctype: "Roo.ColorPalette",
24091 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24093 allowReselect : false,
24096 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24097 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24098 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24099 * of colors with the width setting until the box is symmetrical.</p>
24100 * <p>You can override individual colors if needed:</p>
24102 var cp = new Roo.ColorPalette();
24103 cp.colors[0] = "FF0000"; // change the first box to red
24106 Or you can provide a custom array of your own for complete control:
24108 var cp = new Roo.ColorPalette();
24109 cp.colors = ["000000", "993300", "333300"];
24114 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24115 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24116 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24117 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24118 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24122 onRender : function(container, position){
24123 var t = new Roo.MasterTemplate(
24124 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24126 var c = this.colors;
24127 for(var i = 0, len = c.length; i < len; i++){
24130 var el = document.createElement("div");
24131 el.className = this.itemCls;
24133 container.dom.insertBefore(el, position);
24134 this.el = Roo.get(el);
24135 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24136 if(this.clickEvent != 'click'){
24137 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24142 afterRender : function(){
24143 Roo.ColorPalette.superclass.afterRender.call(this);
24145 var s = this.value;
24152 handleClick : function(e, t){
24153 e.preventDefault();
24154 if(!this.disabled){
24155 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24156 this.select(c.toUpperCase());
24161 * Selects the specified color in the palette (fires the select event)
24162 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24164 select : function(color){
24165 color = color.replace("#", "");
24166 if(color != this.value || this.allowReselect){
24169 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24171 el.child("a.color-"+color).addClass("x-color-palette-sel");
24172 this.value = color;
24173 this.fireEvent("select", this, color);
24178 * Ext JS Library 1.1.1
24179 * Copyright(c) 2006-2007, Ext JS, LLC.
24181 * Originally Released Under LGPL - original licence link has changed is not relivant.
24184 * <script type="text/javascript">
24188 * @class Roo.DatePicker
24189 * @extends Roo.Component
24190 * Simple date picker class.
24192 * Create a new DatePicker
24193 * @param {Object} config The config object
24195 Roo.DatePicker = function(config){
24196 Roo.DatePicker.superclass.constructor.call(this, config);
24198 this.value = config && config.value ?
24199 config.value.clearTime() : new Date().clearTime();
24204 * Fires when a date is selected
24205 * @param {DatePicker} this
24206 * @param {Date} date The selected date
24212 this.on("select", this.handler, this.scope || this);
24214 // build the disabledDatesRE
24215 if(!this.disabledDatesRE && this.disabledDates){
24216 var dd = this.disabledDates;
24218 for(var i = 0; i < dd.length; i++){
24220 if(i != dd.length-1) re += "|";
24222 this.disabledDatesRE = new RegExp(re + ")");
24226 Roo.extend(Roo.DatePicker, Roo.Component, {
24228 * @cfg {String} todayText
24229 * The text to display on the button that selects the current date (defaults to "Today")
24231 todayText : "Today",
24233 * @cfg {String} okText
24234 * The text to display on the ok button
24236 okText : " OK ", //   to give the user extra clicking room
24238 * @cfg {String} cancelText
24239 * The text to display on the cancel button
24241 cancelText : "Cancel",
24243 * @cfg {String} todayTip
24244 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24246 todayTip : "{0} (Spacebar)",
24248 * @cfg {Date} minDate
24249 * Minimum allowable date (JavaScript date object, defaults to null)
24253 * @cfg {Date} maxDate
24254 * Maximum allowable date (JavaScript date object, defaults to null)
24258 * @cfg {String} minText
24259 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24261 minText : "This date is before the minimum date",
24263 * @cfg {String} maxText
24264 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24266 maxText : "This date is after the maximum date",
24268 * @cfg {String} format
24269 * The default date format string which can be overriden for localization support. The format must be
24270 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24274 * @cfg {Array} disabledDays
24275 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24277 disabledDays : null,
24279 * @cfg {String} disabledDaysText
24280 * The tooltip to display when the date falls on a disabled day (defaults to "")
24282 disabledDaysText : "",
24284 * @cfg {RegExp} disabledDatesRE
24285 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24287 disabledDatesRE : null,
24289 * @cfg {String} disabledDatesText
24290 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24292 disabledDatesText : "",
24294 * @cfg {Boolean} constrainToViewport
24295 * True to constrain the date picker to the viewport (defaults to true)
24297 constrainToViewport : true,
24299 * @cfg {Array} monthNames
24300 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24302 monthNames : Date.monthNames,
24304 * @cfg {Array} dayNames
24305 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24307 dayNames : Date.dayNames,
24309 * @cfg {String} nextText
24310 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24312 nextText: 'Next Month (Control+Right)',
24314 * @cfg {String} prevText
24315 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24317 prevText: 'Previous Month (Control+Left)',
24319 * @cfg {String} monthYearText
24320 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24322 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24324 * @cfg {Number} startDay
24325 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24329 * @cfg {Bool} showClear
24330 * Show a clear button (usefull for date form elements that can be blank.)
24336 * Sets the value of the date field
24337 * @param {Date} value The date to set
24339 setValue : function(value){
24340 var old = this.value;
24341 this.value = value.clearTime(true);
24343 this.update(this.value);
24348 * Gets the current selected value of the date field
24349 * @return {Date} The selected date
24351 getValue : function(){
24356 focus : function(){
24358 this.update(this.activeDate);
24363 onRender : function(container, position){
24365 '<table cellspacing="0">',
24366 '<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>',
24367 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24368 var dn = this.dayNames;
24369 for(var i = 0; i < 7; i++){
24370 var d = this.startDay+i;
24374 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24376 m[m.length] = "</tr></thead><tbody><tr>";
24377 for(var i = 0; i < 42; i++) {
24378 if(i % 7 == 0 && i != 0){
24379 m[m.length] = "</tr><tr>";
24381 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24383 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24384 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24386 var el = document.createElement("div");
24387 el.className = "x-date-picker";
24388 el.innerHTML = m.join("");
24390 container.dom.insertBefore(el, position);
24392 this.el = Roo.get(el);
24393 this.eventEl = Roo.get(el.firstChild);
24395 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24396 handler: this.showPrevMonth,
24398 preventDefault:true,
24402 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24403 handler: this.showNextMonth,
24405 preventDefault:true,
24409 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24411 this.monthPicker = this.el.down('div.x-date-mp');
24412 this.monthPicker.enableDisplayMode('block');
24414 var kn = new Roo.KeyNav(this.eventEl, {
24415 "left" : function(e){
24417 this.showPrevMonth() :
24418 this.update(this.activeDate.add("d", -1));
24421 "right" : function(e){
24423 this.showNextMonth() :
24424 this.update(this.activeDate.add("d", 1));
24427 "up" : function(e){
24429 this.showNextYear() :
24430 this.update(this.activeDate.add("d", -7));
24433 "down" : function(e){
24435 this.showPrevYear() :
24436 this.update(this.activeDate.add("d", 7));
24439 "pageUp" : function(e){
24440 this.showNextMonth();
24443 "pageDown" : function(e){
24444 this.showPrevMonth();
24447 "enter" : function(e){
24448 e.stopPropagation();
24455 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24457 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24459 this.el.unselectable();
24461 this.cells = this.el.select("table.x-date-inner tbody td");
24462 this.textNodes = this.el.query("table.x-date-inner tbody span");
24464 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24466 tooltip: this.monthYearText
24469 this.mbtn.on('click', this.showMonthPicker, this);
24470 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24473 var today = (new Date()).dateFormat(this.format);
24475 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24477 text: String.format(this.todayText, today),
24478 tooltip: String.format(this.todayTip, today),
24479 handler: this.selectToday,
24483 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24486 if (this.showClear) {
24488 baseTb.add( new Roo.Toolbar.Fill());
24491 cls: 'x-btn-icon x-btn-clear',
24492 handler: function() {
24494 this.fireEvent("select", this, '');
24504 this.update(this.value);
24507 createMonthPicker : function(){
24508 if(!this.monthPicker.dom.firstChild){
24509 var buf = ['<table border="0" cellspacing="0">'];
24510 for(var i = 0; i < 6; i++){
24512 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24513 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24515 '<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>' :
24516 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24520 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24522 '</button><button type="button" class="x-date-mp-cancel">',
24524 '</button></td></tr>',
24527 this.monthPicker.update(buf.join(''));
24528 this.monthPicker.on('click', this.onMonthClick, this);
24529 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24531 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24532 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24534 this.mpMonths.each(function(m, a, i){
24537 m.dom.xmonth = 5 + Math.round(i * .5);
24539 m.dom.xmonth = Math.round((i-1) * .5);
24545 showMonthPicker : function(){
24546 this.createMonthPicker();
24547 var size = this.el.getSize();
24548 this.monthPicker.setSize(size);
24549 this.monthPicker.child('table').setSize(size);
24551 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24552 this.updateMPMonth(this.mpSelMonth);
24553 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24554 this.updateMPYear(this.mpSelYear);
24556 this.monthPicker.slideIn('t', {duration:.2});
24559 updateMPYear : function(y){
24561 var ys = this.mpYears.elements;
24562 for(var i = 1; i <= 10; i++){
24563 var td = ys[i-1], y2;
24565 y2 = y + Math.round(i * .5);
24566 td.firstChild.innerHTML = y2;
24569 y2 = y - (5-Math.round(i * .5));
24570 td.firstChild.innerHTML = y2;
24573 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24577 updateMPMonth : function(sm){
24578 this.mpMonths.each(function(m, a, i){
24579 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24583 selectMPMonth: function(m){
24587 onMonthClick : function(e, t){
24589 var el = new Roo.Element(t), pn;
24590 if(el.is('button.x-date-mp-cancel')){
24591 this.hideMonthPicker();
24593 else if(el.is('button.x-date-mp-ok')){
24594 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24595 this.hideMonthPicker();
24597 else if(pn = el.up('td.x-date-mp-month', 2)){
24598 this.mpMonths.removeClass('x-date-mp-sel');
24599 pn.addClass('x-date-mp-sel');
24600 this.mpSelMonth = pn.dom.xmonth;
24602 else if(pn = el.up('td.x-date-mp-year', 2)){
24603 this.mpYears.removeClass('x-date-mp-sel');
24604 pn.addClass('x-date-mp-sel');
24605 this.mpSelYear = pn.dom.xyear;
24607 else if(el.is('a.x-date-mp-prev')){
24608 this.updateMPYear(this.mpyear-10);
24610 else if(el.is('a.x-date-mp-next')){
24611 this.updateMPYear(this.mpyear+10);
24615 onMonthDblClick : function(e, t){
24617 var el = new Roo.Element(t), pn;
24618 if(pn = el.up('td.x-date-mp-month', 2)){
24619 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24620 this.hideMonthPicker();
24622 else if(pn = el.up('td.x-date-mp-year', 2)){
24623 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24624 this.hideMonthPicker();
24628 hideMonthPicker : function(disableAnim){
24629 if(this.monthPicker){
24630 if(disableAnim === true){
24631 this.monthPicker.hide();
24633 this.monthPicker.slideOut('t', {duration:.2});
24639 showPrevMonth : function(e){
24640 this.update(this.activeDate.add("mo", -1));
24644 showNextMonth : function(e){
24645 this.update(this.activeDate.add("mo", 1));
24649 showPrevYear : function(){
24650 this.update(this.activeDate.add("y", -1));
24654 showNextYear : function(){
24655 this.update(this.activeDate.add("y", 1));
24659 handleMouseWheel : function(e){
24660 var delta = e.getWheelDelta();
24662 this.showPrevMonth();
24664 } else if(delta < 0){
24665 this.showNextMonth();
24671 handleDateClick : function(e, t){
24673 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24674 this.setValue(new Date(t.dateValue));
24675 this.fireEvent("select", this, this.value);
24680 selectToday : function(){
24681 this.setValue(new Date().clearTime());
24682 this.fireEvent("select", this, this.value);
24686 update : function(date){
24687 var vd = this.activeDate;
24688 this.activeDate = date;
24690 var t = date.getTime();
24691 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24692 this.cells.removeClass("x-date-selected");
24693 this.cells.each(function(c){
24694 if(c.dom.firstChild.dateValue == t){
24695 c.addClass("x-date-selected");
24696 setTimeout(function(){
24697 try{c.dom.firstChild.focus();}catch(e){}
24705 var days = date.getDaysInMonth();
24706 var firstOfMonth = date.getFirstDateOfMonth();
24707 var startingPos = firstOfMonth.getDay()-this.startDay;
24709 if(startingPos <= this.startDay){
24713 var pm = date.add("mo", -1);
24714 var prevStart = pm.getDaysInMonth()-startingPos;
24716 var cells = this.cells.elements;
24717 var textEls = this.textNodes;
24718 days += startingPos;
24720 // convert everything to numbers so it's fast
24721 var day = 86400000;
24722 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24723 var today = new Date().clearTime().getTime();
24724 var sel = date.clearTime().getTime();
24725 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24726 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24727 var ddMatch = this.disabledDatesRE;
24728 var ddText = this.disabledDatesText;
24729 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24730 var ddaysText = this.disabledDaysText;
24731 var format = this.format;
24733 var setCellClass = function(cal, cell){
24735 var t = d.getTime();
24736 cell.firstChild.dateValue = t;
24738 cell.className += " x-date-today";
24739 cell.title = cal.todayText;
24742 cell.className += " x-date-selected";
24743 setTimeout(function(){
24744 try{cell.firstChild.focus();}catch(e){}
24749 cell.className = " x-date-disabled";
24750 cell.title = cal.minText;
24754 cell.className = " x-date-disabled";
24755 cell.title = cal.maxText;
24759 if(ddays.indexOf(d.getDay()) != -1){
24760 cell.title = ddaysText;
24761 cell.className = " x-date-disabled";
24764 if(ddMatch && format){
24765 var fvalue = d.dateFormat(format);
24766 if(ddMatch.test(fvalue)){
24767 cell.title = ddText.replace("%0", fvalue);
24768 cell.className = " x-date-disabled";
24774 for(; i < startingPos; i++) {
24775 textEls[i].innerHTML = (++prevStart);
24776 d.setDate(d.getDate()+1);
24777 cells[i].className = "x-date-prevday";
24778 setCellClass(this, cells[i]);
24780 for(; i < days; i++){
24781 intDay = i - startingPos + 1;
24782 textEls[i].innerHTML = (intDay);
24783 d.setDate(d.getDate()+1);
24784 cells[i].className = "x-date-active";
24785 setCellClass(this, cells[i]);
24788 for(; i < 42; i++) {
24789 textEls[i].innerHTML = (++extraDays);
24790 d.setDate(d.getDate()+1);
24791 cells[i].className = "x-date-nextday";
24792 setCellClass(this, cells[i]);
24795 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
24797 if(!this.internalRender){
24798 var main = this.el.dom.firstChild;
24799 var w = main.offsetWidth;
24800 this.el.setWidth(w + this.el.getBorderWidth("lr"));
24801 Roo.fly(main).setWidth(w);
24802 this.internalRender = true;
24803 // opera does not respect the auto grow header center column
24804 // then, after it gets a width opera refuses to recalculate
24805 // without a second pass
24806 if(Roo.isOpera && !this.secondPass){
24807 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
24808 this.secondPass = true;
24809 this.update.defer(10, this, [date]);
24815 * Ext JS Library 1.1.1
24816 * Copyright(c) 2006-2007, Ext JS, LLC.
24818 * Originally Released Under LGPL - original licence link has changed is not relivant.
24821 * <script type="text/javascript">
24824 * @class Roo.TabPanel
24825 * @extends Roo.util.Observable
24826 * A lightweight tab container.
24830 // basic tabs 1, built from existing content
24831 var tabs = new Roo.TabPanel("tabs1");
24832 tabs.addTab("script", "View Script");
24833 tabs.addTab("markup", "View Markup");
24834 tabs.activate("script");
24836 // more advanced tabs, built from javascript
24837 var jtabs = new Roo.TabPanel("jtabs");
24838 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
24840 // set up the UpdateManager
24841 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
24842 var updater = tab2.getUpdateManager();
24843 updater.setDefaultUrl("ajax1.htm");
24844 tab2.on('activate', updater.refresh, updater, true);
24846 // Use setUrl for Ajax loading
24847 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
24848 tab3.setUrl("ajax2.htm", null, true);
24851 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
24854 jtabs.activate("jtabs-1");
24857 * Create a new TabPanel.
24858 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
24859 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
24861 Roo.TabPanel = function(container, config){
24863 * The container element for this TabPanel.
24864 * @type Roo.Element
24866 this.el = Roo.get(container, true);
24868 if(typeof config == "boolean"){
24869 this.tabPosition = config ? "bottom" : "top";
24871 Roo.apply(this, config);
24874 if(this.tabPosition == "bottom"){
24875 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24876 this.el.addClass("x-tabs-bottom");
24878 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
24879 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
24880 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
24882 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
24884 if(this.tabPosition != "bottom"){
24885 /** The body element that contains {@link Roo.TabPanelItem} bodies.
24886 * @type Roo.Element
24888 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24889 this.el.addClass("x-tabs-top");
24893 this.bodyEl.setStyle("position", "relative");
24895 this.active = null;
24896 this.activateDelegate = this.activate.createDelegate(this);
24901 * Fires when the active tab changes
24902 * @param {Roo.TabPanel} this
24903 * @param {Roo.TabPanelItem} activePanel The new active tab
24907 * @event beforetabchange
24908 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
24909 * @param {Roo.TabPanel} this
24910 * @param {Object} e Set cancel to true on this object to cancel the tab change
24911 * @param {Roo.TabPanelItem} tab The tab being changed to
24913 "beforetabchange" : true
24916 Roo.EventManager.onWindowResize(this.onResize, this);
24917 this.cpad = this.el.getPadding("lr");
24918 this.hiddenCount = 0;
24920 Roo.TabPanel.superclass.constructor.call(this);
24923 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
24925 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
24927 tabPosition : "top",
24929 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
24931 currentTabWidth : 0,
24933 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
24937 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
24941 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
24943 preferredTabWidth : 175,
24945 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
24947 resizeTabs : false,
24949 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
24951 monitorResize : true,
24954 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
24955 * @param {String} id The id of the div to use <b>or create</b>
24956 * @param {String} text The text for the tab
24957 * @param {String} content (optional) Content to put in the TabPanelItem body
24958 * @param {Boolean} closable (optional) True to create a close icon on the tab
24959 * @return {Roo.TabPanelItem} The created TabPanelItem
24961 addTab : function(id, text, content, closable){
24962 var item = new Roo.TabPanelItem(this, id, text, closable);
24963 this.addTabItem(item);
24965 item.setContent(content);
24971 * Returns the {@link Roo.TabPanelItem} with the specified id/index
24972 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
24973 * @return {Roo.TabPanelItem}
24975 getTab : function(id){
24976 return this.items[id];
24980 * Hides the {@link Roo.TabPanelItem} with the specified id/index
24981 * @param {String/Number} id The id or index of the TabPanelItem to hide.
24983 hideTab : function(id){
24984 var t = this.items[id];
24987 this.hiddenCount++;
24988 this.autoSizeTabs();
24993 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
24994 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
24996 unhideTab : function(id){
24997 var t = this.items[id];
24999 t.setHidden(false);
25000 this.hiddenCount--;
25001 this.autoSizeTabs();
25006 * Adds an existing {@link Roo.TabPanelItem}.
25007 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25009 addTabItem : function(item){
25010 this.items[item.id] = item;
25011 this.items.push(item);
25012 if(this.resizeTabs){
25013 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25014 this.autoSizeTabs();
25021 * Removes a {@link Roo.TabPanelItem}.
25022 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25024 removeTab : function(id){
25025 var items = this.items;
25026 var tab = items[id];
25028 var index = items.indexOf(tab);
25029 if(this.active == tab && items.length > 1){
25030 var newTab = this.getNextAvailable(index);
25031 if(newTab)newTab.activate();
25033 this.stripEl.dom.removeChild(tab.pnode.dom);
25034 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25035 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25037 items.splice(index, 1);
25038 delete this.items[tab.id];
25039 tab.fireEvent("close", tab);
25040 tab.purgeListeners();
25041 this.autoSizeTabs();
25044 getNextAvailable : function(start){
25045 var items = this.items;
25047 // look for a next tab that will slide over to
25048 // replace the one being removed
25049 while(index < items.length){
25050 var item = items[++index];
25051 if(item && !item.isHidden()){
25055 // if one isn't found select the previous tab (on the left)
25058 var item = items[--index];
25059 if(item && !item.isHidden()){
25067 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25068 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25070 disableTab : function(id){
25071 var tab = this.items[id];
25072 if(tab && this.active != tab){
25078 * Enables a {@link Roo.TabPanelItem} that is disabled.
25079 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25081 enableTab : function(id){
25082 var tab = this.items[id];
25087 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25088 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25089 * @return {Roo.TabPanelItem} The TabPanelItem.
25091 activate : function(id){
25092 var tab = this.items[id];
25096 if(tab == this.active || tab.disabled){
25100 this.fireEvent("beforetabchange", this, e, tab);
25101 if(e.cancel !== true && !tab.disabled){
25103 this.active.hide();
25105 this.active = this.items[id];
25106 this.active.show();
25107 this.fireEvent("tabchange", this, this.active);
25113 * Gets the active {@link Roo.TabPanelItem}.
25114 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25116 getActiveTab : function(){
25117 return this.active;
25121 * Updates the tab body element to fit the height of the container element
25122 * for overflow scrolling
25123 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25125 syncHeight : function(targetHeight){
25126 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25127 var bm = this.bodyEl.getMargins();
25128 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25129 this.bodyEl.setHeight(newHeight);
25133 onResize : function(){
25134 if(this.monitorResize){
25135 this.autoSizeTabs();
25140 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25142 beginUpdate : function(){
25143 this.updating = true;
25147 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25149 endUpdate : function(){
25150 this.updating = false;
25151 this.autoSizeTabs();
25155 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25157 autoSizeTabs : function(){
25158 var count = this.items.length;
25159 var vcount = count - this.hiddenCount;
25160 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25161 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25162 var availWidth = Math.floor(w / vcount);
25163 var b = this.stripBody;
25164 if(b.getWidth() > w){
25165 var tabs = this.items;
25166 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25167 if(availWidth < this.minTabWidth){
25168 /*if(!this.sleft){ // incomplete scrolling code
25169 this.createScrollButtons();
25172 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25175 if(this.currentTabWidth < this.preferredTabWidth){
25176 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25182 * Returns the number of tabs in this TabPanel.
25185 getCount : function(){
25186 return this.items.length;
25190 * Resizes all the tabs to the passed width
25191 * @param {Number} The new width
25193 setTabWidth : function(width){
25194 this.currentTabWidth = width;
25195 for(var i = 0, len = this.items.length; i < len; i++) {
25196 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25201 * Destroys this TabPanel
25202 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25204 destroy : function(removeEl){
25205 Roo.EventManager.removeResizeListener(this.onResize, this);
25206 for(var i = 0, len = this.items.length; i < len; i++){
25207 this.items[i].purgeListeners();
25209 if(removeEl === true){
25210 this.el.update("");
25217 * @class Roo.TabPanelItem
25218 * @extends Roo.util.Observable
25219 * Represents an individual item (tab plus body) in a TabPanel.
25220 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25221 * @param {String} id The id of this TabPanelItem
25222 * @param {String} text The text for the tab of this TabPanelItem
25223 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25225 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25227 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25228 * @type Roo.TabPanel
25230 this.tabPanel = tabPanel;
25232 * The id for this TabPanelItem
25237 this.disabled = false;
25241 this.loaded = false;
25242 this.closable = closable;
25245 * The body element for this TabPanelItem.
25246 * @type Roo.Element
25248 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25249 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25250 this.bodyEl.setStyle("display", "block");
25251 this.bodyEl.setStyle("zoom", "1");
25254 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25256 this.el = Roo.get(els.el, true);
25257 this.inner = Roo.get(els.inner, true);
25258 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25259 this.pnode = Roo.get(els.el.parentNode, true);
25260 this.el.on("mousedown", this.onTabMouseDown, this);
25261 this.el.on("click", this.onTabClick, this);
25264 var c = Roo.get(els.close, true);
25265 c.dom.title = this.closeText;
25266 c.addClassOnOver("close-over");
25267 c.on("click", this.closeClick, this);
25273 * Fires when this tab becomes the active tab.
25274 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25275 * @param {Roo.TabPanelItem} this
25279 * @event beforeclose
25280 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25281 * @param {Roo.TabPanelItem} this
25282 * @param {Object} e Set cancel to true on this object to cancel the close.
25284 "beforeclose": true,
25287 * Fires when this tab is closed.
25288 * @param {Roo.TabPanelItem} this
25292 * @event deactivate
25293 * Fires when this tab is no longer the active tab.
25294 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25295 * @param {Roo.TabPanelItem} this
25297 "deactivate" : true
25299 this.hidden = false;
25301 Roo.TabPanelItem.superclass.constructor.call(this);
25304 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25305 purgeListeners : function(){
25306 Roo.util.Observable.prototype.purgeListeners.call(this);
25307 this.el.removeAllListeners();
25310 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25313 this.pnode.addClass("on");
25316 this.tabPanel.stripWrap.repaint();
25318 this.fireEvent("activate", this.tabPanel, this);
25322 * Returns true if this tab is the active tab.
25323 * @return {Boolean}
25325 isActive : function(){
25326 return this.tabPanel.getActiveTab() == this;
25330 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25333 this.pnode.removeClass("on");
25335 this.fireEvent("deactivate", this.tabPanel, this);
25338 hideAction : function(){
25339 this.bodyEl.hide();
25340 this.bodyEl.setStyle("position", "absolute");
25341 this.bodyEl.setLeft("-20000px");
25342 this.bodyEl.setTop("-20000px");
25345 showAction : function(){
25346 this.bodyEl.setStyle("position", "relative");
25347 this.bodyEl.setTop("");
25348 this.bodyEl.setLeft("");
25349 this.bodyEl.show();
25353 * Set the tooltip for the tab.
25354 * @param {String} tooltip The tab's tooltip
25356 setTooltip : function(text){
25357 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25358 this.textEl.dom.qtip = text;
25359 this.textEl.dom.removeAttribute('title');
25361 this.textEl.dom.title = text;
25365 onTabClick : function(e){
25366 e.preventDefault();
25367 this.tabPanel.activate(this.id);
25370 onTabMouseDown : function(e){
25371 e.preventDefault();
25372 this.tabPanel.activate(this.id);
25375 getWidth : function(){
25376 return this.inner.getWidth();
25379 setWidth : function(width){
25380 var iwidth = width - this.pnode.getPadding("lr");
25381 this.inner.setWidth(iwidth);
25382 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25383 this.pnode.setWidth(width);
25387 * Show or hide the tab
25388 * @param {Boolean} hidden True to hide or false to show.
25390 setHidden : function(hidden){
25391 this.hidden = hidden;
25392 this.pnode.setStyle("display", hidden ? "none" : "");
25396 * Returns true if this tab is "hidden"
25397 * @return {Boolean}
25399 isHidden : function(){
25400 return this.hidden;
25404 * Returns the text for this tab
25407 getText : function(){
25411 autoSize : function(){
25412 //this.el.beginMeasure();
25413 this.textEl.setWidth(1);
25414 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25415 //this.el.endMeasure();
25419 * Sets the text for the tab (Note: this also sets the tooltip text)
25420 * @param {String} text The tab's text and tooltip
25422 setText : function(text){
25424 this.textEl.update(text);
25425 this.setTooltip(text);
25426 if(!this.tabPanel.resizeTabs){
25431 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25433 activate : function(){
25434 this.tabPanel.activate(this.id);
25438 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25440 disable : function(){
25441 if(this.tabPanel.active != this){
25442 this.disabled = true;
25443 this.pnode.addClass("disabled");
25448 * Enables this TabPanelItem if it was previously disabled.
25450 enable : function(){
25451 this.disabled = false;
25452 this.pnode.removeClass("disabled");
25456 * Sets the content for this TabPanelItem.
25457 * @param {String} content The content
25458 * @param {Boolean} loadScripts true to look for and load scripts
25460 setContent : function(content, loadScripts){
25461 this.bodyEl.update(content, loadScripts);
25465 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25466 * @return {Roo.UpdateManager} The UpdateManager
25468 getUpdateManager : function(){
25469 return this.bodyEl.getUpdateManager();
25473 * Set a URL to be used to load the content for this TabPanelItem.
25474 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25475 * @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)
25476 * @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)
25477 * @return {Roo.UpdateManager} The UpdateManager
25479 setUrl : function(url, params, loadOnce){
25480 if(this.refreshDelegate){
25481 this.un('activate', this.refreshDelegate);
25483 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25484 this.on("activate", this.refreshDelegate);
25485 return this.bodyEl.getUpdateManager();
25489 _handleRefresh : function(url, params, loadOnce){
25490 if(!loadOnce || !this.loaded){
25491 var updater = this.bodyEl.getUpdateManager();
25492 updater.update(url, params, this._setLoaded.createDelegate(this));
25497 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25498 * Will fail silently if the setUrl method has not been called.
25499 * This does not activate the panel, just updates its content.
25501 refresh : function(){
25502 if(this.refreshDelegate){
25503 this.loaded = false;
25504 this.refreshDelegate();
25509 _setLoaded : function(){
25510 this.loaded = true;
25514 closeClick : function(e){
25517 this.fireEvent("beforeclose", this, o);
25518 if(o.cancel !== true){
25519 this.tabPanel.removeTab(this.id);
25523 * The text displayed in the tooltip for the close icon.
25526 closeText : "Close this tab"
25530 Roo.TabPanel.prototype.createStrip = function(container){
25531 var strip = document.createElement("div");
25532 strip.className = "x-tabs-wrap";
25533 container.appendChild(strip);
25537 Roo.TabPanel.prototype.createStripList = function(strip){
25538 // div wrapper for retard IE
25539 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>';
25540 return strip.firstChild.firstChild.firstChild.firstChild;
25543 Roo.TabPanel.prototype.createBody = function(container){
25544 var body = document.createElement("div");
25545 Roo.id(body, "tab-body");
25546 Roo.fly(body).addClass("x-tabs-body");
25547 container.appendChild(body);
25551 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25552 var body = Roo.getDom(id);
25554 body = document.createElement("div");
25557 Roo.fly(body).addClass("x-tabs-item-body");
25558 bodyEl.insertBefore(body, bodyEl.firstChild);
25562 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25563 var td = document.createElement("td");
25564 stripEl.appendChild(td);
25566 td.className = "x-tabs-closable";
25567 if(!this.closeTpl){
25568 this.closeTpl = new Roo.Template(
25569 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25570 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25571 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25574 var el = this.closeTpl.overwrite(td, {"text": text});
25575 var close = el.getElementsByTagName("div")[0];
25576 var inner = el.getElementsByTagName("em")[0];
25577 return {"el": el, "close": close, "inner": inner};
25580 this.tabTpl = new Roo.Template(
25581 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25582 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25585 var el = this.tabTpl.overwrite(td, {"text": text});
25586 var inner = el.getElementsByTagName("em")[0];
25587 return {"el": el, "inner": inner};
25591 * Ext JS Library 1.1.1
25592 * Copyright(c) 2006-2007, Ext JS, LLC.
25594 * Originally Released Under LGPL - original licence link has changed is not relivant.
25597 * <script type="text/javascript">
25601 * @class Roo.Button
25602 * @extends Roo.util.Observable
25603 * Simple Button class
25604 * @cfg {String} text The button text
25605 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25606 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25607 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25608 * @cfg {Object} scope The scope of the handler
25609 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25610 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25611 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25612 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25613 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25614 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25615 applies if enableToggle = true)
25616 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25617 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25618 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25620 * Create a new button
25621 * @param {Object} config The config object
25623 Roo.Button = function(renderTo, config)
25627 renderTo = config.renderTo || false;
25630 Roo.apply(this, config);
25634 * Fires when this button is clicked
25635 * @param {Button} this
25636 * @param {EventObject} e The click event
25641 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25642 * @param {Button} this
25643 * @param {Boolean} pressed
25648 * Fires when the mouse hovers over the button
25649 * @param {Button} this
25650 * @param {Event} e The event object
25652 'mouseover' : true,
25655 * Fires when the mouse exits the button
25656 * @param {Button} this
25657 * @param {Event} e The event object
25662 * Fires when the button is rendered
25663 * @param {Button} this
25668 this.menu = Roo.menu.MenuMgr.get(this.menu);
25671 this.render(renderTo);
25674 Roo.util.Observable.call(this);
25677 Roo.extend(Roo.Button, Roo.util.Observable, {
25683 * Read-only. True if this button is hidden
25688 * Read-only. True if this button is disabled
25693 * Read-only. True if this button is pressed (only if enableToggle = true)
25699 * @cfg {Number} tabIndex
25700 * The DOM tabIndex for this button (defaults to undefined)
25702 tabIndex : undefined,
25705 * @cfg {Boolean} enableToggle
25706 * True to enable pressed/not pressed toggling (defaults to false)
25708 enableToggle: false,
25710 * @cfg {Mixed} menu
25711 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25715 * @cfg {String} menuAlign
25716 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25718 menuAlign : "tl-bl?",
25721 * @cfg {String} iconCls
25722 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25724 iconCls : undefined,
25726 * @cfg {String} type
25727 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25732 menuClassTarget: 'tr',
25735 * @cfg {String} clickEvent
25736 * The type of event to map to the button's event handler (defaults to 'click')
25738 clickEvent : 'click',
25741 * @cfg {Boolean} handleMouseEvents
25742 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25744 handleMouseEvents : true,
25747 * @cfg {String} tooltipType
25748 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
25750 tooltipType : 'qtip',
25753 * @cfg {String} cls
25754 * A CSS class to apply to the button's main element.
25758 * @cfg {Roo.Template} template (Optional)
25759 * An {@link Roo.Template} with which to create the Button's main element. This Template must
25760 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
25761 * require code modifications if required elements (e.g. a button) aren't present.
25765 render : function(renderTo){
25767 if(this.hideParent){
25768 this.parentEl = Roo.get(renderTo);
25770 if(!this.dhconfig){
25771 if(!this.template){
25772 if(!Roo.Button.buttonTemplate){
25773 // hideous table template
25774 Roo.Button.buttonTemplate = new Roo.Template(
25775 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
25776 '<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>',
25777 "</tr></tbody></table>");
25779 this.template = Roo.Button.buttonTemplate;
25781 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
25782 var btnEl = btn.child("button:first");
25783 btnEl.on('focus', this.onFocus, this);
25784 btnEl.on('blur', this.onBlur, this);
25786 btn.addClass(this.cls);
25789 btnEl.setStyle('background-image', 'url(' +this.icon +')');
25792 btnEl.addClass(this.iconCls);
25794 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
25797 if(this.tabIndex !== undefined){
25798 btnEl.dom.tabIndex = this.tabIndex;
25801 if(typeof this.tooltip == 'object'){
25802 Roo.QuickTips.tips(Roo.apply({
25806 btnEl.dom[this.tooltipType] = this.tooltip;
25810 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
25814 this.el.dom.id = this.el.id = this.id;
25817 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
25818 this.menu.on("show", this.onMenuShow, this);
25819 this.menu.on("hide", this.onMenuHide, this);
25821 btn.addClass("x-btn");
25822 if(Roo.isIE && !Roo.isIE7){
25823 this.autoWidth.defer(1, this);
25827 if(this.handleMouseEvents){
25828 btn.on("mouseover", this.onMouseOver, this);
25829 btn.on("mouseout", this.onMouseOut, this);
25830 btn.on("mousedown", this.onMouseDown, this);
25832 btn.on(this.clickEvent, this.onClick, this);
25833 //btn.on("mouseup", this.onMouseUp, this);
25840 Roo.ButtonToggleMgr.register(this);
25842 this.el.addClass("x-btn-pressed");
25845 var repeater = new Roo.util.ClickRepeater(btn,
25846 typeof this.repeat == "object" ? this.repeat : {}
25848 repeater.on("click", this.onClick, this);
25850 this.fireEvent('render', this);
25854 * Returns the button's underlying element
25855 * @return {Roo.Element} The element
25857 getEl : function(){
25862 * Destroys this Button and removes any listeners.
25864 destroy : function(){
25865 Roo.ButtonToggleMgr.unregister(this);
25866 this.el.removeAllListeners();
25867 this.purgeListeners();
25872 autoWidth : function(){
25874 this.el.setWidth("auto");
25875 if(Roo.isIE7 && Roo.isStrict){
25876 var ib = this.el.child('button');
25877 if(ib && ib.getWidth() > 20){
25879 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
25884 this.el.beginMeasure();
25886 if(this.el.getWidth() < this.minWidth){
25887 this.el.setWidth(this.minWidth);
25890 this.el.endMeasure();
25897 * Assigns this button's click handler
25898 * @param {Function} handler The function to call when the button is clicked
25899 * @param {Object} scope (optional) Scope for the function passed in
25901 setHandler : function(handler, scope){
25902 this.handler = handler;
25903 this.scope = scope;
25907 * Sets this button's text
25908 * @param {String} text The button text
25910 setText : function(text){
25913 this.el.child("td.x-btn-center button.x-btn-text").update(text);
25919 * Gets the text for this button
25920 * @return {String} The button text
25922 getText : function(){
25930 this.hidden = false;
25932 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
25940 this.hidden = true;
25942 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
25947 * Convenience function for boolean show/hide
25948 * @param {Boolean} visible True to show, false to hide
25950 setVisible: function(visible){
25959 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
25960 * @param {Boolean} state (optional) Force a particular state
25962 toggle : function(state){
25963 state = state === undefined ? !this.pressed : state;
25964 if(state != this.pressed){
25966 this.el.addClass("x-btn-pressed");
25967 this.pressed = true;
25968 this.fireEvent("toggle", this, true);
25970 this.el.removeClass("x-btn-pressed");
25971 this.pressed = false;
25972 this.fireEvent("toggle", this, false);
25974 if(this.toggleHandler){
25975 this.toggleHandler.call(this.scope || this, this, state);
25983 focus : function(){
25984 this.el.child('button:first').focus();
25988 * Disable this button
25990 disable : function(){
25992 this.el.addClass("x-btn-disabled");
25994 this.disabled = true;
25998 * Enable this button
26000 enable : function(){
26002 this.el.removeClass("x-btn-disabled");
26004 this.disabled = false;
26008 * Convenience function for boolean enable/disable
26009 * @param {Boolean} enabled True to enable, false to disable
26011 setDisabled : function(v){
26012 this[v !== true ? "enable" : "disable"]();
26016 onClick : function(e){
26018 e.preventDefault();
26023 if(!this.disabled){
26024 if(this.enableToggle){
26027 if(this.menu && !this.menu.isVisible()){
26028 this.menu.show(this.el, this.menuAlign);
26030 this.fireEvent("click", this, e);
26032 this.el.removeClass("x-btn-over");
26033 this.handler.call(this.scope || this, this, e);
26038 onMouseOver : function(e){
26039 if(!this.disabled){
26040 this.el.addClass("x-btn-over");
26041 this.fireEvent('mouseover', this, e);
26045 onMouseOut : function(e){
26046 if(!e.within(this.el, true)){
26047 this.el.removeClass("x-btn-over");
26048 this.fireEvent('mouseout', this, e);
26052 onFocus : function(e){
26053 if(!this.disabled){
26054 this.el.addClass("x-btn-focus");
26058 onBlur : function(e){
26059 this.el.removeClass("x-btn-focus");
26062 onMouseDown : function(e){
26063 if(!this.disabled && e.button == 0){
26064 this.el.addClass("x-btn-click");
26065 Roo.get(document).on('mouseup', this.onMouseUp, this);
26069 onMouseUp : function(e){
26071 this.el.removeClass("x-btn-click");
26072 Roo.get(document).un('mouseup', this.onMouseUp, this);
26076 onMenuShow : function(e){
26077 this.el.addClass("x-btn-menu-active");
26080 onMenuHide : function(e){
26081 this.el.removeClass("x-btn-menu-active");
26085 // Private utility class used by Button
26086 Roo.ButtonToggleMgr = function(){
26089 function toggleGroup(btn, state){
26091 var g = groups[btn.toggleGroup];
26092 for(var i = 0, l = g.length; i < l; i++){
26094 g[i].toggle(false);
26101 register : function(btn){
26102 if(!btn.toggleGroup){
26105 var g = groups[btn.toggleGroup];
26107 g = groups[btn.toggleGroup] = [];
26110 btn.on("toggle", toggleGroup);
26113 unregister : function(btn){
26114 if(!btn.toggleGroup){
26117 var g = groups[btn.toggleGroup];
26120 btn.un("toggle", toggleGroup);
26126 * Ext JS Library 1.1.1
26127 * Copyright(c) 2006-2007, Ext JS, LLC.
26129 * Originally Released Under LGPL - original licence link has changed is not relivant.
26132 * <script type="text/javascript">
26136 * @class Roo.SplitButton
26137 * @extends Roo.Button
26138 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26139 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26140 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26141 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26142 * @cfg {String} arrowTooltip The title attribute of the arrow
26144 * Create a new menu button
26145 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26146 * @param {Object} config The config object
26148 Roo.SplitButton = function(renderTo, config){
26149 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26151 * @event arrowclick
26152 * Fires when this button's arrow is clicked
26153 * @param {SplitButton} this
26154 * @param {EventObject} e The click event
26156 this.addEvents({"arrowclick":true});
26159 Roo.extend(Roo.SplitButton, Roo.Button, {
26160 render : function(renderTo){
26161 // this is one sweet looking template!
26162 var tpl = new Roo.Template(
26163 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26164 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26165 '<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>',
26166 "</tbody></table></td><td>",
26167 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26168 '<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>',
26169 "</tbody></table></td></tr></table>"
26171 var btn = tpl.append(renderTo, [this.text, this.type], true);
26172 var btnEl = btn.child("button");
26174 btn.addClass(this.cls);
26177 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26180 btnEl.addClass(this.iconCls);
26182 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26186 if(this.handleMouseEvents){
26187 btn.on("mouseover", this.onMouseOver, this);
26188 btn.on("mouseout", this.onMouseOut, this);
26189 btn.on("mousedown", this.onMouseDown, this);
26190 btn.on("mouseup", this.onMouseUp, this);
26192 btn.on(this.clickEvent, this.onClick, this);
26194 if(typeof this.tooltip == 'object'){
26195 Roo.QuickTips.tips(Roo.apply({
26199 btnEl.dom[this.tooltipType] = this.tooltip;
26202 if(this.arrowTooltip){
26203 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26212 this.el.addClass("x-btn-pressed");
26214 if(Roo.isIE && !Roo.isIE7){
26215 this.autoWidth.defer(1, this);
26220 this.menu.on("show", this.onMenuShow, this);
26221 this.menu.on("hide", this.onMenuHide, this);
26223 this.fireEvent('render', this);
26227 autoWidth : function(){
26229 var tbl = this.el.child("table:first");
26230 var tbl2 = this.el.child("table:last");
26231 this.el.setWidth("auto");
26232 tbl.setWidth("auto");
26233 if(Roo.isIE7 && Roo.isStrict){
26234 var ib = this.el.child('button:first');
26235 if(ib && ib.getWidth() > 20){
26237 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26242 this.el.beginMeasure();
26244 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26245 tbl.setWidth(this.minWidth-tbl2.getWidth());
26248 this.el.endMeasure();
26251 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26255 * Sets this button's click handler
26256 * @param {Function} handler The function to call when the button is clicked
26257 * @param {Object} scope (optional) Scope for the function passed above
26259 setHandler : function(handler, scope){
26260 this.handler = handler;
26261 this.scope = scope;
26265 * Sets this button's arrow click handler
26266 * @param {Function} handler The function to call when the arrow is clicked
26267 * @param {Object} scope (optional) Scope for the function passed above
26269 setArrowHandler : function(handler, scope){
26270 this.arrowHandler = handler;
26271 this.scope = scope;
26277 focus : function(){
26279 this.el.child("button:first").focus();
26284 onClick : function(e){
26285 e.preventDefault();
26286 if(!this.disabled){
26287 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26288 if(this.menu && !this.menu.isVisible()){
26289 this.menu.show(this.el, this.menuAlign);
26291 this.fireEvent("arrowclick", this, e);
26292 if(this.arrowHandler){
26293 this.arrowHandler.call(this.scope || this, this, e);
26296 this.fireEvent("click", this, e);
26298 this.handler.call(this.scope || this, this, e);
26304 onMouseDown : function(e){
26305 if(!this.disabled){
26306 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26310 onMouseUp : function(e){
26311 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26316 // backwards compat
26317 Roo.MenuButton = Roo.SplitButton;/*
26319 * Ext JS Library 1.1.1
26320 * Copyright(c) 2006-2007, Ext JS, LLC.
26322 * Originally Released Under LGPL - original licence link has changed is not relivant.
26325 * <script type="text/javascript">
26329 * @class Roo.Toolbar
26330 * Basic Toolbar class.
26332 * Creates a new Toolbar
26333 * @param {Object} config The config object
26335 Roo.Toolbar = function(container, buttons, config)
26337 /// old consturctor format still supported..
26338 if(container instanceof Array){ // omit the container for later rendering
26339 buttons = container;
26343 if (typeof(container) == 'object' && container.xtype) {
26344 config = container;
26345 container = config.container;
26346 buttons = config.buttons; // not really - use items!!
26349 if (config && config.items) {
26350 xitems = config.items;
26351 delete config.items;
26353 Roo.apply(this, config);
26354 this.buttons = buttons;
26357 this.render(container);
26359 Roo.each(xitems, function(b) {
26365 Roo.Toolbar.prototype = {
26367 * @cfg {Roo.data.Store} items
26368 * array of button configs or elements to add
26372 * @cfg {String/HTMLElement/Element} container
26373 * The id or element that will contain the toolbar
26376 render : function(ct){
26377 this.el = Roo.get(ct);
26379 this.el.addClass(this.cls);
26381 // using a table allows for vertical alignment
26382 // 100% width is needed by Safari...
26383 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26384 this.tr = this.el.child("tr", true);
26386 this.items = new Roo.util.MixedCollection(false, function(o){
26387 return o.id || ("item" + (++autoId));
26390 this.add.apply(this, this.buttons);
26391 delete this.buttons;
26396 * Adds element(s) to the toolbar -- this function takes a variable number of
26397 * arguments of mixed type and adds them to the toolbar.
26398 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26400 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26401 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26402 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26403 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26404 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26405 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26406 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26407 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26408 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26410 * @param {Mixed} arg2
26411 * @param {Mixed} etc.
26414 var a = arguments, l = a.length;
26415 for(var i = 0; i < l; i++){
26420 _add : function(el) {
26423 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26426 if (el.applyTo){ // some kind of form field
26427 return this.addField(el);
26429 if (el.render){ // some kind of Toolbar.Item
26430 return this.addItem(el);
26432 if (typeof el == "string"){ // string
26433 if(el == "separator" || el == "-"){
26434 return this.addSeparator();
26437 return this.addSpacer();
26440 return this.addFill();
26442 return this.addText(el);
26445 if(el.tagName){ // element
26446 return this.addElement(el);
26448 if(typeof el == "object"){ // must be button config?
26449 return this.addButton(el);
26451 // and now what?!?!
26457 * Add an Xtype element
26458 * @param {Object} xtype Xtype Object
26459 * @return {Object} created Object
26461 addxtype : function(e){
26462 return this.add(e);
26466 * Returns the Element for this toolbar.
26467 * @return {Roo.Element}
26469 getEl : function(){
26475 * @return {Roo.Toolbar.Item} The separator item
26477 addSeparator : function(){
26478 return this.addItem(new Roo.Toolbar.Separator());
26482 * Adds a spacer element
26483 * @return {Roo.Toolbar.Spacer} The spacer item
26485 addSpacer : function(){
26486 return this.addItem(new Roo.Toolbar.Spacer());
26490 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26491 * @return {Roo.Toolbar.Fill} The fill item
26493 addFill : function(){
26494 return this.addItem(new Roo.Toolbar.Fill());
26498 * Adds any standard HTML element to the toolbar
26499 * @param {String/HTMLElement/Element} el The element or id of the element to add
26500 * @return {Roo.Toolbar.Item} The element's item
26502 addElement : function(el){
26503 return this.addItem(new Roo.Toolbar.Item(el));
26506 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26507 * @type Roo.util.MixedCollection
26512 * Adds any Toolbar.Item or subclass
26513 * @param {Roo.Toolbar.Item} item
26514 * @return {Roo.Toolbar.Item} The item
26516 addItem : function(item){
26517 var td = this.nextBlock();
26519 this.items.add(item);
26524 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26525 * @param {Object/Array} config A button config or array of configs
26526 * @return {Roo.Toolbar.Button/Array}
26528 addButton : function(config){
26529 if(config instanceof Array){
26531 for(var i = 0, len = config.length; i < len; i++) {
26532 buttons.push(this.addButton(config[i]));
26537 if(!(config instanceof Roo.Toolbar.Button)){
26539 new Roo.Toolbar.SplitButton(config) :
26540 new Roo.Toolbar.Button(config);
26542 var td = this.nextBlock();
26549 * Adds text to the toolbar
26550 * @param {String} text The text to add
26551 * @return {Roo.Toolbar.Item} The element's item
26553 addText : function(text){
26554 return this.addItem(new Roo.Toolbar.TextItem(text));
26558 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26559 * @param {Number} index The index where the item is to be inserted
26560 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26561 * @return {Roo.Toolbar.Button/Item}
26563 insertButton : function(index, item){
26564 if(item instanceof Array){
26566 for(var i = 0, len = item.length; i < len; i++) {
26567 buttons.push(this.insertButton(index + i, item[i]));
26571 if (!(item instanceof Roo.Toolbar.Button)){
26572 item = new Roo.Toolbar.Button(item);
26574 var td = document.createElement("td");
26575 this.tr.insertBefore(td, this.tr.childNodes[index]);
26577 this.items.insert(index, item);
26582 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26583 * @param {Object} config
26584 * @return {Roo.Toolbar.Item} The element's item
26586 addDom : function(config, returnEl){
26587 var td = this.nextBlock();
26588 Roo.DomHelper.overwrite(td, config);
26589 var ti = new Roo.Toolbar.Item(td.firstChild);
26591 this.items.add(ti);
26596 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26597 * @type Roo.util.MixedCollection
26602 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26603 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26604 * @param {Roo.form.Field} field
26605 * @return {Roo.ToolbarItem}
26609 addField : function(field) {
26610 if (!this.fields) {
26612 this.fields = new Roo.util.MixedCollection(false, function(o){
26613 return o.id || ("item" + (++autoId));
26618 var td = this.nextBlock();
26620 var ti = new Roo.Toolbar.Item(td.firstChild);
26622 this.items.add(ti);
26623 this.fields.add(field);
26634 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26635 this.el.child('div').hide();
26643 this.el.child('div').show();
26647 nextBlock : function(){
26648 var td = document.createElement("td");
26649 this.tr.appendChild(td);
26654 destroy : function(){
26655 if(this.items){ // rendered?
26656 Roo.destroy.apply(Roo, this.items.items);
26658 if(this.fields){ // rendered?
26659 Roo.destroy.apply(Roo, this.fields.items);
26661 Roo.Element.uncache(this.el, this.tr);
26666 * @class Roo.Toolbar.Item
26667 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26669 * Creates a new Item
26670 * @param {HTMLElement} el
26672 Roo.Toolbar.Item = function(el){
26673 this.el = Roo.getDom(el);
26674 this.id = Roo.id(this.el);
26675 this.hidden = false;
26678 Roo.Toolbar.Item.prototype = {
26681 * Get this item's HTML Element
26682 * @return {HTMLElement}
26684 getEl : function(){
26689 render : function(td){
26691 td.appendChild(this.el);
26695 * Removes and destroys this item.
26697 destroy : function(){
26698 this.td.parentNode.removeChild(this.td);
26705 this.hidden = false;
26706 this.td.style.display = "";
26713 this.hidden = true;
26714 this.td.style.display = "none";
26718 * Convenience function for boolean show/hide.
26719 * @param {Boolean} visible true to show/false to hide
26721 setVisible: function(visible){
26730 * Try to focus this item.
26732 focus : function(){
26733 Roo.fly(this.el).focus();
26737 * Disables this item.
26739 disable : function(){
26740 Roo.fly(this.td).addClass("x-item-disabled");
26741 this.disabled = true;
26742 this.el.disabled = true;
26746 * Enables this item.
26748 enable : function(){
26749 Roo.fly(this.td).removeClass("x-item-disabled");
26750 this.disabled = false;
26751 this.el.disabled = false;
26757 * @class Roo.Toolbar.Separator
26758 * @extends Roo.Toolbar.Item
26759 * A simple toolbar separator class
26761 * Creates a new Separator
26763 Roo.Toolbar.Separator = function(){
26764 var s = document.createElement("span");
26765 s.className = "ytb-sep";
26766 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
26768 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
26769 enable:Roo.emptyFn,
26770 disable:Roo.emptyFn,
26775 * @class Roo.Toolbar.Spacer
26776 * @extends Roo.Toolbar.Item
26777 * A simple element that adds extra horizontal space to a toolbar.
26779 * Creates a new Spacer
26781 Roo.Toolbar.Spacer = function(){
26782 var s = document.createElement("div");
26783 s.className = "ytb-spacer";
26784 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
26786 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
26787 enable:Roo.emptyFn,
26788 disable:Roo.emptyFn,
26793 * @class Roo.Toolbar.Fill
26794 * @extends Roo.Toolbar.Spacer
26795 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
26797 * Creates a new Spacer
26799 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
26801 render : function(td){
26802 td.style.width = '100%';
26803 Roo.Toolbar.Fill.superclass.render.call(this, td);
26808 * @class Roo.Toolbar.TextItem
26809 * @extends Roo.Toolbar.Item
26810 * A simple class that renders text directly into a toolbar.
26812 * Creates a new TextItem
26813 * @param {String} text
26815 Roo.Toolbar.TextItem = function(text){
26816 if (typeof(text) == 'object') {
26819 var s = document.createElement("span");
26820 s.className = "ytb-text";
26821 s.innerHTML = text;
26822 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
26824 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
26825 enable:Roo.emptyFn,
26826 disable:Roo.emptyFn,
26831 * @class Roo.Toolbar.Button
26832 * @extends Roo.Button
26833 * A button that renders into a toolbar.
26835 * Creates a new Button
26836 * @param {Object} config A standard {@link Roo.Button} config object
26838 Roo.Toolbar.Button = function(config){
26839 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
26841 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
26842 render : function(td){
26844 Roo.Toolbar.Button.superclass.render.call(this, td);
26848 * Removes and destroys this button
26850 destroy : function(){
26851 Roo.Toolbar.Button.superclass.destroy.call(this);
26852 this.td.parentNode.removeChild(this.td);
26856 * Shows this button
26859 this.hidden = false;
26860 this.td.style.display = "";
26864 * Hides this button
26867 this.hidden = true;
26868 this.td.style.display = "none";
26872 * Disables this item
26874 disable : function(){
26875 Roo.fly(this.td).addClass("x-item-disabled");
26876 this.disabled = true;
26880 * Enables this item
26882 enable : function(){
26883 Roo.fly(this.td).removeClass("x-item-disabled");
26884 this.disabled = false;
26887 // backwards compat
26888 Roo.ToolbarButton = Roo.Toolbar.Button;
26891 * @class Roo.Toolbar.SplitButton
26892 * @extends Roo.SplitButton
26893 * A menu button that renders into a toolbar.
26895 * Creates a new SplitButton
26896 * @param {Object} config A standard {@link Roo.SplitButton} config object
26898 Roo.Toolbar.SplitButton = function(config){
26899 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
26901 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
26902 render : function(td){
26904 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
26908 * Removes and destroys this button
26910 destroy : function(){
26911 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
26912 this.td.parentNode.removeChild(this.td);
26916 * Shows this button
26919 this.hidden = false;
26920 this.td.style.display = "";
26924 * Hides this button
26927 this.hidden = true;
26928 this.td.style.display = "none";
26932 // backwards compat
26933 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
26935 * Ext JS Library 1.1.1
26936 * Copyright(c) 2006-2007, Ext JS, LLC.
26938 * Originally Released Under LGPL - original licence link has changed is not relivant.
26941 * <script type="text/javascript">
26945 * @class Roo.PagingToolbar
26946 * @extends Roo.Toolbar
26947 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26949 * Create a new PagingToolbar
26950 * @param {Object} config The config object
26952 Roo.PagingToolbar = function(el, ds, config)
26954 // old args format still supported... - xtype is prefered..
26955 if (typeof(el) == 'object' && el.xtype) {
26956 // created from xtype...
26958 ds = el.dataSource;
26959 el = config.container;
26963 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
26966 this.renderButtons(this.el);
26970 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
26972 * @cfg {Roo.data.Store} dataSource
26973 * The underlying data store providing the paged data
26976 * @cfg {String/HTMLElement/Element} container
26977 * container The id or element that will contain the toolbar
26980 * @cfg {Boolean} displayInfo
26981 * True to display the displayMsg (defaults to false)
26984 * @cfg {Number} pageSize
26985 * The number of records to display per page (defaults to 20)
26989 * @cfg {String} displayMsg
26990 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26992 displayMsg : 'Displaying {0} - {1} of {2}',
26994 * @cfg {String} emptyMsg
26995 * The message to display when no records are found (defaults to "No data to display")
26997 emptyMsg : 'No data to display',
26999 * Customizable piece of the default paging text (defaults to "Page")
27002 beforePageText : "Page",
27004 * Customizable piece of the default paging text (defaults to "of %0")
27007 afterPageText : "of {0}",
27009 * Customizable piece of the default paging text (defaults to "First Page")
27012 firstText : "First Page",
27014 * Customizable piece of the default paging text (defaults to "Previous Page")
27017 prevText : "Previous Page",
27019 * Customizable piece of the default paging text (defaults to "Next Page")
27022 nextText : "Next Page",
27024 * Customizable piece of the default paging text (defaults to "Last Page")
27027 lastText : "Last Page",
27029 * Customizable piece of the default paging text (defaults to "Refresh")
27032 refreshText : "Refresh",
27035 renderButtons : function(el){
27036 Roo.PagingToolbar.superclass.render.call(this, el);
27037 this.first = this.addButton({
27038 tooltip: this.firstText,
27039 cls: "x-btn-icon x-grid-page-first",
27041 handler: this.onClick.createDelegate(this, ["first"])
27043 this.prev = this.addButton({
27044 tooltip: this.prevText,
27045 cls: "x-btn-icon x-grid-page-prev",
27047 handler: this.onClick.createDelegate(this, ["prev"])
27049 this.addSeparator();
27050 this.add(this.beforePageText);
27051 this.field = Roo.get(this.addDom({
27056 cls: "x-grid-page-number"
27058 this.field.on("keydown", this.onPagingKeydown, this);
27059 this.field.on("focus", function(){this.dom.select();});
27060 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27061 this.field.setHeight(18);
27062 this.addSeparator();
27063 this.next = this.addButton({
27064 tooltip: this.nextText,
27065 cls: "x-btn-icon x-grid-page-next",
27067 handler: this.onClick.createDelegate(this, ["next"])
27069 this.last = this.addButton({
27070 tooltip: this.lastText,
27071 cls: "x-btn-icon x-grid-page-last",
27073 handler: this.onClick.createDelegate(this, ["last"])
27075 this.addSeparator();
27076 this.loading = this.addButton({
27077 tooltip: this.refreshText,
27078 cls: "x-btn-icon x-grid-loading",
27079 handler: this.onClick.createDelegate(this, ["refresh"])
27082 if(this.displayInfo){
27083 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27088 updateInfo : function(){
27089 if(this.displayEl){
27090 var count = this.ds.getCount();
27091 var msg = count == 0 ?
27095 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27097 this.displayEl.update(msg);
27102 onLoad : function(ds, r, o){
27103 this.cursor = o.params ? o.params.start : 0;
27104 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27106 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27107 this.field.dom.value = ap;
27108 this.first.setDisabled(ap == 1);
27109 this.prev.setDisabled(ap == 1);
27110 this.next.setDisabled(ap == ps);
27111 this.last.setDisabled(ap == ps);
27112 this.loading.enable();
27117 getPageData : function(){
27118 var total = this.ds.getTotalCount();
27121 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27122 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27127 onLoadError : function(){
27128 this.loading.enable();
27132 onPagingKeydown : function(e){
27133 var k = e.getKey();
27134 var d = this.getPageData();
27136 var v = this.field.dom.value, pageNum;
27137 if(!v || isNaN(pageNum = parseInt(v, 10))){
27138 this.field.dom.value = d.activePage;
27141 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27142 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27145 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))
27147 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27148 this.field.dom.value = pageNum;
27149 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27152 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27154 var v = this.field.dom.value, pageNum;
27155 var increment = (e.shiftKey) ? 10 : 1;
27156 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27158 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27159 this.field.dom.value = d.activePage;
27162 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27164 this.field.dom.value = parseInt(v, 10) + increment;
27165 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27166 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27173 beforeLoad : function(){
27175 this.loading.disable();
27180 onClick : function(which){
27184 ds.load({params:{start: 0, limit: this.pageSize}});
27187 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27190 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27193 var total = ds.getTotalCount();
27194 var extra = total % this.pageSize;
27195 var lastStart = extra ? (total - extra) : total-this.pageSize;
27196 ds.load({params:{start: lastStart, limit: this.pageSize}});
27199 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27205 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27206 * @param {Roo.data.Store} store The data store to unbind
27208 unbind : function(ds){
27209 ds.un("beforeload", this.beforeLoad, this);
27210 ds.un("load", this.onLoad, this);
27211 ds.un("loadexception", this.onLoadError, this);
27212 ds.un("remove", this.updateInfo, this);
27213 ds.un("add", this.updateInfo, this);
27214 this.ds = undefined;
27218 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27219 * @param {Roo.data.Store} store The data store to bind
27221 bind : function(ds){
27222 ds.on("beforeload", this.beforeLoad, this);
27223 ds.on("load", this.onLoad, this);
27224 ds.on("loadexception", this.onLoadError, this);
27225 ds.on("remove", this.updateInfo, this);
27226 ds.on("add", this.updateInfo, this);
27231 * Ext JS Library 1.1.1
27232 * Copyright(c) 2006-2007, Ext JS, LLC.
27234 * Originally Released Under LGPL - original licence link has changed is not relivant.
27237 * <script type="text/javascript">
27241 * @class Roo.Resizable
27242 * @extends Roo.util.Observable
27243 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27244 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27245 * 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
27246 * the element will be wrapped for you automatically.</p>
27247 * <p>Here is the list of valid resize handles:</p>
27250 ------ -------------------
27261 * <p>Here's an example showing the creation of a typical Resizable:</p>
27263 var resizer = new Roo.Resizable("element-id", {
27271 resizer.on("resize", myHandler);
27273 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27274 * resizer.east.setDisplayed(false);</p>
27275 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27276 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27277 * resize operation's new size (defaults to [0, 0])
27278 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27279 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27280 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27281 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27282 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27283 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27284 * @cfg {Number} width The width of the element in pixels (defaults to null)
27285 * @cfg {Number} height The height of the element in pixels (defaults to null)
27286 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27287 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27288 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27289 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27290 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27291 * in favor of the handles config option (defaults to false)
27292 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27293 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27294 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27295 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27296 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27297 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27298 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27299 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27300 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27301 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27302 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27304 * Create a new resizable component
27305 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27306 * @param {Object} config configuration options
27308 Roo.Resizable = function(el, config){
27309 this.el = Roo.get(el);
27311 if(config && config.wrap){
27312 config.resizeChild = this.el;
27313 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27314 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27315 this.el.setStyle("overflow", "hidden");
27316 this.el.setPositioning(config.resizeChild.getPositioning());
27317 config.resizeChild.clearPositioning();
27318 if(!config.width || !config.height){
27319 var csize = config.resizeChild.getSize();
27320 this.el.setSize(csize.width, csize.height);
27322 if(config.pinned && !config.adjustments){
27323 config.adjustments = "auto";
27327 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27328 this.proxy.unselectable();
27329 this.proxy.enableDisplayMode('block');
27331 Roo.apply(this, config);
27334 this.disableTrackOver = true;
27335 this.el.addClass("x-resizable-pinned");
27337 // if the element isn't positioned, make it relative
27338 var position = this.el.getStyle("position");
27339 if(position != "absolute" && position != "fixed"){
27340 this.el.setStyle("position", "relative");
27342 if(!this.handles){ // no handles passed, must be legacy style
27343 this.handles = 's,e,se';
27344 if(this.multiDirectional){
27345 this.handles += ',n,w';
27348 if(this.handles == "all"){
27349 this.handles = "n s e w ne nw se sw";
27351 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27352 var ps = Roo.Resizable.positions;
27353 for(var i = 0, len = hs.length; i < len; i++){
27354 if(hs[i] && ps[hs[i]]){
27355 var pos = ps[hs[i]];
27356 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27360 this.corner = this.southeast;
27362 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1){
27363 this.updateBox = true;
27366 this.activeHandle = null;
27368 if(this.resizeChild){
27369 if(typeof this.resizeChild == "boolean"){
27370 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27372 this.resizeChild = Roo.get(this.resizeChild, true);
27376 if(this.adjustments == "auto"){
27377 var rc = this.resizeChild;
27378 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27379 if(rc && (hw || hn)){
27380 rc.position("relative");
27381 rc.setLeft(hw ? hw.el.getWidth() : 0);
27382 rc.setTop(hn ? hn.el.getHeight() : 0);
27384 this.adjustments = [
27385 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27386 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27390 if(this.draggable){
27391 this.dd = this.dynamic ?
27392 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27393 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27399 * @event beforeresize
27400 * Fired before resize is allowed. Set enabled to false to cancel resize.
27401 * @param {Roo.Resizable} this
27402 * @param {Roo.EventObject} e The mousedown event
27404 "beforeresize" : true,
27407 * Fired after a resize.
27408 * @param {Roo.Resizable} this
27409 * @param {Number} width The new width
27410 * @param {Number} height The new height
27411 * @param {Roo.EventObject} e The mouseup event
27416 if(this.width !== null && this.height !== null){
27417 this.resizeTo(this.width, this.height);
27419 this.updateChildSize();
27422 this.el.dom.style.zoom = 1;
27424 Roo.Resizable.superclass.constructor.call(this);
27427 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27428 resizeChild : false,
27429 adjustments : [0, 0],
27439 multiDirectional : false,
27440 disableTrackOver : false,
27441 easing : 'easeOutStrong',
27442 widthIncrement : 0,
27443 heightIncrement : 0,
27447 preserveRatio : false,
27448 transparent: false,
27454 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27456 constrainTo: undefined,
27458 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27460 resizeRegion: undefined,
27464 * Perform a manual resize
27465 * @param {Number} width
27466 * @param {Number} height
27468 resizeTo : function(width, height){
27469 this.el.setSize(width, height);
27470 this.updateChildSize();
27471 this.fireEvent("resize", this, width, height, null);
27475 startSizing : function(e, handle){
27476 this.fireEvent("beforeresize", this, e);
27477 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27480 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27481 this.overlay.unselectable();
27482 this.overlay.enableDisplayMode("block");
27483 this.overlay.on("mousemove", this.onMouseMove, this);
27484 this.overlay.on("mouseup", this.onMouseUp, this);
27486 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27488 this.resizing = true;
27489 this.startBox = this.el.getBox();
27490 this.startPoint = e.getXY();
27491 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27492 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27494 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27495 this.overlay.show();
27497 if(this.constrainTo) {
27498 var ct = Roo.get(this.constrainTo);
27499 this.resizeRegion = ct.getRegion().adjust(
27500 ct.getFrameWidth('t'),
27501 ct.getFrameWidth('l'),
27502 -ct.getFrameWidth('b'),
27503 -ct.getFrameWidth('r')
27507 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27509 this.proxy.setBox(this.startBox);
27511 this.proxy.setStyle('visibility', 'visible');
27517 onMouseDown : function(handle, e){
27520 this.activeHandle = handle;
27521 this.startSizing(e, handle);
27526 onMouseUp : function(e){
27527 var size = this.resizeElement();
27528 this.resizing = false;
27530 this.overlay.hide();
27532 this.fireEvent("resize", this, size.width, size.height, e);
27536 updateChildSize : function(){
27537 if(this.resizeChild){
27539 var child = this.resizeChild;
27540 var adj = this.adjustments;
27541 if(el.dom.offsetWidth){
27542 var b = el.getSize(true);
27543 child.setSize(b.width+adj[0], b.height+adj[1]);
27545 // Second call here for IE
27546 // The first call enables instant resizing and
27547 // the second call corrects scroll bars if they
27550 setTimeout(function(){
27551 if(el.dom.offsetWidth){
27552 var b = el.getSize(true);
27553 child.setSize(b.width+adj[0], b.height+adj[1]);
27561 snap : function(value, inc, min){
27562 if(!inc || !value) return value;
27563 var newValue = value;
27564 var m = value % inc;
27567 newValue = value + (inc-m);
27569 newValue = value - m;
27572 return Math.max(min, newValue);
27576 resizeElement : function(){
27577 var box = this.proxy.getBox();
27578 if(this.updateBox){
27579 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27581 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27583 this.updateChildSize();
27591 constrain : function(v, diff, m, mx){
27594 }else if(v - diff > mx){
27601 onMouseMove : function(e){
27603 try{// try catch so if something goes wrong the user doesn't get hung
27605 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27609 //var curXY = this.startPoint;
27610 var curSize = this.curSize || this.startBox;
27611 var x = this.startBox.x, y = this.startBox.y;
27612 var ox = x, oy = y;
27613 var w = curSize.width, h = curSize.height;
27614 var ow = w, oh = h;
27615 var mw = this.minWidth, mh = this.minHeight;
27616 var mxw = this.maxWidth, mxh = this.maxHeight;
27617 var wi = this.widthIncrement;
27618 var hi = this.heightIncrement;
27620 var eventXY = e.getXY();
27621 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27622 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27624 var pos = this.activeHandle.position;
27629 w = Math.min(Math.max(mw, w), mxw);
27633 h = Math.min(Math.max(mh, h), mxh);
27638 w = Math.min(Math.max(mw, w), mxw);
27639 h = Math.min(Math.max(mh, h), mxh);
27642 diffY = this.constrain(h, diffY, mh, mxh);
27647 diffX = this.constrain(w, diffX, mw, mxw);
27653 w = Math.min(Math.max(mw, w), mxw);
27654 diffY = this.constrain(h, diffY, mh, mxh);
27659 diffX = this.constrain(w, diffX, mw, mxw);
27660 diffY = this.constrain(h, diffY, mh, mxh);
27667 diffX = this.constrain(w, diffX, mw, mxw);
27669 h = Math.min(Math.max(mh, h), mxh);
27675 var sw = this.snap(w, wi, mw);
27676 var sh = this.snap(h, hi, mh);
27677 if(sw != w || sh != h){
27700 if(this.preserveRatio){
27705 h = Math.min(Math.max(mh, h), mxh);
27710 w = Math.min(Math.max(mw, w), mxw);
27715 w = Math.min(Math.max(mw, w), mxw);
27721 w = Math.min(Math.max(mw, w), mxw);
27727 h = Math.min(Math.max(mh, h), mxh);
27735 h = Math.min(Math.max(mh, h), mxh);
27745 h = Math.min(Math.max(mh, h), mxh);
27753 this.proxy.setBounds(x, y, w, h);
27755 this.resizeElement();
27762 handleOver : function(){
27764 this.el.addClass("x-resizable-over");
27769 handleOut : function(){
27770 if(!this.resizing){
27771 this.el.removeClass("x-resizable-over");
27776 * Returns the element this component is bound to.
27777 * @return {Roo.Element}
27779 getEl : function(){
27784 * Returns the resizeChild element (or null).
27785 * @return {Roo.Element}
27787 getResizeChild : function(){
27788 return this.resizeChild;
27792 * Destroys this resizable. If the element was wrapped and
27793 * removeEl is not true then the element remains.
27794 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
27796 destroy : function(removeEl){
27797 this.proxy.remove();
27799 this.overlay.removeAllListeners();
27800 this.overlay.remove();
27802 var ps = Roo.Resizable.positions;
27804 if(typeof ps[k] != "function" && this[ps[k]]){
27805 var h = this[ps[k]];
27806 h.el.removeAllListeners();
27811 this.el.update("");
27818 // hash to map config positions to true positions
27819 Roo.Resizable.positions = {
27820 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast"
27824 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
27826 // only initialize the template if resizable is used
27827 var tpl = Roo.DomHelper.createTemplate(
27828 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
27831 Roo.Resizable.Handle.prototype.tpl = tpl;
27833 this.position = pos;
27835 this.el = this.tpl.append(rz.el.dom, [this.position], true);
27836 this.el.unselectable();
27838 this.el.setOpacity(0);
27840 this.el.on("mousedown", this.onMouseDown, this);
27841 if(!disableTrackOver){
27842 this.el.on("mouseover", this.onMouseOver, this);
27843 this.el.on("mouseout", this.onMouseOut, this);
27848 Roo.Resizable.Handle.prototype = {
27849 afterResize : function(rz){
27853 onMouseDown : function(e){
27854 this.rz.onMouseDown(this, e);
27857 onMouseOver : function(e){
27858 this.rz.handleOver(this, e);
27861 onMouseOut : function(e){
27862 this.rz.handleOut(this, e);
27866 * Ext JS Library 1.1.1
27867 * Copyright(c) 2006-2007, Ext JS, LLC.
27869 * Originally Released Under LGPL - original licence link has changed is not relivant.
27872 * <script type="text/javascript">
27876 * @class Roo.Editor
27877 * @extends Roo.Component
27878 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
27880 * Create a new Editor
27881 * @param {Roo.form.Field} field The Field object (or descendant)
27882 * @param {Object} config The config object
27884 Roo.Editor = function(field, config){
27885 Roo.Editor.superclass.constructor.call(this, config);
27886 this.field = field;
27889 * @event beforestartedit
27890 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
27891 * false from the handler of this event.
27892 * @param {Editor} this
27893 * @param {Roo.Element} boundEl The underlying element bound to this editor
27894 * @param {Mixed} value The field value being set
27896 "beforestartedit" : true,
27899 * Fires when this editor is displayed
27900 * @param {Roo.Element} boundEl The underlying element bound to this editor
27901 * @param {Mixed} value The starting field value
27903 "startedit" : true,
27905 * @event beforecomplete
27906 * Fires after a change has been made to the field, but before the change is reflected in the underlying
27907 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
27908 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
27909 * event will not fire since no edit actually occurred.
27910 * @param {Editor} this
27911 * @param {Mixed} value The current field value
27912 * @param {Mixed} startValue The original field value
27914 "beforecomplete" : true,
27917 * Fires after editing is complete and any changed value has been written to the underlying field.
27918 * @param {Editor} this
27919 * @param {Mixed} value The current field value
27920 * @param {Mixed} startValue The original field value
27924 * @event specialkey
27925 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
27926 * {@link Roo.EventObject#getKey} to determine which key was pressed.
27927 * @param {Roo.form.Field} this
27928 * @param {Roo.EventObject} e The event object
27930 "specialkey" : true
27934 Roo.extend(Roo.Editor, Roo.Component, {
27936 * @cfg {Boolean/String} autosize
27937 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
27938 * or "height" to adopt the height only (defaults to false)
27941 * @cfg {Boolean} revertInvalid
27942 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
27943 * validation fails (defaults to true)
27946 * @cfg {Boolean} ignoreNoChange
27947 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
27948 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
27949 * will never be ignored.
27952 * @cfg {Boolean} hideEl
27953 * False to keep the bound element visible while the editor is displayed (defaults to true)
27956 * @cfg {Mixed} value
27957 * The data value of the underlying field (defaults to "")
27961 * @cfg {String} alignment
27962 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
27966 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
27967 * for bottom-right shadow (defaults to "frame")
27971 * @cfg {Boolean} constrain True to constrain the editor to the viewport
27975 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
27977 completeOnEnter : false,
27979 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
27981 cancelOnEsc : false,
27983 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
27988 onRender : function(ct, position){
27989 this.el = new Roo.Layer({
27990 shadow: this.shadow,
27996 constrain: this.constrain
27998 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
27999 if(this.field.msgTarget != 'title'){
28000 this.field.msgTarget = 'qtip';
28002 this.field.render(this.el);
28004 this.field.el.dom.setAttribute('autocomplete', 'off');
28006 this.field.on("specialkey", this.onSpecialKey, this);
28007 if(this.swallowKeys){
28008 this.field.el.swallowEvent(['keydown','keypress']);
28011 this.field.on("blur", this.onBlur, this);
28012 if(this.field.grow){
28013 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28017 onSpecialKey : function(field, e){
28018 if(this.completeOnEnter && e.getKey() == e.ENTER){
28020 this.completeEdit();
28021 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
28024 this.fireEvent('specialkey', field, e);
28029 * Starts the editing process and shows the editor.
28030 * @param {String/HTMLElement/Element} el The element to edit
28031 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28032 * to the innerHTML of el.
28034 startEdit : function(el, value){
28036 this.completeEdit();
28038 this.boundEl = Roo.get(el);
28039 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28040 if(!this.rendered){
28041 this.render(this.parentEl || document.body);
28043 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28046 this.startValue = v;
28047 this.field.setValue(v);
28049 var sz = this.boundEl.getSize();
28050 switch(this.autoSize){
28052 this.setSize(sz.width, "");
28055 this.setSize("", sz.height);
28058 this.setSize(sz.width, sz.height);
28061 this.el.alignTo(this.boundEl, this.alignment);
28062 this.editing = true;
28064 Roo.QuickTips.disable();
28070 * Sets the height and width of this editor.
28071 * @param {Number} width The new width
28072 * @param {Number} height The new height
28074 setSize : function(w, h){
28075 this.field.setSize(w, h);
28082 * Realigns the editor to the bound field based on the current alignment config value.
28084 realign : function(){
28085 this.el.alignTo(this.boundEl, this.alignment);
28089 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28090 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28092 completeEdit : function(remainVisible){
28096 var v = this.getValue();
28097 if(this.revertInvalid !== false && !this.field.isValid()){
28098 v = this.startValue;
28099 this.cancelEdit(true);
28101 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28102 this.editing = false;
28106 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28107 this.editing = false;
28108 if(this.updateEl && this.boundEl){
28109 this.boundEl.update(v);
28111 if(remainVisible !== true){
28114 this.fireEvent("complete", this, v, this.startValue);
28119 onShow : function(){
28121 if(this.hideEl !== false){
28122 this.boundEl.hide();
28125 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28126 this.fixIEFocus = true;
28127 this.deferredFocus.defer(50, this);
28129 this.field.focus();
28131 this.fireEvent("startedit", this.boundEl, this.startValue);
28134 deferredFocus : function(){
28136 this.field.focus();
28141 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28142 * reverted to the original starting value.
28143 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28144 * cancel (defaults to false)
28146 cancelEdit : function(remainVisible){
28148 this.setValue(this.startValue);
28149 if(remainVisible !== true){
28156 onBlur : function(){
28157 if(this.allowBlur !== true && this.editing){
28158 this.completeEdit();
28163 onHide : function(){
28165 this.completeEdit();
28169 if(this.field.collapse){
28170 this.field.collapse();
28173 if(this.hideEl !== false){
28174 this.boundEl.show();
28177 Roo.QuickTips.enable();
28182 * Sets the data value of the editor
28183 * @param {Mixed} value Any valid value supported by the underlying field
28185 setValue : function(v){
28186 this.field.setValue(v);
28190 * Gets the data value of the editor
28191 * @return {Mixed} The data value
28193 getValue : function(){
28194 return this.field.getValue();
28198 * Ext JS Library 1.1.1
28199 * Copyright(c) 2006-2007, Ext JS, LLC.
28201 * Originally Released Under LGPL - original licence link has changed is not relivant.
28204 * <script type="text/javascript">
28208 * @class Roo.BasicDialog
28209 * @extends Roo.util.Observable
28210 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28212 var dlg = new Roo.BasicDialog("my-dlg", {
28221 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28222 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28223 dlg.addButton('Cancel', dlg.hide, dlg);
28226 <b>A Dialog should always be a direct child of the body element.</b>
28227 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28228 * @cfg {String} title Default text to display in the title bar (defaults to null)
28229 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28230 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28231 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28232 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28233 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28234 * (defaults to null with no animation)
28235 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28236 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28237 * property for valid values (defaults to 'all')
28238 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28239 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28240 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28241 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28242 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28243 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28244 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28245 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28246 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28247 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28248 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28249 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28250 * draggable = true (defaults to false)
28251 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28252 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28253 * shadow (defaults to false)
28254 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28255 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28256 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28257 * @cfg {Array} buttons Array of buttons
28258 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28260 * Create a new BasicDialog.
28261 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28262 * @param {Object} config Configuration options
28264 Roo.BasicDialog = function(el, config){
28265 this.el = Roo.get(el);
28266 var dh = Roo.DomHelper;
28267 if(!this.el && config && config.autoCreate){
28268 if(typeof config.autoCreate == "object"){
28269 if(!config.autoCreate.id){
28270 config.autoCreate.id = el;
28272 this.el = dh.append(document.body,
28273 config.autoCreate, true);
28275 this.el = dh.append(document.body,
28276 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28280 el.setDisplayed(true);
28281 el.hide = this.hideAction;
28283 el.addClass("x-dlg");
28285 Roo.apply(this, config);
28287 this.proxy = el.createProxy("x-dlg-proxy");
28288 this.proxy.hide = this.hideAction;
28289 this.proxy.setOpacity(.5);
28293 el.setWidth(config.width);
28296 el.setHeight(config.height);
28298 this.size = el.getSize();
28299 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28300 this.xy = [config.x,config.y];
28302 this.xy = el.getCenterXY(true);
28304 /** The header element @type Roo.Element */
28305 this.header = el.child("> .x-dlg-hd");
28306 /** The body element @type Roo.Element */
28307 this.body = el.child("> .x-dlg-bd");
28308 /** The footer element @type Roo.Element */
28309 this.footer = el.child("> .x-dlg-ft");
28312 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28315 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28318 this.header.unselectable();
28320 this.header.update(this.title);
28322 // this element allows the dialog to be focused for keyboard event
28323 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28324 this.focusEl.swallowEvent("click", true);
28326 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28328 // wrap the body and footer for special rendering
28329 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28331 this.bwrap.dom.appendChild(this.footer.dom);
28334 this.bg = this.el.createChild({
28335 tag: "div", cls:"x-dlg-bg",
28336 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28338 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28341 if(this.autoScroll !== false && !this.autoTabs){
28342 this.body.setStyle("overflow", "auto");
28345 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28347 if(this.closable !== false){
28348 this.el.addClass("x-dlg-closable");
28349 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28350 this.close.on("click", this.closeClick, this);
28351 this.close.addClassOnOver("x-dlg-close-over");
28353 if(this.collapsible !== false){
28354 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28355 this.collapseBtn.on("click", this.collapseClick, this);
28356 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28357 this.header.on("dblclick", this.collapseClick, this);
28359 if(this.resizable !== false){
28360 this.el.addClass("x-dlg-resizable");
28361 this.resizer = new Roo.Resizable(el, {
28362 minWidth: this.minWidth || 80,
28363 minHeight:this.minHeight || 80,
28364 handles: this.resizeHandles || "all",
28367 this.resizer.on("beforeresize", this.beforeResize, this);
28368 this.resizer.on("resize", this.onResize, this);
28370 if(this.draggable !== false){
28371 el.addClass("x-dlg-draggable");
28372 if (!this.proxyDrag) {
28373 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28376 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28378 dd.setHandleElId(this.header.id);
28379 dd.endDrag = this.endMove.createDelegate(this);
28380 dd.startDrag = this.startMove.createDelegate(this);
28381 dd.onDrag = this.onDrag.createDelegate(this);
28386 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28387 this.mask.enableDisplayMode("block");
28389 this.el.addClass("x-dlg-modal");
28392 this.shadow = new Roo.Shadow({
28393 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28394 offset : this.shadowOffset
28397 this.shadowOffset = 0;
28399 if(Roo.useShims && this.shim !== false){
28400 this.shim = this.el.createShim();
28401 this.shim.hide = this.hideAction;
28409 if (this.buttons) {
28410 var bts= this.buttons;
28412 Roo.each(bts, function(b) {
28421 * Fires when a key is pressed
28422 * @param {Roo.BasicDialog} this
28423 * @param {Roo.EventObject} e
28428 * Fires when this dialog is moved by the user.
28429 * @param {Roo.BasicDialog} this
28430 * @param {Number} x The new page X
28431 * @param {Number} y The new page Y
28436 * Fires when this dialog is resized by the user.
28437 * @param {Roo.BasicDialog} this
28438 * @param {Number} width The new width
28439 * @param {Number} height The new height
28443 * @event beforehide
28444 * Fires before this dialog is hidden.
28445 * @param {Roo.BasicDialog} this
28447 "beforehide" : true,
28450 * Fires when this dialog is hidden.
28451 * @param {Roo.BasicDialog} this
28455 * @event beforeshow
28456 * Fires before this dialog is shown.
28457 * @param {Roo.BasicDialog} this
28459 "beforeshow" : true,
28462 * Fires when this dialog is shown.
28463 * @param {Roo.BasicDialog} this
28467 el.on("keydown", this.onKeyDown, this);
28468 el.on("mousedown", this.toFront, this);
28469 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28471 Roo.DialogManager.register(this);
28472 Roo.BasicDialog.superclass.constructor.call(this);
28475 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28476 shadowOffset: Roo.isIE ? 6 : 5,
28479 minButtonWidth: 75,
28480 defaultButton: null,
28481 buttonAlign: "right",
28486 * Sets the dialog title text
28487 * @param {String} text The title text to display
28488 * @return {Roo.BasicDialog} this
28490 setTitle : function(text){
28491 this.header.update(text);
28496 closeClick : function(){
28501 collapseClick : function(){
28502 this[this.collapsed ? "expand" : "collapse"]();
28506 * Collapses the dialog to its minimized state (only the title bar is visible).
28507 * Equivalent to the user clicking the collapse dialog button.
28509 collapse : function(){
28510 if(!this.collapsed){
28511 this.collapsed = true;
28512 this.el.addClass("x-dlg-collapsed");
28513 this.restoreHeight = this.el.getHeight();
28514 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28519 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28520 * clicking the expand dialog button.
28522 expand : function(){
28523 if(this.collapsed){
28524 this.collapsed = false;
28525 this.el.removeClass("x-dlg-collapsed");
28526 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28531 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28532 * @return {Roo.TabPanel} The tabs component
28534 initTabs : function(){
28535 var tabs = this.getTabs();
28536 while(tabs.getTab(0)){
28539 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28541 tabs.addTab(Roo.id(dom), dom.title);
28549 beforeResize : function(){
28550 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28554 onResize : function(){
28555 this.refreshSize();
28556 this.syncBodyHeight();
28557 this.adjustAssets();
28559 this.fireEvent("resize", this, this.size.width, this.size.height);
28563 onKeyDown : function(e){
28564 if(this.isVisible()){
28565 this.fireEvent("keydown", this, e);
28570 * Resizes the dialog.
28571 * @param {Number} width
28572 * @param {Number} height
28573 * @return {Roo.BasicDialog} this
28575 resizeTo : function(width, height){
28576 this.el.setSize(width, height);
28577 this.size = {width: width, height: height};
28578 this.syncBodyHeight();
28579 if(this.fixedcenter){
28582 if(this.isVisible()){
28583 this.constrainXY();
28584 this.adjustAssets();
28586 this.fireEvent("resize", this, width, height);
28592 * Resizes the dialog to fit the specified content size.
28593 * @param {Number} width
28594 * @param {Number} height
28595 * @return {Roo.BasicDialog} this
28597 setContentSize : function(w, h){
28598 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28599 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28600 //if(!this.el.isBorderBox()){
28601 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28602 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28605 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28606 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28608 this.resizeTo(w, h);
28613 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28614 * executed in response to a particular key being pressed while the dialog is active.
28615 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28616 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28617 * @param {Function} fn The function to call
28618 * @param {Object} scope (optional) The scope of the function
28619 * @return {Roo.BasicDialog} this
28621 addKeyListener : function(key, fn, scope){
28622 var keyCode, shift, ctrl, alt;
28623 if(typeof key == "object" && !(key instanceof Array)){
28624 keyCode = key["key"];
28625 shift = key["shift"];
28626 ctrl = key["ctrl"];
28631 var handler = function(dlg, e){
28632 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28633 var k = e.getKey();
28634 if(keyCode instanceof Array){
28635 for(var i = 0, len = keyCode.length; i < len; i++){
28636 if(keyCode[i] == k){
28637 fn.call(scope || window, dlg, k, e);
28643 fn.call(scope || window, dlg, k, e);
28648 this.on("keydown", handler);
28653 * Returns the TabPanel component (creates it if it doesn't exist).
28654 * Note: If you wish to simply check for the existence of tabs without creating them,
28655 * check for a null 'tabs' property.
28656 * @return {Roo.TabPanel} The tabs component
28658 getTabs : function(){
28660 this.el.addClass("x-dlg-auto-tabs");
28661 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28662 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28668 * Adds a button to the footer section of the dialog.
28669 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28670 * object or a valid Roo.DomHelper element config
28671 * @param {Function} handler The function called when the button is clicked
28672 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28673 * @return {Roo.Button} The new button
28675 addButton : function(config, handler, scope){
28676 var dh = Roo.DomHelper;
28678 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28680 if(!this.btnContainer){
28681 var tb = this.footer.createChild({
28683 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28684 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28686 this.btnContainer = tb.firstChild.firstChild.firstChild;
28691 minWidth: this.minButtonWidth,
28694 if(typeof config == "string"){
28695 bconfig.text = config;
28698 bconfig.dhconfig = config;
28700 Roo.apply(bconfig, config);
28704 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
28705 bconfig.position = Math.max(0, bconfig.position);
28706 fc = this.btnContainer.childNodes[bconfig.position];
28709 var btn = new Roo.Button(
28711 this.btnContainer.insertBefore(document.createElement("td"),fc)
28712 : this.btnContainer.appendChild(document.createElement("td")),
28713 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
28716 this.syncBodyHeight();
28719 * Array of all the buttons that have been added to this dialog via addButton
28724 this.buttons.push(btn);
28729 * Sets the default button to be focused when the dialog is displayed.
28730 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
28731 * @return {Roo.BasicDialog} this
28733 setDefaultButton : function(btn){
28734 this.defaultButton = btn;
28739 getHeaderFooterHeight : function(safe){
28742 height += this.header.getHeight();
28745 var fm = this.footer.getMargins();
28746 height += (this.footer.getHeight()+fm.top+fm.bottom);
28748 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
28749 height += this.centerBg.getPadding("tb");
28754 syncBodyHeight : function(){
28755 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
28756 var height = this.size.height - this.getHeaderFooterHeight(false);
28757 bd.setHeight(height-bd.getMargins("tb"));
28758 var hh = this.header.getHeight();
28759 var h = this.size.height-hh;
28761 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
28762 bw.setHeight(h-cb.getPadding("tb"));
28763 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
28764 bd.setWidth(bw.getWidth(true));
28766 this.tabs.syncHeight();
28768 this.tabs.el.repaint();
28774 * Restores the previous state of the dialog if Roo.state is configured.
28775 * @return {Roo.BasicDialog} this
28777 restoreState : function(){
28778 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
28779 if(box && box.width){
28780 this.xy = [box.x, box.y];
28781 this.resizeTo(box.width, box.height);
28787 beforeShow : function(){
28789 if(this.fixedcenter){
28790 this.xy = this.el.getCenterXY(true);
28793 Roo.get(document.body).addClass("x-body-masked");
28794 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28797 this.constrainXY();
28801 animShow : function(){
28802 var b = Roo.get(this.animateTarget, true).getBox();
28803 this.proxy.setSize(b.width, b.height);
28804 this.proxy.setLocation(b.x, b.y);
28806 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
28807 true, .35, this.showEl.createDelegate(this));
28811 * Shows the dialog.
28812 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
28813 * @return {Roo.BasicDialog} this
28815 show : function(animateTarget){
28816 if (this.fireEvent("beforeshow", this) === false){
28819 if(this.syncHeightBeforeShow){
28820 this.syncBodyHeight();
28821 }else if(this.firstShow){
28822 this.firstShow = false;
28823 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
28825 this.animateTarget = animateTarget || this.animateTarget;
28826 if(!this.el.isVisible()){
28828 if(this.animateTarget){
28838 showEl : function(){
28840 this.el.setXY(this.xy);
28842 this.adjustAssets(true);
28845 // IE peekaboo bug - fix found by Dave Fenwick
28849 this.fireEvent("show", this);
28853 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
28854 * dialog itself will receive focus.
28856 focus : function(){
28857 if(this.defaultButton){
28858 this.defaultButton.focus();
28860 this.focusEl.focus();
28865 constrainXY : function(){
28866 if(this.constraintoviewport !== false){
28867 if(!this.viewSize){
28868 if(this.container){
28869 var s = this.container.getSize();
28870 this.viewSize = [s.width, s.height];
28872 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
28875 var s = Roo.get(this.container||document).getScroll();
28877 var x = this.xy[0], y = this.xy[1];
28878 var w = this.size.width, h = this.size.height;
28879 var vw = this.viewSize[0], vh = this.viewSize[1];
28880 // only move it if it needs it
28882 // first validate right/bottom
28883 if(x + w > vw+s.left){
28887 if(y + h > vh+s.top){
28891 // then make sure top/left isn't negative
28903 if(this.isVisible()){
28904 this.el.setLocation(x, y);
28905 this.adjustAssets();
28912 onDrag : function(){
28913 if(!this.proxyDrag){
28914 this.xy = this.el.getXY();
28915 this.adjustAssets();
28920 adjustAssets : function(doShow){
28921 var x = this.xy[0], y = this.xy[1];
28922 var w = this.size.width, h = this.size.height;
28923 if(doShow === true){
28925 this.shadow.show(this.el);
28931 if(this.shadow && this.shadow.isVisible()){
28932 this.shadow.show(this.el);
28934 if(this.shim && this.shim.isVisible()){
28935 this.shim.setBounds(x, y, w, h);
28940 adjustViewport : function(w, h){
28942 w = Roo.lib.Dom.getViewWidth();
28943 h = Roo.lib.Dom.getViewHeight();
28946 this.viewSize = [w, h];
28947 if(this.modal && this.mask.isVisible()){
28948 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
28949 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28951 if(this.isVisible()){
28952 this.constrainXY();
28957 * Destroys this dialog and all its supporting elements (including any tabs, shim,
28958 * shadow, proxy, mask, etc.) Also removes all event listeners.
28959 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28961 destroy : function(removeEl){
28962 if(this.isVisible()){
28963 this.animateTarget = null;
28966 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
28968 this.tabs.destroy(removeEl);
28981 for(var i = 0, len = this.buttons.length; i < len; i++){
28982 this.buttons[i].destroy();
28985 this.el.removeAllListeners();
28986 if(removeEl === true){
28987 this.el.update("");
28990 Roo.DialogManager.unregister(this);
28994 startMove : function(){
28995 if(this.proxyDrag){
28998 if(this.constraintoviewport !== false){
28999 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29004 endMove : function(){
29005 if(!this.proxyDrag){
29006 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29008 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29011 this.refreshSize();
29012 this.adjustAssets();
29014 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29018 * Brings this dialog to the front of any other visible dialogs
29019 * @return {Roo.BasicDialog} this
29021 toFront : function(){
29022 Roo.DialogManager.bringToFront(this);
29027 * Sends this dialog to the back (under) of any other visible dialogs
29028 * @return {Roo.BasicDialog} this
29030 toBack : function(){
29031 Roo.DialogManager.sendToBack(this);
29036 * Centers this dialog in the viewport
29037 * @return {Roo.BasicDialog} this
29039 center : function(){
29040 var xy = this.el.getCenterXY(true);
29041 this.moveTo(xy[0], xy[1]);
29046 * Moves the dialog's top-left corner to the specified point
29047 * @param {Number} x
29048 * @param {Number} y
29049 * @return {Roo.BasicDialog} this
29051 moveTo : function(x, y){
29053 if(this.isVisible()){
29054 this.el.setXY(this.xy);
29055 this.adjustAssets();
29061 * Aligns the dialog to the specified element
29062 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29063 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29064 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29065 * @return {Roo.BasicDialog} this
29067 alignTo : function(element, position, offsets){
29068 this.xy = this.el.getAlignToXY(element, position, offsets);
29069 if(this.isVisible()){
29070 this.el.setXY(this.xy);
29071 this.adjustAssets();
29077 * Anchors an element to another element and realigns it when the window is resized.
29078 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29079 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29080 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29081 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29082 * is a number, it is used as the buffer delay (defaults to 50ms).
29083 * @return {Roo.BasicDialog} this
29085 anchorTo : function(el, alignment, offsets, monitorScroll){
29086 var action = function(){
29087 this.alignTo(el, alignment, offsets);
29089 Roo.EventManager.onWindowResize(action, this);
29090 var tm = typeof monitorScroll;
29091 if(tm != 'undefined'){
29092 Roo.EventManager.on(window, 'scroll', action, this,
29093 {buffer: tm == 'number' ? monitorScroll : 50});
29100 * Returns true if the dialog is visible
29101 * @return {Boolean}
29103 isVisible : function(){
29104 return this.el.isVisible();
29108 animHide : function(callback){
29109 var b = Roo.get(this.animateTarget).getBox();
29111 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29113 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29114 this.hideEl.createDelegate(this, [callback]));
29118 * Hides the dialog.
29119 * @param {Function} callback (optional) Function to call when the dialog is hidden
29120 * @return {Roo.BasicDialog} this
29122 hide : function(callback){
29123 if (this.fireEvent("beforehide", this) === false){
29127 this.shadow.hide();
29132 if(this.animateTarget){
29133 this.animHide(callback);
29136 this.hideEl(callback);
29142 hideEl : function(callback){
29146 Roo.get(document.body).removeClass("x-body-masked");
29148 this.fireEvent("hide", this);
29149 if(typeof callback == "function"){
29155 hideAction : function(){
29156 this.setLeft("-10000px");
29157 this.setTop("-10000px");
29158 this.setStyle("visibility", "hidden");
29162 refreshSize : function(){
29163 this.size = this.el.getSize();
29164 this.xy = this.el.getXY();
29165 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29169 // z-index is managed by the DialogManager and may be overwritten at any time
29170 setZIndex : function(index){
29172 this.mask.setStyle("z-index", index);
29175 this.shim.setStyle("z-index", ++index);
29178 this.shadow.setZIndex(++index);
29180 this.el.setStyle("z-index", ++index);
29182 this.proxy.setStyle("z-index", ++index);
29185 this.resizer.proxy.setStyle("z-index", ++index);
29188 this.lastZIndex = index;
29192 * Returns the element for this dialog
29193 * @return {Roo.Element} The underlying dialog Element
29195 getEl : function(){
29201 * @class Roo.DialogManager
29202 * Provides global access to BasicDialogs that have been created and
29203 * support for z-indexing (layering) multiple open dialogs.
29205 Roo.DialogManager = function(){
29207 var accessList = [];
29211 var sortDialogs = function(d1, d2){
29212 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29216 var orderDialogs = function(){
29217 accessList.sort(sortDialogs);
29218 var seed = Roo.DialogManager.zseed;
29219 for(var i = 0, len = accessList.length; i < len; i++){
29220 var dlg = accessList[i];
29222 dlg.setZIndex(seed + (i*10));
29229 * The starting z-index for BasicDialogs (defaults to 9000)
29230 * @type Number The z-index value
29235 register : function(dlg){
29236 list[dlg.id] = dlg;
29237 accessList.push(dlg);
29241 unregister : function(dlg){
29242 delete list[dlg.id];
29245 if(!accessList.indexOf){
29246 for( i = 0, len = accessList.length; i < len; i++){
29247 if(accessList[i] == dlg){
29248 accessList.splice(i, 1);
29253 i = accessList.indexOf(dlg);
29255 accessList.splice(i, 1);
29261 * Gets a registered dialog by id
29262 * @param {String/Object} id The id of the dialog or a dialog
29263 * @return {Roo.BasicDialog} this
29265 get : function(id){
29266 return typeof id == "object" ? id : list[id];
29270 * Brings the specified dialog to the front
29271 * @param {String/Object} dlg The id of the dialog or a dialog
29272 * @return {Roo.BasicDialog} this
29274 bringToFront : function(dlg){
29275 dlg = this.get(dlg);
29278 dlg._lastAccess = new Date().getTime();
29285 * Sends the specified dialog to the back
29286 * @param {String/Object} dlg The id of the dialog or a dialog
29287 * @return {Roo.BasicDialog} this
29289 sendToBack : function(dlg){
29290 dlg = this.get(dlg);
29291 dlg._lastAccess = -(new Date().getTime());
29297 * Hides all dialogs
29299 hideAll : function(){
29300 for(var id in list){
29301 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29310 * @class Roo.LayoutDialog
29311 * @extends Roo.BasicDialog
29312 * Dialog which provides adjustments for working with a layout in a Dialog.
29313 * Add your necessary layout config options to the dialog's config.<br>
29314 * Example usage (including a nested layout):
29317 dialog = new Roo.LayoutDialog("download-dlg", {
29326 // layout config merges with the dialog config
29328 tabPosition: "top",
29329 alwaysShowTabs: true
29332 dialog.addKeyListener(27, dialog.hide, dialog);
29333 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29334 dialog.addButton("Build It!", this.getDownload, this);
29336 // we can even add nested layouts
29337 var innerLayout = new Roo.BorderLayout("dl-inner", {
29347 innerLayout.beginUpdate();
29348 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29349 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29350 innerLayout.endUpdate(true);
29352 var layout = dialog.getLayout();
29353 layout.beginUpdate();
29354 layout.add("center", new Roo.ContentPanel("standard-panel",
29355 {title: "Download the Source", fitToFrame:true}));
29356 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29357 {title: "Build your own roo.js"}));
29358 layout.getRegion("center").showPanel(sp);
29359 layout.endUpdate();
29363 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29364 * @param {Object} config configuration options
29366 Roo.LayoutDialog = function(el, cfg){
29369 if (typeof(cfg) == 'undefined') {
29370 config = Roo.apply({}, el);
29371 el = Roo.get( document.documentElement || document.body).createChild();
29372 //config.autoCreate = true;
29376 config.autoTabs = false;
29377 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29378 this.body.setStyle({overflow:"hidden", position:"relative"});
29379 this.layout = new Roo.BorderLayout(this.body.dom, config);
29380 this.layout.monitorWindowResize = false;
29381 this.el.addClass("x-dlg-auto-layout");
29382 // fix case when center region overwrites center function
29383 this.center = Roo.BasicDialog.prototype.center;
29384 this.on("show", this.layout.layout, this.layout, true);
29385 if (config.items) {
29386 var xitems = config.items;
29387 delete config.items;
29388 Roo.each(xitems, this.addxtype, this);
29393 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29395 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29398 endUpdate : function(){
29399 this.layout.endUpdate();
29403 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29406 beginUpdate : function(){
29407 this.layout.beginUpdate();
29411 * Get the BorderLayout for this dialog
29412 * @return {Roo.BorderLayout}
29414 getLayout : function(){
29415 return this.layout;
29418 showEl : function(){
29419 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29421 this.layout.layout();
29426 // Use the syncHeightBeforeShow config option to control this automatically
29427 syncBodyHeight : function(){
29428 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29429 if(this.layout){this.layout.layout();}
29433 * Add an xtype element (actually adds to the layout.)
29434 * @return {Object} xdata xtype object data.
29437 addxtype : function(c) {
29438 return this.layout.addxtype(c);
29442 * Ext JS Library 1.1.1
29443 * Copyright(c) 2006-2007, Ext JS, LLC.
29445 * Originally Released Under LGPL - original licence link has changed is not relivant.
29448 * <script type="text/javascript">
29452 * @class Roo.MessageBox
29453 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29457 Roo.Msg.alert('Status', 'Changes saved successfully.');
29459 // Prompt for user data:
29460 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29462 // process text value...
29466 // Show a dialog using config options:
29468 title:'Save Changes?',
29469 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29470 buttons: Roo.Msg.YESNOCANCEL,
29477 Roo.MessageBox = function(){
29478 var dlg, opt, mask, waitTimer;
29479 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29480 var buttons, activeTextEl, bwidth;
29483 var handleButton = function(button){
29485 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29489 var handleHide = function(){
29490 if(opt && opt.cls){
29491 dlg.el.removeClass(opt.cls);
29494 Roo.TaskMgr.stop(waitTimer);
29500 var updateButtons = function(b){
29503 buttons["ok"].hide();
29504 buttons["cancel"].hide();
29505 buttons["yes"].hide();
29506 buttons["no"].hide();
29507 dlg.footer.dom.style.display = 'none';
29510 dlg.footer.dom.style.display = '';
29511 for(var k in buttons){
29512 if(typeof buttons[k] != "function"){
29515 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29516 width += buttons[k].el.getWidth()+15;
29526 var handleEsc = function(d, k, e){
29527 if(opt && opt.closable !== false){
29537 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29538 * @return {Roo.BasicDialog} The BasicDialog element
29540 getDialog : function(){
29542 dlg = new Roo.BasicDialog("x-msg-box", {
29547 constraintoviewport:false,
29549 collapsible : false,
29552 width:400, height:100,
29553 buttonAlign:"center",
29554 closeClick : function(){
29555 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29556 handleButton("no");
29558 handleButton("cancel");
29562 dlg.on("hide", handleHide);
29564 dlg.addKeyListener(27, handleEsc);
29566 var bt = this.buttonText;
29567 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29568 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29569 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29570 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29571 bodyEl = dlg.body.createChild({
29573 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>'
29575 msgEl = bodyEl.dom.firstChild;
29576 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29577 textboxEl.enableDisplayMode();
29578 textboxEl.addKeyListener([10,13], function(){
29579 if(dlg.isVisible() && opt && opt.buttons){
29580 if(opt.buttons.ok){
29581 handleButton("ok");
29582 }else if(opt.buttons.yes){
29583 handleButton("yes");
29587 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29588 textareaEl.enableDisplayMode();
29589 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29590 progressEl.enableDisplayMode();
29591 var pf = progressEl.dom.firstChild;
29593 pp = Roo.get(pf.firstChild);
29594 pp.setHeight(pf.offsetHeight);
29602 * Updates the message box body text
29603 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29604 * the XHTML-compliant non-breaking space character '&#160;')
29605 * @return {Roo.MessageBox} This message box
29607 updateText : function(text){
29608 if(!dlg.isVisible() && !opt.width){
29609 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29611 msgEl.innerHTML = text || ' ';
29612 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29613 Math.max(opt.minWidth || this.minWidth, bwidth));
29615 activeTextEl.setWidth(w);
29617 if(dlg.isVisible()){
29618 dlg.fixedcenter = false;
29620 dlg.setContentSize(w, bodyEl.getHeight());
29621 if(dlg.isVisible()){
29622 dlg.fixedcenter = true;
29628 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29629 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29630 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29631 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29632 * @return {Roo.MessageBox} This message box
29634 updateProgress : function(value, text){
29636 this.updateText(text);
29638 if (pp) { // weird bug on my firefox - for some reason this is not defined
29639 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29645 * Returns true if the message box is currently displayed
29646 * @return {Boolean} True if the message box is visible, else false
29648 isVisible : function(){
29649 return dlg && dlg.isVisible();
29653 * Hides the message box if it is displayed
29656 if(this.isVisible()){
29662 * Displays a new message box, or reinitializes an existing message box, based on the config options
29663 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29664 * The following config object properties are supported:
29666 Property Type Description
29667 ---------- --------------- ------------------------------------------------------------------------------------
29668 animEl String/Element An id or Element from which the message box should animate as it opens and
29669 closes (defaults to undefined)
29670 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29671 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29672 closable Boolean False to hide the top-right close button (defaults to true). Note that
29673 progress and wait dialogs will ignore this property and always hide the
29674 close button as they can only be closed programmatically.
29675 cls String A custom CSS class to apply to the message box element
29676 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29677 displayed (defaults to 75)
29678 fn Function A callback function to execute after closing the dialog. The arguments to the
29679 function will be btn (the name of the button that was clicked, if applicable,
29680 e.g. "ok"), and text (the value of the active text field, if applicable).
29681 Progress and wait dialogs will ignore this option since they do not respond to
29682 user actions and can only be closed programmatically, so any required function
29683 should be called by the same code after it closes the dialog.
29684 icon String A CSS class that provides a background image to be used as an icon for
29685 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29686 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29687 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29688 modal Boolean False to allow user interaction with the page while the message box is
29689 displayed (defaults to true)
29690 msg String A string that will replace the existing message box body text (defaults
29691 to the XHTML-compliant non-breaking space character ' ')
29692 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
29693 progress Boolean True to display a progress bar (defaults to false)
29694 progressText String The text to display inside the progress bar if progress = true (defaults to '')
29695 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
29696 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
29697 title String The title text
29698 value String The string value to set into the active textbox element if displayed
29699 wait Boolean True to display a progress bar (defaults to false)
29700 width Number The width of the dialog in pixels
29707 msg: 'Please enter your address:',
29709 buttons: Roo.MessageBox.OKCANCEL,
29712 animEl: 'addAddressBtn'
29715 * @param {Object} config Configuration options
29716 * @return {Roo.MessageBox} This message box
29718 show : function(options){
29719 if(this.isVisible()){
29722 var d = this.getDialog();
29724 d.setTitle(opt.title || " ");
29725 d.close.setDisplayed(opt.closable !== false);
29726 activeTextEl = textboxEl;
29727 opt.prompt = opt.prompt || (opt.multiline ? true : false);
29732 textareaEl.setHeight(typeof opt.multiline == "number" ?
29733 opt.multiline : this.defaultTextHeight);
29734 activeTextEl = textareaEl;
29743 progressEl.setDisplayed(opt.progress === true);
29744 this.updateProgress(0);
29745 activeTextEl.dom.value = opt.value || "";
29747 dlg.setDefaultButton(activeTextEl);
29749 var bs = opt.buttons;
29752 db = buttons["ok"];
29753 }else if(bs && bs.yes){
29754 db = buttons["yes"];
29756 dlg.setDefaultButton(db);
29758 bwidth = updateButtons(opt.buttons);
29759 this.updateText(opt.msg);
29761 d.el.addClass(opt.cls);
29763 d.proxyDrag = opt.proxyDrag === true;
29764 d.modal = opt.modal !== false;
29765 d.mask = opt.modal !== false ? mask : false;
29766 if(!d.isVisible()){
29767 // force it to the end of the z-index stack so it gets a cursor in FF
29768 document.body.appendChild(dlg.el.dom);
29769 d.animateTarget = null;
29770 d.show(options.animEl);
29776 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
29777 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
29778 * and closing the message box when the process is complete.
29779 * @param {String} title The title bar text
29780 * @param {String} msg The message box body text
29781 * @return {Roo.MessageBox} This message box
29783 progress : function(title, msg){
29790 minWidth: this.minProgressWidth,
29797 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
29798 * If a callback function is passed it will be called after the user clicks the button, and the
29799 * id of the button that was clicked will be passed as the only parameter to the callback
29800 * (could also be the top-right close button).
29801 * @param {String} title The title bar text
29802 * @param {String} msg The message box body text
29803 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29804 * @param {Object} scope (optional) The scope of the callback function
29805 * @return {Roo.MessageBox} This message box
29807 alert : function(title, msg, fn, scope){
29820 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
29821 * interaction while waiting for a long-running process to complete that does not have defined intervals.
29822 * You are responsible for closing the message box when the process is complete.
29823 * @param {String} msg The message box body text
29824 * @param {String} title (optional) The title bar text
29825 * @return {Roo.MessageBox} This message box
29827 wait : function(msg, title){
29838 waitTimer = Roo.TaskMgr.start({
29840 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
29848 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
29849 * If a callback function is passed it will be called after the user clicks either button, and the id of the
29850 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
29851 * @param {String} title The title bar text
29852 * @param {String} msg The message box body text
29853 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29854 * @param {Object} scope (optional) The scope of the callback function
29855 * @return {Roo.MessageBox} This message box
29857 confirm : function(title, msg, fn, scope){
29861 buttons: this.YESNO,
29870 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
29871 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
29872 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
29873 * (could also be the top-right close button) and the text that was entered will be passed as the two
29874 * parameters to the callback.
29875 * @param {String} title The title bar text
29876 * @param {String} msg The message box body text
29877 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29878 * @param {Object} scope (optional) The scope of the callback function
29879 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
29880 * property, or the height in pixels to create the textbox (defaults to false / single-line)
29881 * @return {Roo.MessageBox} This message box
29883 prompt : function(title, msg, fn, scope, multiline){
29887 buttons: this.OKCANCEL,
29892 multiline: multiline,
29899 * Button config that displays a single OK button
29904 * Button config that displays Yes and No buttons
29907 YESNO : {yes:true, no:true},
29909 * Button config that displays OK and Cancel buttons
29912 OKCANCEL : {ok:true, cancel:true},
29914 * Button config that displays Yes, No and Cancel buttons
29917 YESNOCANCEL : {yes:true, no:true, cancel:true},
29920 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
29923 defaultTextHeight : 75,
29925 * The maximum width in pixels of the message box (defaults to 600)
29930 * The minimum width in pixels of the message box (defaults to 100)
29935 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
29936 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
29939 minProgressWidth : 250,
29941 * An object containing the default button text strings that can be overriden for localized language support.
29942 * Supported properties are: ok, cancel, yes and no.
29943 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
29956 * Shorthand for {@link Roo.MessageBox}
29958 Roo.Msg = Roo.MessageBox;/*
29960 * Ext JS Library 1.1.1
29961 * Copyright(c) 2006-2007, Ext JS, LLC.
29963 * Originally Released Under LGPL - original licence link has changed is not relivant.
29966 * <script type="text/javascript">
29969 * @class Roo.QuickTips
29970 * Provides attractive and customizable tooltips for any element.
29973 Roo.QuickTips = function(){
29974 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
29975 var ce, bd, xy, dd;
29976 var visible = false, disabled = true, inited = false;
29977 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
29979 var onOver = function(e){
29983 var t = e.getTarget();
29984 if(!t || t.nodeType !== 1 || t == document || t == document.body){
29987 if(ce && t == ce.el){
29988 clearTimeout(hideProc);
29991 if(t && tagEls[t.id]){
29992 tagEls[t.id].el = t;
29993 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
29996 var ttp, et = Roo.fly(t);
29997 var ns = cfg.namespace;
29998 if(tm.interceptTitles && t.title){
30001 t.removeAttribute("title");
30002 e.preventDefault();
30004 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30007 showProc = show.defer(tm.showDelay, tm, [{
30010 width: et.getAttributeNS(ns, cfg.width),
30011 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30012 title: et.getAttributeNS(ns, cfg.title),
30013 cls: et.getAttributeNS(ns, cfg.cls)
30018 var onOut = function(e){
30019 clearTimeout(showProc);
30020 var t = e.getTarget();
30021 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30022 hideProc = setTimeout(hide, tm.hideDelay);
30026 var onMove = function(e){
30032 if(tm.trackMouse && ce){
30037 var onDown = function(e){
30038 clearTimeout(showProc);
30039 clearTimeout(hideProc);
30041 if(tm.hideOnClick){
30044 tm.enable.defer(100, tm);
30049 var getPad = function(){
30050 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30053 var show = function(o){
30057 clearTimeout(dismissProc);
30059 if(removeCls){ // in case manually hidden
30060 el.removeClass(removeCls);
30064 el.addClass(ce.cls);
30065 removeCls = ce.cls;
30068 tipTitle.update(ce.title);
30071 tipTitle.update('');
30074 el.dom.style.width = tm.maxWidth+'px';
30075 //tipBody.dom.style.width = '';
30076 tipBodyText.update(o.text);
30077 var p = getPad(), w = ce.width;
30079 var td = tipBodyText.dom;
30080 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30081 if(aw > tm.maxWidth){
30083 }else if(aw < tm.minWidth){
30089 //tipBody.setWidth(w);
30090 el.setWidth(parseInt(w, 10) + p);
30091 if(ce.autoHide === false){
30092 close.setDisplayed(true);
30097 close.setDisplayed(false);
30103 el.avoidY = xy[1]-18;
30108 el.setStyle("visibility", "visible");
30109 el.fadeIn({callback: afterShow});
30115 var afterShow = function(){
30119 if(tm.autoDismiss && ce.autoHide !== false){
30120 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30125 var hide = function(noanim){
30126 clearTimeout(dismissProc);
30127 clearTimeout(hideProc);
30129 if(el.isVisible()){
30131 if(noanim !== true && tm.animate){
30132 el.fadeOut({callback: afterHide});
30139 var afterHide = function(){
30142 el.removeClass(removeCls);
30149 * @cfg {Number} minWidth
30150 * The minimum width of the quick tip (defaults to 40)
30154 * @cfg {Number} maxWidth
30155 * The maximum width of the quick tip (defaults to 300)
30159 * @cfg {Boolean} interceptTitles
30160 * True to automatically use the element's DOM title value if available (defaults to false)
30162 interceptTitles : false,
30164 * @cfg {Boolean} trackMouse
30165 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30167 trackMouse : false,
30169 * @cfg {Boolean} hideOnClick
30170 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30172 hideOnClick : true,
30174 * @cfg {Number} showDelay
30175 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30179 * @cfg {Number} hideDelay
30180 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30184 * @cfg {Boolean} autoHide
30185 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30186 * Used in conjunction with hideDelay.
30191 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30192 * (defaults to true). Used in conjunction with autoDismissDelay.
30194 autoDismiss : true,
30197 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30199 autoDismissDelay : 5000,
30201 * @cfg {Boolean} animate
30202 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30207 * @cfg {String} title
30208 * Title text to display (defaults to ''). This can be any valid HTML markup.
30212 * @cfg {String} text
30213 * Body text to display (defaults to ''). This can be any valid HTML markup.
30217 * @cfg {String} cls
30218 * A CSS class to apply to the base quick tip element (defaults to '').
30222 * @cfg {Number} width
30223 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30224 * minWidth or maxWidth.
30229 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30230 * or display QuickTips in a page.
30233 tm = Roo.QuickTips;
30234 cfg = tm.tagConfig;
30236 if(!Roo.isReady){ // allow calling of init() before onReady
30237 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30240 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30241 el.fxDefaults = {stopFx: true};
30242 // maximum custom styling
30243 //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>');
30244 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>');
30245 tipTitle = el.child('h3');
30246 tipTitle.enableDisplayMode("block");
30247 tipBody = el.child('div.x-tip-bd');
30248 tipBodyText = el.child('div.x-tip-bd-inner');
30249 //bdLeft = el.child('div.x-tip-bd-left');
30250 //bdRight = el.child('div.x-tip-bd-right');
30251 close = el.child('div.x-tip-close');
30252 close.enableDisplayMode("block");
30253 close.on("click", hide);
30254 var d = Roo.get(document);
30255 d.on("mousedown", onDown);
30256 d.on("mouseover", onOver);
30257 d.on("mouseout", onOut);
30258 d.on("mousemove", onMove);
30259 esc = d.addKeyListener(27, hide);
30262 dd = el.initDD("default", null, {
30263 onDrag : function(){
30267 dd.setHandleElId(tipTitle.id);
30276 * Configures a new quick tip instance and assigns it to a target element. The following config options
30279 Property Type Description
30280 ---------- --------------------- ------------------------------------------------------------------------
30281 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30283 * @param {Object} config The config object
30285 register : function(config){
30286 var cs = config instanceof Array ? config : arguments;
30287 for(var i = 0, len = cs.length; i < len; i++) {
30289 var target = c.target;
30291 if(target instanceof Array){
30292 for(var j = 0, jlen = target.length; j < jlen; j++){
30293 tagEls[target[j]] = c;
30296 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30303 * Removes this quick tip from its element and destroys it.
30304 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30306 unregister : function(el){
30307 delete tagEls[Roo.id(el)];
30311 * Enable this quick tip.
30313 enable : function(){
30314 if(inited && disabled){
30316 if(locks.length < 1){
30323 * Disable this quick tip.
30325 disable : function(){
30327 clearTimeout(showProc);
30328 clearTimeout(hideProc);
30329 clearTimeout(dismissProc);
30337 * Returns true if the quick tip is enabled, else false.
30339 isEnabled : function(){
30346 attribute : "qtip",
30356 // backwards compat
30357 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30359 * Ext JS Library 1.1.1
30360 * Copyright(c) 2006-2007, Ext JS, LLC.
30362 * Originally Released Under LGPL - original licence link has changed is not relivant.
30365 * <script type="text/javascript">
30370 * @class Roo.tree.TreePanel
30371 * @extends Roo.data.Tree
30373 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30374 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30375 * @cfg {Boolean} enableDD true to enable drag and drop
30376 * @cfg {Boolean} enableDrag true to enable just drag
30377 * @cfg {Boolean} enableDrop true to enable just drop
30378 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30379 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30380 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30381 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30382 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30383 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30384 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30385 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30386 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30387 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30388 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30389 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30390 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30391 * @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>
30392 * @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>
30395 * @param {String/HTMLElement/Element} el The container element
30396 * @param {Object} config
30398 Roo.tree.TreePanel = function(el, config){
30400 var loader = false;
30402 root = config.root;
30403 delete config.root;
30405 if (config.loader) {
30406 loader = config.loader;
30407 delete config.loader;
30410 Roo.apply(this, config);
30411 Roo.tree.TreePanel.superclass.constructor.call(this);
30412 this.el = Roo.get(el);
30413 this.el.addClass('x-tree');
30414 //console.log(root);
30416 this.setRootNode( Roo.factory(root, Roo.tree));
30419 this.loader = Roo.factory(loader, Roo.tree);
30422 * Read-only. The id of the container element becomes this TreePanel's id.
30424 this.id = this.el.id;
30427 * @event beforeload
30428 * Fires before a node is loaded, return false to cancel
30429 * @param {Node} node The node being loaded
30431 "beforeload" : true,
30434 * Fires when a node is loaded
30435 * @param {Node} node The node that was loaded
30439 * @event textchange
30440 * Fires when the text for a node is changed
30441 * @param {Node} node The node
30442 * @param {String} text The new text
30443 * @param {String} oldText The old text
30445 "textchange" : true,
30447 * @event beforeexpand
30448 * Fires before a node is expanded, return false to cancel.
30449 * @param {Node} node The node
30450 * @param {Boolean} deep
30451 * @param {Boolean} anim
30453 "beforeexpand" : true,
30455 * @event beforecollapse
30456 * Fires before a node is collapsed, return false to cancel.
30457 * @param {Node} node The node
30458 * @param {Boolean} deep
30459 * @param {Boolean} anim
30461 "beforecollapse" : true,
30464 * Fires when a node is expanded
30465 * @param {Node} node The node
30469 * @event disabledchange
30470 * Fires when the disabled status of a node changes
30471 * @param {Node} node The node
30472 * @param {Boolean} disabled
30474 "disabledchange" : true,
30477 * Fires when a node is collapsed
30478 * @param {Node} node The node
30482 * @event beforeclick
30483 * Fires before click processing on a node. Return false to cancel the default action.
30484 * @param {Node} node The node
30485 * @param {Roo.EventObject} e The event object
30487 "beforeclick":true,
30489 * @event checkchange
30490 * Fires when a node with a checkbox's checked property changes
30491 * @param {Node} this This node
30492 * @param {Boolean} checked
30494 "checkchange":true,
30497 * Fires when a node is clicked
30498 * @param {Node} node The node
30499 * @param {Roo.EventObject} e The event object
30504 * Fires when a node is double clicked
30505 * @param {Node} node The node
30506 * @param {Roo.EventObject} e The event object
30510 * @event contextmenu
30511 * Fires when a node is right clicked
30512 * @param {Node} node The node
30513 * @param {Roo.EventObject} e The event object
30515 "contextmenu":true,
30517 * @event beforechildrenrendered
30518 * Fires right before the child nodes for a node are rendered
30519 * @param {Node} node The node
30521 "beforechildrenrendered":true,
30524 * Fires when a node starts being dragged
30525 * @param {Roo.tree.TreePanel} this
30526 * @param {Roo.tree.TreeNode} node
30527 * @param {event} e The raw browser event
30529 "startdrag" : true,
30532 * Fires when a drag operation is complete
30533 * @param {Roo.tree.TreePanel} this
30534 * @param {Roo.tree.TreeNode} node
30535 * @param {event} e The raw browser event
30540 * Fires when a dragged node is dropped on a valid DD target
30541 * @param {Roo.tree.TreePanel} this
30542 * @param {Roo.tree.TreeNode} node
30543 * @param {DD} dd The dd it was dropped on
30544 * @param {event} e The raw browser event
30548 * @event beforenodedrop
30549 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
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 <b>OR</b> you can supply node(s)
30559 * to be inserted by setting them on this object.</li>
30560 * <li>cancel - Set this to true to cancel the drop.</li>
30562 * @param {Object} dropEvent
30564 "beforenodedrop" : true,
30567 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30568 * passed to handlers has the following properties:<br />
30569 * <ul style="padding:5px;padding-left:16px;">
30570 * <li>tree - The TreePanel</li>
30571 * <li>target - The node being targeted for the drop</li>
30572 * <li>data - The drag data from the drag source</li>
30573 * <li>point - The point of the drop - append, above or below</li>
30574 * <li>source - The drag source</li>
30575 * <li>rawEvent - Raw mouse event</li>
30576 * <li>dropNode - Dropped node(s).</li>
30578 * @param {Object} dropEvent
30582 * @event nodedragover
30583 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30584 * passed to handlers has the following properties:<br />
30585 * <ul style="padding:5px;padding-left:16px;">
30586 * <li>tree - The TreePanel</li>
30587 * <li>target - The node being targeted for the drop</li>
30588 * <li>data - The drag data from the drag source</li>
30589 * <li>point - The point of the drop - append, above or below</li>
30590 * <li>source - The drag source</li>
30591 * <li>rawEvent - Raw mouse event</li>
30592 * <li>dropNode - Drop node(s) provided by the source.</li>
30593 * <li>cancel - Set this to true to signal drop not allowed.</li>
30595 * @param {Object} dragOverEvent
30597 "nodedragover" : true
30600 if(this.singleExpand){
30601 this.on("beforeexpand", this.restrictExpand, this);
30604 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30605 rootVisible : true,
30606 animate: Roo.enableFx,
30609 hlDrop : Roo.enableFx,
30613 rendererTip: false,
30615 restrictExpand : function(node){
30616 var p = node.parentNode;
30618 if(p.expandedChild && p.expandedChild.parentNode == p){
30619 p.expandedChild.collapse();
30621 p.expandedChild = node;
30625 // private override
30626 setRootNode : function(node){
30627 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30628 if(!this.rootVisible){
30629 node.ui = new Roo.tree.RootTreeNodeUI(node);
30635 * Returns the container element for this TreePanel
30637 getEl : function(){
30642 * Returns the default TreeLoader for this TreePanel
30644 getLoader : function(){
30645 return this.loader;
30651 expandAll : function(){
30652 this.root.expand(true);
30656 * Collapse all nodes
30658 collapseAll : function(){
30659 this.root.collapse(true);
30663 * Returns the selection model used by this TreePanel
30665 getSelectionModel : function(){
30666 if(!this.selModel){
30667 this.selModel = new Roo.tree.DefaultSelectionModel();
30669 return this.selModel;
30673 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30674 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30675 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30678 getChecked : function(a, startNode){
30679 startNode = startNode || this.root;
30681 var f = function(){
30682 if(this.attributes.checked){
30683 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30686 startNode.cascade(f);
30691 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30692 * @param {String} path
30693 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30694 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
30695 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
30697 expandPath : function(path, attr, callback){
30698 attr = attr || "id";
30699 var keys = path.split(this.pathSeparator);
30700 var curNode = this.root;
30701 if(curNode.attributes[attr] != keys[1]){ // invalid root
30703 callback(false, null);
30708 var f = function(){
30709 if(++index == keys.length){
30711 callback(true, curNode);
30715 var c = curNode.findChild(attr, keys[index]);
30718 callback(false, curNode);
30723 c.expand(false, false, f);
30725 curNode.expand(false, false, f);
30729 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30730 * @param {String} path
30731 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30732 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
30733 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
30735 selectPath : function(path, attr, callback){
30736 attr = attr || "id";
30737 var keys = path.split(this.pathSeparator);
30738 var v = keys.pop();
30739 if(keys.length > 0){
30740 var f = function(success, node){
30741 if(success && node){
30742 var n = node.findChild(attr, v);
30748 }else if(callback){
30749 callback(false, n);
30753 callback(false, n);
30757 this.expandPath(keys.join(this.pathSeparator), attr, f);
30759 this.root.select();
30761 callback(true, this.root);
30766 getTreeEl : function(){
30771 * Trigger rendering of this TreePanel
30773 render : function(){
30774 if (this.innerCt) {
30775 return this; // stop it rendering more than once!!
30778 this.innerCt = this.el.createChild({tag:"ul",
30779 cls:"x-tree-root-ct " +
30780 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
30782 if(this.containerScroll){
30783 Roo.dd.ScrollManager.register(this.el);
30785 if((this.enableDD || this.enableDrop) && !this.dropZone){
30787 * The dropZone used by this tree if drop is enabled
30788 * @type Roo.tree.TreeDropZone
30790 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
30791 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
30794 if((this.enableDD || this.enableDrag) && !this.dragZone){
30796 * The dragZone used by this tree if drag is enabled
30797 * @type Roo.tree.TreeDragZone
30799 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
30800 ddGroup: this.ddGroup || "TreeDD",
30801 scroll: this.ddScroll
30804 this.getSelectionModel().init(this);
30806 console.log("ROOT not set in tree");
30809 this.root.render();
30810 if(!this.rootVisible){
30811 this.root.renderChildren();
30817 * Ext JS Library 1.1.1
30818 * Copyright(c) 2006-2007, Ext JS, LLC.
30820 * Originally Released Under LGPL - original licence link has changed is not relivant.
30823 * <script type="text/javascript">
30828 * @class Roo.tree.DefaultSelectionModel
30829 * @extends Roo.util.Observable
30830 * The default single selection for a TreePanel.
30832 Roo.tree.DefaultSelectionModel = function(){
30833 this.selNode = null;
30837 * @event selectionchange
30838 * Fires when the selected node changes
30839 * @param {DefaultSelectionModel} this
30840 * @param {TreeNode} node the new selection
30842 "selectionchange" : true,
30845 * @event beforeselect
30846 * Fires before the selected node changes, return false to cancel the change
30847 * @param {DefaultSelectionModel} this
30848 * @param {TreeNode} node the new selection
30849 * @param {TreeNode} node the old selection
30851 "beforeselect" : true
30855 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
30856 init : function(tree){
30858 tree.getTreeEl().on("keydown", this.onKeyDown, this);
30859 tree.on("click", this.onNodeClick, this);
30862 onNodeClick : function(node, e){
30863 if (e.ctrlKey && this.selNode == node) {
30864 this.unselect(node);
30872 * @param {TreeNode} node The node to select
30873 * @return {TreeNode} The selected node
30875 select : function(node){
30876 var last = this.selNode;
30877 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
30879 last.ui.onSelectedChange(false);
30881 this.selNode = node;
30882 node.ui.onSelectedChange(true);
30883 this.fireEvent("selectionchange", this, node, last);
30890 * @param {TreeNode} node The node to unselect
30892 unselect : function(node){
30893 if(this.selNode == node){
30894 this.clearSelections();
30899 * Clear all selections
30901 clearSelections : function(){
30902 var n = this.selNode;
30904 n.ui.onSelectedChange(false);
30905 this.selNode = null;
30906 this.fireEvent("selectionchange", this, null);
30912 * Get the selected node
30913 * @return {TreeNode} The selected node
30915 getSelectedNode : function(){
30916 return this.selNode;
30920 * Returns true if the node is selected
30921 * @param {TreeNode} node The node to check
30922 * @return {Boolean}
30924 isSelected : function(node){
30925 return this.selNode == node;
30929 * Selects the node above the selected node in the tree, intelligently walking the nodes
30930 * @return TreeNode The new selection
30932 selectPrevious : function(){
30933 var s = this.selNode || this.lastSelNode;
30937 var ps = s.previousSibling;
30939 if(!ps.isExpanded() || ps.childNodes.length < 1){
30940 return this.select(ps);
30942 var lc = ps.lastChild;
30943 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
30946 return this.select(lc);
30948 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
30949 return this.select(s.parentNode);
30955 * Selects the node above the selected node in the tree, intelligently walking the nodes
30956 * @return TreeNode The new selection
30958 selectNext : function(){
30959 var s = this.selNode || this.lastSelNode;
30963 if(s.firstChild && s.isExpanded()){
30964 return this.select(s.firstChild);
30965 }else if(s.nextSibling){
30966 return this.select(s.nextSibling);
30967 }else if(s.parentNode){
30969 s.parentNode.bubble(function(){
30970 if(this.nextSibling){
30971 newS = this.getOwnerTree().selModel.select(this.nextSibling);
30980 onKeyDown : function(e){
30981 var s = this.selNode || this.lastSelNode;
30982 // undesirable, but required
30987 var k = e.getKey();
30995 this.selectPrevious();
30998 e.preventDefault();
30999 if(s.hasChildNodes()){
31000 if(!s.isExpanded()){
31002 }else if(s.firstChild){
31003 this.select(s.firstChild, e);
31008 e.preventDefault();
31009 if(s.hasChildNodes() && s.isExpanded()){
31011 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31012 this.select(s.parentNode, e);
31020 * @class Roo.tree.MultiSelectionModel
31021 * @extends Roo.util.Observable
31022 * Multi selection for a TreePanel.
31024 Roo.tree.MultiSelectionModel = function(){
31025 this.selNodes = [];
31029 * @event selectionchange
31030 * Fires when the selected nodes change
31031 * @param {MultiSelectionModel} this
31032 * @param {Array} nodes Array of the selected nodes
31034 "selectionchange" : true
31038 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31039 init : function(tree){
31041 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31042 tree.on("click", this.onNodeClick, this);
31045 onNodeClick : function(node, e){
31046 this.select(node, e, e.ctrlKey);
31051 * @param {TreeNode} node The node to select
31052 * @param {EventObject} e (optional) An event associated with the selection
31053 * @param {Boolean} keepExisting True to retain existing selections
31054 * @return {TreeNode} The selected node
31056 select : function(node, e, keepExisting){
31057 if(keepExisting !== true){
31058 this.clearSelections(true);
31060 if(this.isSelected(node)){
31061 this.lastSelNode = node;
31064 this.selNodes.push(node);
31065 this.selMap[node.id] = node;
31066 this.lastSelNode = node;
31067 node.ui.onSelectedChange(true);
31068 this.fireEvent("selectionchange", this, this.selNodes);
31074 * @param {TreeNode} node The node to unselect
31076 unselect : function(node){
31077 if(this.selMap[node.id]){
31078 node.ui.onSelectedChange(false);
31079 var sn = this.selNodes;
31082 index = sn.indexOf(node);
31084 for(var i = 0, len = sn.length; i < len; i++){
31092 this.selNodes.splice(index, 1);
31094 delete this.selMap[node.id];
31095 this.fireEvent("selectionchange", this, this.selNodes);
31100 * Clear all selections
31102 clearSelections : function(suppressEvent){
31103 var sn = this.selNodes;
31105 for(var i = 0, len = sn.length; i < len; i++){
31106 sn[i].ui.onSelectedChange(false);
31108 this.selNodes = [];
31110 if(suppressEvent !== true){
31111 this.fireEvent("selectionchange", this, this.selNodes);
31117 * Returns true if the node is selected
31118 * @param {TreeNode} node The node to check
31119 * @return {Boolean}
31121 isSelected : function(node){
31122 return this.selMap[node.id] ? true : false;
31126 * Returns an array of the selected nodes
31129 getSelectedNodes : function(){
31130 return this.selNodes;
31133 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31135 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31137 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31140 * Ext JS Library 1.1.1
31141 * Copyright(c) 2006-2007, Ext JS, LLC.
31143 * Originally Released Under LGPL - original licence link has changed is not relivant.
31146 * <script type="text/javascript">
31150 * @class Roo.tree.TreeNode
31151 * @extends Roo.data.Node
31152 * @cfg {String} text The text for this node
31153 * @cfg {Boolean} expanded true to start the node expanded
31154 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31155 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31156 * @cfg {Boolean} disabled true to start the node disabled
31157 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31158 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31159 * @cfg {String} cls A css class to be added to the node
31160 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31161 * @cfg {String} href URL of the link used for the node (defaults to #)
31162 * @cfg {String} hrefTarget target frame for the link
31163 * @cfg {String} qtip An Ext QuickTip for the node
31164 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31165 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31166 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31167 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31168 * (defaults to undefined with no checkbox rendered)
31170 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31172 Roo.tree.TreeNode = function(attributes){
31173 attributes = attributes || {};
31174 if(typeof attributes == "string"){
31175 attributes = {text: attributes};
31177 this.childrenRendered = false;
31178 this.rendered = false;
31179 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31180 this.expanded = attributes.expanded === true;
31181 this.isTarget = attributes.isTarget !== false;
31182 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31183 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31186 * Read-only. The text for this node. To change it use setText().
31189 this.text = attributes.text;
31191 * True if this node is disabled.
31194 this.disabled = attributes.disabled === true;
31198 * @event textchange
31199 * Fires when the text for this node is changed
31200 * @param {Node} this This node
31201 * @param {String} text The new text
31202 * @param {String} oldText The old text
31204 "textchange" : true,
31206 * @event beforeexpand
31207 * Fires before this node is expanded, return false to cancel.
31208 * @param {Node} this This node
31209 * @param {Boolean} deep
31210 * @param {Boolean} anim
31212 "beforeexpand" : true,
31214 * @event beforecollapse
31215 * Fires before this node is collapsed, return false to cancel.
31216 * @param {Node} this This node
31217 * @param {Boolean} deep
31218 * @param {Boolean} anim
31220 "beforecollapse" : true,
31223 * Fires when this node is expanded
31224 * @param {Node} this This node
31228 * @event disabledchange
31229 * Fires when the disabled status of this node changes
31230 * @param {Node} this This node
31231 * @param {Boolean} disabled
31233 "disabledchange" : true,
31236 * Fires when this node is collapsed
31237 * @param {Node} this This node
31241 * @event beforeclick
31242 * Fires before click processing. Return false to cancel the default action.
31243 * @param {Node} this This node
31244 * @param {Roo.EventObject} e The event object
31246 "beforeclick":true,
31248 * @event checkchange
31249 * Fires when a node with a checkbox's checked property changes
31250 * @param {Node} this This node
31251 * @param {Boolean} checked
31253 "checkchange":true,
31256 * Fires when this node is clicked
31257 * @param {Node} this This node
31258 * @param {Roo.EventObject} e The event object
31263 * Fires when this node is double clicked
31264 * @param {Node} this This node
31265 * @param {Roo.EventObject} e The event object
31269 * @event contextmenu
31270 * Fires when this node is right clicked
31271 * @param {Node} this This node
31272 * @param {Roo.EventObject} e The event object
31274 "contextmenu":true,
31276 * @event beforechildrenrendered
31277 * Fires right before the child nodes for this node are rendered
31278 * @param {Node} this This node
31280 "beforechildrenrendered":true
31283 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31286 * Read-only. The UI for this node
31289 this.ui = new uiClass(this);
31291 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31292 preventHScroll: true,
31294 * Returns true if this node is expanded
31295 * @return {Boolean}
31297 isExpanded : function(){
31298 return this.expanded;
31302 * Returns the UI object for this node
31303 * @return {TreeNodeUI}
31305 getUI : function(){
31309 // private override
31310 setFirstChild : function(node){
31311 var of = this.firstChild;
31312 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31313 if(this.childrenRendered && of && node != of){
31314 of.renderIndent(true, true);
31317 this.renderIndent(true, true);
31321 // private override
31322 setLastChild : function(node){
31323 var ol = this.lastChild;
31324 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31325 if(this.childrenRendered && ol && node != ol){
31326 ol.renderIndent(true, true);
31329 this.renderIndent(true, true);
31333 // these methods are overridden to provide lazy rendering support
31334 // private override
31335 appendChild : function(){
31336 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31337 if(node && this.childrenRendered){
31340 this.ui.updateExpandIcon();
31344 // private override
31345 removeChild : function(node){
31346 this.ownerTree.getSelectionModel().unselect(node);
31347 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31348 // if it's been rendered remove dom node
31349 if(this.childrenRendered){
31352 if(this.childNodes.length < 1){
31353 this.collapse(false, false);
31355 this.ui.updateExpandIcon();
31357 if(!this.firstChild) {
31358 this.childrenRendered = false;
31363 // private override
31364 insertBefore : function(node, refNode){
31365 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31366 if(newNode && refNode && this.childrenRendered){
31369 this.ui.updateExpandIcon();
31374 * Sets the text for this node
31375 * @param {String} text
31377 setText : function(text){
31378 var oldText = this.text;
31380 this.attributes.text = text;
31381 if(this.rendered){ // event without subscribing
31382 this.ui.onTextChange(this, text, oldText);
31384 this.fireEvent("textchange", this, text, oldText);
31388 * Triggers selection of this node
31390 select : function(){
31391 this.getOwnerTree().getSelectionModel().select(this);
31395 * Triggers deselection of this node
31397 unselect : function(){
31398 this.getOwnerTree().getSelectionModel().unselect(this);
31402 * Returns true if this node is selected
31403 * @return {Boolean}
31405 isSelected : function(){
31406 return this.getOwnerTree().getSelectionModel().isSelected(this);
31410 * Expand this node.
31411 * @param {Boolean} deep (optional) True to expand all children as well
31412 * @param {Boolean} anim (optional) false to cancel the default animation
31413 * @param {Function} callback (optional) A callback to be called when
31414 * expanding this node completes (does not wait for deep expand to complete).
31415 * Called with 1 parameter, this node.
31417 expand : function(deep, anim, callback){
31418 if(!this.expanded){
31419 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31422 if(!this.childrenRendered){
31423 this.renderChildren();
31425 this.expanded = true;
31426 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31427 this.ui.animExpand(function(){
31428 this.fireEvent("expand", this);
31429 if(typeof callback == "function"){
31433 this.expandChildNodes(true);
31435 }.createDelegate(this));
31439 this.fireEvent("expand", this);
31440 if(typeof callback == "function"){
31445 if(typeof callback == "function"){
31450 this.expandChildNodes(true);
31454 isHiddenRoot : function(){
31455 return this.isRoot && !this.getOwnerTree().rootVisible;
31459 * Collapse this node.
31460 * @param {Boolean} deep (optional) True to collapse all children as well
31461 * @param {Boolean} anim (optional) false to cancel the default animation
31463 collapse : function(deep, anim){
31464 if(this.expanded && !this.isHiddenRoot()){
31465 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31468 this.expanded = false;
31469 if((this.getOwnerTree().animate && anim !== false) || anim){
31470 this.ui.animCollapse(function(){
31471 this.fireEvent("collapse", this);
31473 this.collapseChildNodes(true);
31475 }.createDelegate(this));
31478 this.ui.collapse();
31479 this.fireEvent("collapse", this);
31483 var cs = this.childNodes;
31484 for(var i = 0, len = cs.length; i < len; i++) {
31485 cs[i].collapse(true, false);
31491 delayedExpand : function(delay){
31492 if(!this.expandProcId){
31493 this.expandProcId = this.expand.defer(delay, this);
31498 cancelExpand : function(){
31499 if(this.expandProcId){
31500 clearTimeout(this.expandProcId);
31502 this.expandProcId = false;
31506 * Toggles expanded/collapsed state of the node
31508 toggle : function(){
31517 * Ensures all parent nodes are expanded
31519 ensureVisible : function(callback){
31520 var tree = this.getOwnerTree();
31521 tree.expandPath(this.parentNode.getPath(), false, function(){
31522 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31523 Roo.callback(callback);
31524 }.createDelegate(this));
31528 * Expand all child nodes
31529 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31531 expandChildNodes : function(deep){
31532 var cs = this.childNodes;
31533 for(var i = 0, len = cs.length; i < len; i++) {
31534 cs[i].expand(deep);
31539 * Collapse all child nodes
31540 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31542 collapseChildNodes : function(deep){
31543 var cs = this.childNodes;
31544 for(var i = 0, len = cs.length; i < len; i++) {
31545 cs[i].collapse(deep);
31550 * Disables this node
31552 disable : function(){
31553 this.disabled = true;
31555 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31556 this.ui.onDisableChange(this, true);
31558 this.fireEvent("disabledchange", this, true);
31562 * Enables this node
31564 enable : function(){
31565 this.disabled = false;
31566 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31567 this.ui.onDisableChange(this, false);
31569 this.fireEvent("disabledchange", this, false);
31573 renderChildren : function(suppressEvent){
31574 if(suppressEvent !== false){
31575 this.fireEvent("beforechildrenrendered", this);
31577 var cs = this.childNodes;
31578 for(var i = 0, len = cs.length; i < len; i++){
31579 cs[i].render(true);
31581 this.childrenRendered = true;
31585 sort : function(fn, scope){
31586 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31587 if(this.childrenRendered){
31588 var cs = this.childNodes;
31589 for(var i = 0, len = cs.length; i < len; i++){
31590 cs[i].render(true);
31596 render : function(bulkRender){
31597 this.ui.render(bulkRender);
31598 if(!this.rendered){
31599 this.rendered = true;
31601 this.expanded = false;
31602 this.expand(false, false);
31608 renderIndent : function(deep, refresh){
31610 this.ui.childIndent = null;
31612 this.ui.renderIndent();
31613 if(deep === true && this.childrenRendered){
31614 var cs = this.childNodes;
31615 for(var i = 0, len = cs.length; i < len; i++){
31616 cs[i].renderIndent(true, refresh);
31622 * Ext JS Library 1.1.1
31623 * Copyright(c) 2006-2007, Ext JS, LLC.
31625 * Originally Released Under LGPL - original licence link has changed is not relivant.
31628 * <script type="text/javascript">
31632 * @class Roo.tree.AsyncTreeNode
31633 * @extends Roo.tree.TreeNode
31634 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31636 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31638 Roo.tree.AsyncTreeNode = function(config){
31639 this.loaded = false;
31640 this.loading = false;
31641 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31643 * @event beforeload
31644 * Fires before this node is loaded, return false to cancel
31645 * @param {Node} this This node
31647 this.addEvents({'beforeload':true, 'load': true});
31650 * Fires when this node is loaded
31651 * @param {Node} this This node
31654 * The loader used by this node (defaults to using the tree's defined loader)
31659 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31660 expand : function(deep, anim, callback){
31661 if(this.loading){ // if an async load is already running, waiting til it's done
31663 var f = function(){
31664 if(!this.loading){ // done loading
31665 clearInterval(timer);
31666 this.expand(deep, anim, callback);
31668 }.createDelegate(this);
31669 timer = setInterval(f, 200);
31673 if(this.fireEvent("beforeload", this) === false){
31676 this.loading = true;
31677 this.ui.beforeLoad(this);
31678 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31680 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31684 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31688 * Returns true if this node is currently loading
31689 * @return {Boolean}
31691 isLoading : function(){
31692 return this.loading;
31695 loadComplete : function(deep, anim, callback){
31696 this.loading = false;
31697 this.loaded = true;
31698 this.ui.afterLoad(this);
31699 this.fireEvent("load", this);
31700 this.expand(deep, anim, callback);
31704 * Returns true if this node has been loaded
31705 * @return {Boolean}
31707 isLoaded : function(){
31708 return this.loaded;
31711 hasChildNodes : function(){
31712 if(!this.isLeaf() && !this.loaded){
31715 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
31720 * Trigger a reload for this node
31721 * @param {Function} callback
31723 reload : function(callback){
31724 this.collapse(false, false);
31725 while(this.firstChild){
31726 this.removeChild(this.firstChild);
31728 this.childrenRendered = false;
31729 this.loaded = false;
31730 if(this.isHiddenRoot()){
31731 this.expanded = false;
31733 this.expand(false, false, callback);
31737 * Ext JS Library 1.1.1
31738 * Copyright(c) 2006-2007, Ext JS, LLC.
31740 * Originally Released Under LGPL - original licence link has changed is not relivant.
31743 * <script type="text/javascript">
31747 * @class Roo.tree.TreeNodeUI
31749 * @param {Object} node The node to render
31750 * The TreeNode UI implementation is separate from the
31751 * tree implementation. Unless you are customizing the tree UI,
31752 * you should never have to use this directly.
31754 Roo.tree.TreeNodeUI = function(node){
31756 this.rendered = false;
31757 this.animating = false;
31758 this.emptyIcon = Roo.BLANK_IMAGE_URL;
31761 Roo.tree.TreeNodeUI.prototype = {
31762 removeChild : function(node){
31764 this.ctNode.removeChild(node.ui.getEl());
31768 beforeLoad : function(){
31769 this.addClass("x-tree-node-loading");
31772 afterLoad : function(){
31773 this.removeClass("x-tree-node-loading");
31776 onTextChange : function(node, text, oldText){
31778 this.textNode.innerHTML = text;
31782 onDisableChange : function(node, state){
31783 this.disabled = state;
31785 this.addClass("x-tree-node-disabled");
31787 this.removeClass("x-tree-node-disabled");
31791 onSelectedChange : function(state){
31794 this.addClass("x-tree-selected");
31797 this.removeClass("x-tree-selected");
31801 onMove : function(tree, node, oldParent, newParent, index, refNode){
31802 this.childIndent = null;
31804 var targetNode = newParent.ui.getContainer();
31805 if(!targetNode){//target not rendered
31806 this.holder = document.createElement("div");
31807 this.holder.appendChild(this.wrap);
31810 var insertBefore = refNode ? refNode.ui.getEl() : null;
31812 targetNode.insertBefore(this.wrap, insertBefore);
31814 targetNode.appendChild(this.wrap);
31816 this.node.renderIndent(true);
31820 addClass : function(cls){
31822 Roo.fly(this.elNode).addClass(cls);
31826 removeClass : function(cls){
31828 Roo.fly(this.elNode).removeClass(cls);
31832 remove : function(){
31834 this.holder = document.createElement("div");
31835 this.holder.appendChild(this.wrap);
31839 fireEvent : function(){
31840 return this.node.fireEvent.apply(this.node, arguments);
31843 initEvents : function(){
31844 this.node.on("move", this.onMove, this);
31845 var E = Roo.EventManager;
31846 var a = this.anchor;
31848 var el = Roo.fly(a, '_treeui');
31850 if(Roo.isOpera){ // opera render bug ignores the CSS
31851 el.setStyle("text-decoration", "none");
31854 el.on("click", this.onClick, this);
31855 el.on("dblclick", this.onDblClick, this);
31858 Roo.EventManager.on(this.checkbox,
31859 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
31862 el.on("contextmenu", this.onContextMenu, this);
31864 var icon = Roo.fly(this.iconNode);
31865 icon.on("click", this.onClick, this);
31866 icon.on("dblclick", this.onDblClick, this);
31867 icon.on("contextmenu", this.onContextMenu, this);
31868 E.on(this.ecNode, "click", this.ecClick, this, true);
31870 if(this.node.disabled){
31871 this.addClass("x-tree-node-disabled");
31873 if(this.node.hidden){
31874 this.addClass("x-tree-node-disabled");
31876 var ot = this.node.getOwnerTree();
31877 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
31878 if(dd && (!this.node.isRoot || ot.rootVisible)){
31879 Roo.dd.Registry.register(this.elNode, {
31881 handles: this.getDDHandles(),
31887 getDDHandles : function(){
31888 return [this.iconNode, this.textNode];
31893 this.wrap.style.display = "none";
31899 this.wrap.style.display = "";
31903 onContextMenu : function(e){
31904 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
31905 e.preventDefault();
31907 this.fireEvent("contextmenu", this.node, e);
31911 onClick : function(e){
31916 if(this.fireEvent("beforeclick", this.node, e) !== false){
31917 if(!this.disabled && this.node.attributes.href){
31918 this.fireEvent("click", this.node, e);
31921 e.preventDefault();
31926 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
31927 this.node.toggle();
31930 this.fireEvent("click", this.node, e);
31936 onDblClick : function(e){
31937 e.preventDefault();
31942 this.toggleCheck();
31944 if(!this.animating && this.node.hasChildNodes()){
31945 this.node.toggle();
31947 this.fireEvent("dblclick", this.node, e);
31950 onCheckChange : function(){
31951 var checked = this.checkbox.checked;
31952 this.node.attributes.checked = checked;
31953 this.fireEvent('checkchange', this.node, checked);
31956 ecClick : function(e){
31957 if(!this.animating && this.node.hasChildNodes()){
31958 this.node.toggle();
31962 startDrop : function(){
31963 this.dropping = true;
31966 // delayed drop so the click event doesn't get fired on a drop
31967 endDrop : function(){
31968 setTimeout(function(){
31969 this.dropping = false;
31970 }.createDelegate(this), 50);
31973 expand : function(){
31974 this.updateExpandIcon();
31975 this.ctNode.style.display = "";
31978 focus : function(){
31979 if(!this.node.preventHScroll){
31980 try{this.anchor.focus();
31982 }else if(!Roo.isIE){
31984 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
31985 var l = noscroll.scrollLeft;
31986 this.anchor.focus();
31987 noscroll.scrollLeft = l;
31992 toggleCheck : function(value){
31993 var cb = this.checkbox;
31995 cb.checked = (value === undefined ? !cb.checked : value);
32001 this.anchor.blur();
32005 animExpand : function(callback){
32006 var ct = Roo.get(this.ctNode);
32008 if(!this.node.hasChildNodes()){
32009 this.updateExpandIcon();
32010 this.ctNode.style.display = "";
32011 Roo.callback(callback);
32014 this.animating = true;
32015 this.updateExpandIcon();
32018 callback : function(){
32019 this.animating = false;
32020 Roo.callback(callback);
32023 duration: this.node.ownerTree.duration || .25
32027 highlight : function(){
32028 var tree = this.node.getOwnerTree();
32029 Roo.fly(this.wrap).highlight(
32030 tree.hlColor || "C3DAF9",
32031 {endColor: tree.hlBaseColor}
32035 collapse : function(){
32036 this.updateExpandIcon();
32037 this.ctNode.style.display = "none";
32040 animCollapse : function(callback){
32041 var ct = Roo.get(this.ctNode);
32042 ct.enableDisplayMode('block');
32045 this.animating = true;
32046 this.updateExpandIcon();
32049 callback : function(){
32050 this.animating = false;
32051 Roo.callback(callback);
32054 duration: this.node.ownerTree.duration || .25
32058 getContainer : function(){
32059 return this.ctNode;
32062 getEl : function(){
32066 appendDDGhost : function(ghostNode){
32067 ghostNode.appendChild(this.elNode.cloneNode(true));
32070 getDDRepairXY : function(){
32071 return Roo.lib.Dom.getXY(this.iconNode);
32074 onRender : function(){
32078 render : function(bulkRender){
32079 var n = this.node, a = n.attributes;
32080 var targetNode = n.parentNode ?
32081 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32083 if(!this.rendered){
32084 this.rendered = true;
32086 this.renderElements(n, a, targetNode, bulkRender);
32089 if(this.textNode.setAttributeNS){
32090 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32092 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32095 this.textNode.setAttribute("ext:qtip", a.qtip);
32097 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32100 }else if(a.qtipCfg){
32101 a.qtipCfg.target = Roo.id(this.textNode);
32102 Roo.QuickTips.register(a.qtipCfg);
32105 if(!this.node.expanded){
32106 this.updateExpandIcon();
32109 if(bulkRender === true) {
32110 targetNode.appendChild(this.wrap);
32115 renderElements : function(n, a, targetNode, bulkRender){
32116 // add some indent caching, this helps performance when rendering a large tree
32117 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32118 var t = n.getOwnerTree();
32119 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32120 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32121 var cb = typeof a.checked == 'boolean';
32122 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32123 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32124 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32125 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32126 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32127 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32128 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32129 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32130 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32131 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32134 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32135 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32136 n.nextSibling.ui.getEl(), buf.join(""));
32138 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32141 this.elNode = this.wrap.childNodes[0];
32142 this.ctNode = this.wrap.childNodes[1];
32143 var cs = this.elNode.childNodes;
32144 this.indentNode = cs[0];
32145 this.ecNode = cs[1];
32146 this.iconNode = cs[2];
32149 this.checkbox = cs[3];
32152 this.anchor = cs[index];
32153 this.textNode = cs[index].firstChild;
32156 getAnchor : function(){
32157 return this.anchor;
32160 getTextEl : function(){
32161 return this.textNode;
32164 getIconEl : function(){
32165 return this.iconNode;
32168 isChecked : function(){
32169 return this.checkbox ? this.checkbox.checked : false;
32172 updateExpandIcon : function(){
32174 var n = this.node, c1, c2;
32175 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32176 var hasChild = n.hasChildNodes();
32180 c1 = "x-tree-node-collapsed";
32181 c2 = "x-tree-node-expanded";
32184 c1 = "x-tree-node-expanded";
32185 c2 = "x-tree-node-collapsed";
32188 this.removeClass("x-tree-node-leaf");
32189 this.wasLeaf = false;
32191 if(this.c1 != c1 || this.c2 != c2){
32192 Roo.fly(this.elNode).replaceClass(c1, c2);
32193 this.c1 = c1; this.c2 = c2;
32197 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32200 this.wasLeaf = true;
32203 var ecc = "x-tree-ec-icon "+cls;
32204 if(this.ecc != ecc){
32205 this.ecNode.className = ecc;
32211 getChildIndent : function(){
32212 if(!this.childIndent){
32216 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32218 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32220 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32225 this.childIndent = buf.join("");
32227 return this.childIndent;
32230 renderIndent : function(){
32233 var p = this.node.parentNode;
32235 indent = p.ui.getChildIndent();
32237 if(this.indentMarkup != indent){ // don't rerender if not required
32238 this.indentNode.innerHTML = indent;
32239 this.indentMarkup = indent;
32241 this.updateExpandIcon();
32246 Roo.tree.RootTreeNodeUI = function(){
32247 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32249 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32250 render : function(){
32251 if(!this.rendered){
32252 var targetNode = this.node.ownerTree.innerCt.dom;
32253 this.node.expanded = true;
32254 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32255 this.wrap = this.ctNode = targetNode.firstChild;
32258 collapse : function(){
32260 expand : function(){
32264 * Ext JS Library 1.1.1
32265 * Copyright(c) 2006-2007, Ext JS, LLC.
32267 * Originally Released Under LGPL - original licence link has changed is not relivant.
32270 * <script type="text/javascript">
32273 * @class Roo.tree.TreeLoader
32274 * @extends Roo.util.Observable
32275 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32276 * nodes from a specified URL. The response must be a javascript Array definition
32277 * who's elements are node definition objects. eg:
32279 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32280 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32283 * A server request is sent, and child nodes are loaded only when a node is expanded.
32284 * The loading node's id is passed to the server under the parameter name "node" to
32285 * enable the server to produce the correct child nodes.
32287 * To pass extra parameters, an event handler may be attached to the "beforeload"
32288 * event, and the parameters specified in the TreeLoader's baseParams property:
32290 myTreeLoader.on("beforeload", function(treeLoader, node) {
32291 this.baseParams.category = node.attributes.category;
32294 * This would pass an HTTP parameter called "category" to the server containing
32295 * the value of the Node's "category" attribute.
32297 * Creates a new Treeloader.
32298 * @param {Object} config A config object containing config properties.
32300 Roo.tree.TreeLoader = function(config){
32301 this.baseParams = {};
32302 this.requestMethod = "POST";
32303 Roo.apply(this, config);
32308 * @event beforeload
32309 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32310 * @param {Object} This TreeLoader object.
32311 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32312 * @param {Object} callback The callback function specified in the {@link #load} call.
32317 * Fires when the node has been successfuly loaded.
32318 * @param {Object} This TreeLoader object.
32319 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32320 * @param {Object} response The response object containing the data from the server.
32324 * @event loadexception
32325 * Fires if the network request failed.
32326 * @param {Object} This TreeLoader object.
32327 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32328 * @param {Object} response The response object containing the data from the server.
32330 loadexception : true,
32333 * Fires before a node is created, enabling you to return custom Node types
32334 * @param {Object} This TreeLoader object.
32335 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32340 Roo.tree.TreeLoader.superclass.constructor.call(this);
32343 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32345 * @cfg {String} dataUrl The URL from which to request a Json string which
32346 * specifies an array of node definition object representing the child nodes
32350 * @cfg {Object} baseParams (optional) An object containing properties which
32351 * specify HTTP parameters to be passed to each request for child nodes.
32354 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32355 * created by this loader. If the attributes sent by the server have an attribute in this object,
32356 * they take priority.
32359 * @cfg {Object} uiProviders (optional) An object containing properties which
32361 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32362 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32363 * <i>uiProvider</i> attribute of a returned child node is a string rather
32364 * than a reference to a TreeNodeUI implementation, this that string value
32365 * is used as a property name in the uiProviders object. You can define the provider named
32366 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32371 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32372 * child nodes before loading.
32374 clearOnLoad : true,
32377 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32378 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32379 * Grid query { data : [ .....] }
32384 * @cfg {String} queryParam (optional)
32385 * Name of the query as it will be passed on the querystring (defaults to 'node')
32386 * eg. the request will be ?node=[id]
32393 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32394 * This is called automatically when a node is expanded, but may be used to reload
32395 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32396 * @param {Roo.tree.TreeNode} node
32397 * @param {Function} callback
32399 load : function(node, callback){
32400 if(this.clearOnLoad){
32401 while(node.firstChild){
32402 node.removeChild(node.firstChild);
32405 if(node.attributes.children){ // preloaded json children
32406 var cs = node.attributes.children;
32407 for(var i = 0, len = cs.length; i < len; i++){
32408 node.appendChild(this.createNode(cs[i]));
32410 if(typeof callback == "function"){
32413 }else if(this.dataUrl){
32414 this.requestData(node, callback);
32418 getParams: function(node){
32419 var buf = [], bp = this.baseParams;
32420 for(var key in bp){
32421 if(typeof bp[key] != "function"){
32422 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32425 var n = this.queryParam === false ? 'node' : this.queryParam;
32426 buf.push(n + "=", encodeURIComponent(node.id));
32427 return buf.join("");
32430 requestData : function(node, callback){
32431 if(this.fireEvent("beforeload", this, node, callback) !== false){
32432 this.transId = Roo.Ajax.request({
32433 method:this.requestMethod,
32434 url: this.dataUrl||this.url,
32435 success: this.handleResponse,
32436 failure: this.handleFailure,
32438 argument: {callback: callback, node: node},
32439 params: this.getParams(node)
32442 // if the load is cancelled, make sure we notify
32443 // the node that we are done
32444 if(typeof callback == "function"){
32450 isLoading : function(){
32451 return this.transId ? true : false;
32454 abort : function(){
32455 if(this.isLoading()){
32456 Roo.Ajax.abort(this.transId);
32461 createNode : function(attr){
32462 // apply baseAttrs, nice idea Corey!
32463 if(this.baseAttrs){
32464 Roo.applyIf(attr, this.baseAttrs);
32466 if(this.applyLoader !== false){
32467 attr.loader = this;
32469 // uiProvider = depreciated..
32471 if(typeof(attr.uiProvider) == 'string'){
32472 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32473 /** eval:var:attr */ eval(attr.uiProvider);
32475 if(typeof(this.uiProviders['default']) != 'undefined') {
32476 attr.uiProvider = this.uiProviders['default'];
32479 this.fireEvent('create', this, attr);
32481 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32483 new Roo.tree.TreeNode(attr) :
32484 new Roo.tree.AsyncTreeNode(attr));
32487 processResponse : function(response, node, callback){
32488 var json = response.responseText;
32491 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32492 if (this.root !== false) {
32496 for(var i = 0, len = o.length; i < len; i++){
32497 var n = this.createNode(o[i]);
32499 node.appendChild(n);
32502 if(typeof callback == "function"){
32503 callback(this, node);
32506 this.handleFailure(response);
32510 handleResponse : function(response){
32511 this.transId = false;
32512 var a = response.argument;
32513 this.processResponse(response, a.node, a.callback);
32514 this.fireEvent("load", this, a.node, response);
32517 handleFailure : function(response){
32518 this.transId = false;
32519 var a = response.argument;
32520 this.fireEvent("loadexception", this, a.node, response);
32521 if(typeof a.callback == "function"){
32522 a.callback(this, a.node);
32527 * Ext JS Library 1.1.1
32528 * Copyright(c) 2006-2007, Ext JS, LLC.
32530 * Originally Released Under LGPL - original licence link has changed is not relivant.
32533 * <script type="text/javascript">
32537 * @class Roo.tree.TreeFilter
32538 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32539 * @param {TreePanel} tree
32540 * @param {Object} config (optional)
32542 Roo.tree.TreeFilter = function(tree, config){
32544 this.filtered = {};
32545 Roo.apply(this, config);
32548 Roo.tree.TreeFilter.prototype = {
32555 * Filter the data by a specific attribute.
32556 * @param {String/RegExp} value Either string that the attribute value
32557 * should start with or a RegExp to test against the attribute
32558 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32559 * @param {TreeNode} startNode (optional) The node to start the filter at.
32561 filter : function(value, attr, startNode){
32562 attr = attr || "text";
32564 if(typeof value == "string"){
32565 var vlen = value.length;
32566 // auto clear empty filter
32567 if(vlen == 0 && this.clearBlank){
32571 value = value.toLowerCase();
32573 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32575 }else if(value.exec){ // regex?
32577 return value.test(n.attributes[attr]);
32580 throw 'Illegal filter type, must be string or regex';
32582 this.filterBy(f, null, startNode);
32586 * Filter by a function. The passed function will be called with each
32587 * node in the tree (or from the startNode). If the function returns true, the node is kept
32588 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32589 * @param {Function} fn The filter function
32590 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32592 filterBy : function(fn, scope, startNode){
32593 startNode = startNode || this.tree.root;
32594 if(this.autoClear){
32597 var af = this.filtered, rv = this.reverse;
32598 var f = function(n){
32599 if(n == startNode){
32605 var m = fn.call(scope || n, n);
32613 startNode.cascade(f);
32616 if(typeof id != "function"){
32618 if(n && n.parentNode){
32619 n.parentNode.removeChild(n);
32627 * Clears the current filter. Note: with the "remove" option
32628 * set a filter cannot be cleared.
32630 clear : function(){
32632 var af = this.filtered;
32634 if(typeof id != "function"){
32641 this.filtered = {};
32646 * Ext JS Library 1.1.1
32647 * Copyright(c) 2006-2007, Ext JS, LLC.
32649 * Originally Released Under LGPL - original licence link has changed is not relivant.
32652 * <script type="text/javascript">
32657 * @class Roo.tree.TreeSorter
32658 * Provides sorting of nodes in a TreePanel
32660 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32661 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32662 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32663 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32664 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32665 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32667 * @param {TreePanel} tree
32668 * @param {Object} config
32670 Roo.tree.TreeSorter = function(tree, config){
32671 Roo.apply(this, config);
32672 tree.on("beforechildrenrendered", this.doSort, this);
32673 tree.on("append", this.updateSort, this);
32674 tree.on("insert", this.updateSort, this);
32676 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32677 var p = this.property || "text";
32678 var sortType = this.sortType;
32679 var fs = this.folderSort;
32680 var cs = this.caseSensitive === true;
32681 var leafAttr = this.leafAttr || 'leaf';
32683 this.sortFn = function(n1, n2){
32685 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32688 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
32692 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
32693 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
32695 return dsc ? +1 : -1;
32697 return dsc ? -1 : +1;
32704 Roo.tree.TreeSorter.prototype = {
32705 doSort : function(node){
32706 node.sort(this.sortFn);
32709 compareNodes : function(n1, n2){
32710 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
32713 updateSort : function(tree, node){
32714 if(node.childrenRendered){
32715 this.doSort.defer(1, this, [node]);
32720 * Ext JS Library 1.1.1
32721 * Copyright(c) 2006-2007, Ext JS, LLC.
32723 * Originally Released Under LGPL - original licence link has changed is not relivant.
32726 * <script type="text/javascript">
32729 if(Roo.dd.DropZone){
32731 Roo.tree.TreeDropZone = function(tree, config){
32732 this.allowParentInsert = false;
32733 this.allowContainerDrop = false;
32734 this.appendOnly = false;
32735 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
32737 this.lastInsertClass = "x-tree-no-status";
32738 this.dragOverData = {};
32741 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
32742 ddGroup : "TreeDD",
32744 expandDelay : 1000,
32746 expandNode : function(node){
32747 if(node.hasChildNodes() && !node.isExpanded()){
32748 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
32752 queueExpand : function(node){
32753 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
32756 cancelExpand : function(){
32757 if(this.expandProcId){
32758 clearTimeout(this.expandProcId);
32759 this.expandProcId = false;
32763 isValidDropPoint : function(n, pt, dd, e, data){
32764 if(!n || !data){ return false; }
32765 var targetNode = n.node;
32766 var dropNode = data.node;
32767 // default drop rules
32768 if(!(targetNode && targetNode.isTarget && pt)){
32771 if(pt == "append" && targetNode.allowChildren === false){
32774 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
32777 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
32780 // reuse the object
32781 var overEvent = this.dragOverData;
32782 overEvent.tree = this.tree;
32783 overEvent.target = targetNode;
32784 overEvent.data = data;
32785 overEvent.point = pt;
32786 overEvent.source = dd;
32787 overEvent.rawEvent = e;
32788 overEvent.dropNode = dropNode;
32789 overEvent.cancel = false;
32790 var result = this.tree.fireEvent("nodedragover", overEvent);
32791 return overEvent.cancel === false && result !== false;
32794 getDropPoint : function(e, n, dd){
32797 return tn.allowChildren !== false ? "append" : false; // always append for root
32799 var dragEl = n.ddel;
32800 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
32801 var y = Roo.lib.Event.getPageY(e);
32802 var noAppend = tn.allowChildren === false || tn.isLeaf();
32803 if(this.appendOnly || tn.parentNode.allowChildren === false){
32804 return noAppend ? false : "append";
32806 var noBelow = false;
32807 if(!this.allowParentInsert){
32808 noBelow = tn.hasChildNodes() && tn.isExpanded();
32810 var q = (b - t) / (noAppend ? 2 : 3);
32811 if(y >= t && y < (t + q)){
32813 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
32820 onNodeEnter : function(n, dd, e, data){
32821 this.cancelExpand();
32824 onNodeOver : function(n, dd, e, data){
32825 var pt = this.getDropPoint(e, n, dd);
32828 // auto node expand check
32829 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
32830 this.queueExpand(node);
32831 }else if(pt != "append"){
32832 this.cancelExpand();
32835 // set the insert point style on the target node
32836 var returnCls = this.dropNotAllowed;
32837 if(this.isValidDropPoint(n, pt, dd, e, data)){
32842 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
32843 cls = "x-tree-drag-insert-above";
32844 }else if(pt == "below"){
32845 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
32846 cls = "x-tree-drag-insert-below";
32848 returnCls = "x-tree-drop-ok-append";
32849 cls = "x-tree-drag-append";
32851 if(this.lastInsertClass != cls){
32852 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
32853 this.lastInsertClass = cls;
32860 onNodeOut : function(n, dd, e, data){
32861 this.cancelExpand();
32862 this.removeDropIndicators(n);
32865 onNodeDrop : function(n, dd, e, data){
32866 var point = this.getDropPoint(e, n, dd);
32867 var targetNode = n.node;
32868 targetNode.ui.startDrop();
32869 if(!this.isValidDropPoint(n, point, dd, e, data)){
32870 targetNode.ui.endDrop();
32873 // first try to find the drop node
32874 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
32877 target: targetNode,
32882 dropNode: dropNode,
32885 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
32886 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
32887 targetNode.ui.endDrop();
32890 // allow target changing
32891 targetNode = dropEvent.target;
32892 if(point == "append" && !targetNode.isExpanded()){
32893 targetNode.expand(false, null, function(){
32894 this.completeDrop(dropEvent);
32895 }.createDelegate(this));
32897 this.completeDrop(dropEvent);
32902 completeDrop : function(de){
32903 var ns = de.dropNode, p = de.point, t = de.target;
32904 if(!(ns instanceof Array)){
32908 for(var i = 0, len = ns.length; i < len; i++){
32911 t.parentNode.insertBefore(n, t);
32912 }else if(p == "below"){
32913 t.parentNode.insertBefore(n, t.nextSibling);
32919 if(this.tree.hlDrop){
32923 this.tree.fireEvent("nodedrop", de);
32926 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
32927 if(this.tree.hlDrop){
32928 dropNode.ui.focus();
32929 dropNode.ui.highlight();
32931 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
32934 getTree : function(){
32938 removeDropIndicators : function(n){
32941 Roo.fly(el).removeClass([
32942 "x-tree-drag-insert-above",
32943 "x-tree-drag-insert-below",
32944 "x-tree-drag-append"]);
32945 this.lastInsertClass = "_noclass";
32949 beforeDragDrop : function(target, e, id){
32950 this.cancelExpand();
32954 afterRepair : function(data){
32955 if(data && Roo.enableFx){
32956 data.node.ui.highlight();
32964 * Ext JS Library 1.1.1
32965 * Copyright(c) 2006-2007, Ext JS, LLC.
32967 * Originally Released Under LGPL - original licence link has changed is not relivant.
32970 * <script type="text/javascript">
32974 if(Roo.dd.DragZone){
32975 Roo.tree.TreeDragZone = function(tree, config){
32976 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
32980 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
32981 ddGroup : "TreeDD",
32983 onBeforeDrag : function(data, e){
32985 return n && n.draggable && !n.disabled;
32988 onInitDrag : function(e){
32989 var data = this.dragData;
32990 this.tree.getSelectionModel().select(data.node);
32991 this.proxy.update("");
32992 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
32993 this.tree.fireEvent("startdrag", this.tree, data.node, e);
32996 getRepairXY : function(e, data){
32997 return data.node.ui.getDDRepairXY();
33000 onEndDrag : function(data, e){
33001 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33004 onValidDrop : function(dd, e, id){
33005 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33009 beforeInvalidDrop : function(e, id){
33010 // this scrolls the original position back into view
33011 var sm = this.tree.getSelectionModel();
33012 sm.clearSelections();
33013 sm.select(this.dragData.node);
33018 * Ext JS Library 1.1.1
33019 * Copyright(c) 2006-2007, Ext JS, LLC.
33021 * Originally Released Under LGPL - original licence link has changed is not relivant.
33024 * <script type="text/javascript">
33027 * @class Roo.tree.TreeEditor
33028 * @extends Roo.Editor
33029 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33030 * as the editor field.
33032 * @param {TreePanel} tree
33033 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33035 Roo.tree.TreeEditor = function(tree, config){
33036 config = config || {};
33037 var field = config.events ? config : new Roo.form.TextField(config);
33038 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33042 tree.on('beforeclick', this.beforeNodeClick, this);
33043 tree.getTreeEl().on('mousedown', this.hide, this);
33044 this.on('complete', this.updateNode, this);
33045 this.on('beforestartedit', this.fitToTree, this);
33046 this.on('startedit', this.bindScroll, this, {delay:10});
33047 this.on('specialkey', this.onSpecialKey, this);
33050 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33052 * @cfg {String} alignment
33053 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33059 * @cfg {Boolean} hideEl
33060 * True to hide the bound element while the editor is displayed (defaults to false)
33064 * @cfg {String} cls
33065 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33067 cls: "x-small-editor x-tree-editor",
33069 * @cfg {Boolean} shim
33070 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33076 * @cfg {Number} maxWidth
33077 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33078 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33079 * scroll and client offsets into account prior to each edit.
33086 fitToTree : function(ed, el){
33087 var td = this.tree.getTreeEl().dom, nd = el.dom;
33088 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33089 td.scrollLeft = nd.offsetLeft;
33093 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33094 this.setSize(w, '');
33098 triggerEdit : function(node){
33099 this.completeEdit();
33100 this.editNode = node;
33101 this.startEdit(node.ui.textNode, node.text);
33105 bindScroll : function(){
33106 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33110 beforeNodeClick : function(node, e){
33111 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33112 this.lastClick = new Date();
33113 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33115 this.triggerEdit(node);
33121 updateNode : function(ed, value){
33122 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33123 this.editNode.setText(value);
33127 onHide : function(){
33128 Roo.tree.TreeEditor.superclass.onHide.call(this);
33130 this.editNode.ui.focus();
33135 onSpecialKey : function(field, e){
33136 var k = e.getKey();
33140 }else if(k == e.ENTER && !e.hasModifier()){
33142 this.completeEdit();
33145 });//<Script type="text/javascript">
33148 * Ext JS Library 1.1.1
33149 * Copyright(c) 2006-2007, Ext JS, LLC.
33151 * Originally Released Under LGPL - original licence link has changed is not relivant.
33154 * <script type="text/javascript">
33158 * Not documented??? - probably should be...
33161 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33162 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33164 renderElements : function(n, a, targetNode, bulkRender){
33165 //consel.log("renderElements?");
33166 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33168 var t = n.getOwnerTree();
33169 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33171 var cols = t.columns;
33172 var bw = t.borderWidth;
33174 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33175 var cb = typeof a.checked == "boolean";
33176 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33177 var colcls = 'x-t-' + tid + '-c0';
33179 '<li class="x-tree-node">',
33182 '<div class="x-tree-node-el ', a.cls,'">',
33184 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33187 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33188 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33189 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33190 (a.icon ? ' x-tree-node-inline-icon' : ''),
33191 (a.iconCls ? ' '+a.iconCls : ''),
33192 '" unselectable="on" />',
33193 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33194 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33196 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33197 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33198 '<span unselectable="on" qtip="' + tx + '">',
33202 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33203 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33206 for(var i = 1, len = cols.length; i < len; i++){
33208 colcls = 'x-t-' + tid + '-c' +i;
33209 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33210 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33211 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33217 '<div class="x-clear"></div></div>',
33218 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33221 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33222 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33223 n.nextSibling.ui.getEl(), buf.join(""));
33225 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33227 var el = this.wrap.firstChild;
33229 this.elNode = el.firstChild;
33230 this.ranchor = el.childNodes[1];
33231 this.ctNode = this.wrap.childNodes[1];
33232 var cs = el.firstChild.childNodes;
33233 this.indentNode = cs[0];
33234 this.ecNode = cs[1];
33235 this.iconNode = cs[2];
33238 this.checkbox = cs[3];
33241 this.anchor = cs[index];
33243 this.textNode = cs[index].firstChild;
33245 //el.on("click", this.onClick, this);
33246 //el.on("dblclick", this.onDblClick, this);
33249 // console.log(this);
33251 initEvents : function(){
33252 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33255 var a = this.ranchor;
33257 var el = Roo.get(a);
33259 if(Roo.isOpera){ // opera render bug ignores the CSS
33260 el.setStyle("text-decoration", "none");
33263 el.on("click", this.onClick, this);
33264 el.on("dblclick", this.onDblClick, this);
33265 el.on("contextmenu", this.onContextMenu, this);
33269 /*onSelectedChange : function(state){
33272 this.addClass("x-tree-selected");
33275 this.removeClass("x-tree-selected");
33278 addClass : function(cls){
33280 Roo.fly(this.elRow).addClass(cls);
33286 removeClass : function(cls){
33288 Roo.fly(this.elRow).removeClass(cls);
33294 });//<Script type="text/javascript">
33298 * Ext JS Library 1.1.1
33299 * Copyright(c) 2006-2007, Ext JS, LLC.
33301 * Originally Released Under LGPL - original licence link has changed is not relivant.
33304 * <script type="text/javascript">
33309 * @class Roo.tree.ColumnTree
33310 * @extends Roo.data.TreePanel
33311 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33312 * @cfg {int} borderWidth compined right/left border allowance
33314 * @param {String/HTMLElement/Element} el The container element
33315 * @param {Object} config
33317 Roo.tree.ColumnTree = function(el, config)
33319 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33323 * Fire this event on a container when it resizes
33324 * @param {int} w Width
33325 * @param {int} h Height
33329 this.on('resize', this.onResize, this);
33332 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33336 borderWidth: Roo.isBorderBox ? 0 : 2,
33339 render : function(){
33340 // add the header.....
33342 Roo.tree.ColumnTree.superclass.render.apply(this);
33344 this.el.addClass('x-column-tree');
33346 this.headers = this.el.createChild(
33347 {cls:'x-tree-headers'},this.innerCt.dom);
33349 var cols = this.columns, c;
33350 var totalWidth = 0;
33352 var len = cols.length;
33353 for(var i = 0; i < len; i++){
33355 totalWidth += c.width;
33356 this.headEls.push(this.headers.createChild({
33357 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33359 cls:'x-tree-hd-text',
33362 style:'width:'+(c.width-this.borderWidth)+'px;'
33365 this.headers.createChild({cls:'x-clear'});
33366 // prevent floats from wrapping when clipped
33367 this.headers.setWidth(totalWidth);
33368 //this.innerCt.setWidth(totalWidth);
33369 this.innerCt.setStyle({ overflow: 'auto' });
33370 this.onResize(this.width, this.height);
33374 onResize : function(w,h)
33379 this.innerCt.setWidth(this.width);
33380 this.innerCt.setHeight(this.height-20);
33383 var cols = this.columns, c;
33384 var totalWidth = 0;
33386 var len = cols.length;
33387 for(var i = 0; i < len; i++){
33389 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33390 // it's the expander..
33391 expEl = this.headEls[i];
33394 totalWidth += c.width;
33398 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33400 this.headers.setWidth(w-20);
33409 * Ext JS Library 1.1.1
33410 * Copyright(c) 2006-2007, Ext JS, LLC.
33412 * Originally Released Under LGPL - original licence link has changed is not relivant.
33415 * <script type="text/javascript">
33419 * @class Roo.menu.Menu
33420 * @extends Roo.util.Observable
33421 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33422 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33424 * Creates a new Menu
33425 * @param {Object} config Configuration options
33427 Roo.menu.Menu = function(config){
33428 Roo.apply(this, config);
33429 this.id = this.id || Roo.id();
33432 * @event beforeshow
33433 * Fires before this menu is displayed
33434 * @param {Roo.menu.Menu} this
33438 * @event beforehide
33439 * Fires before this menu is hidden
33440 * @param {Roo.menu.Menu} this
33445 * Fires after this menu is displayed
33446 * @param {Roo.menu.Menu} this
33451 * Fires after this menu is hidden
33452 * @param {Roo.menu.Menu} this
33457 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33458 * @param {Roo.menu.Menu} this
33459 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33460 * @param {Roo.EventObject} e
33465 * Fires when the mouse is hovering over this menu
33466 * @param {Roo.menu.Menu} this
33467 * @param {Roo.EventObject} e
33468 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33473 * Fires when the mouse exits this menu
33474 * @param {Roo.menu.Menu} this
33475 * @param {Roo.EventObject} e
33476 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33481 * Fires when a menu item contained in this menu is clicked
33482 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33483 * @param {Roo.EventObject} e
33487 if (this.registerMenu) {
33488 Roo.menu.MenuMgr.register(this);
33491 var mis = this.items;
33492 this.items = new Roo.util.MixedCollection();
33494 this.add.apply(this, mis);
33498 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33500 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33504 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33505 * for bottom-right shadow (defaults to "sides")
33509 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33510 * this menu (defaults to "tl-tr?")
33512 subMenuAlign : "tl-tr?",
33514 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33515 * relative to its element of origin (defaults to "tl-bl?")
33517 defaultAlign : "tl-bl?",
33519 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33521 allowOtherMenus : false,
33523 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33525 registerMenu : true,
33530 render : function(){
33534 var el = this.el = new Roo.Layer({
33536 shadow:this.shadow,
33538 parentEl: this.parentEl || document.body,
33542 this.keyNav = new Roo.menu.MenuNav(this);
33545 el.addClass("x-menu-plain");
33548 el.addClass(this.cls);
33550 // generic focus element
33551 this.focusEl = el.createChild({
33552 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33554 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33555 ul.on("click", this.onClick, this);
33556 ul.on("mouseover", this.onMouseOver, this);
33557 ul.on("mouseout", this.onMouseOut, this);
33558 this.items.each(function(item){
33559 var li = document.createElement("li");
33560 li.className = "x-menu-list-item";
33561 ul.dom.appendChild(li);
33562 item.render(li, this);
33569 autoWidth : function(){
33570 var el = this.el, ul = this.ul;
33574 var w = this.width;
33577 }else if(Roo.isIE){
33578 el.setWidth(this.minWidth);
33579 var t = el.dom.offsetWidth; // force recalc
33580 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33585 delayAutoWidth : function(){
33588 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33590 this.awTask.delay(20);
33595 findTargetItem : function(e){
33596 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33597 if(t && t.menuItemId){
33598 return this.items.get(t.menuItemId);
33603 onClick : function(e){
33605 if(t = this.findTargetItem(e)){
33607 this.fireEvent("click", this, t, e);
33612 setActiveItem : function(item, autoExpand){
33613 if(item != this.activeItem){
33614 if(this.activeItem){
33615 this.activeItem.deactivate();
33617 this.activeItem = item;
33618 item.activate(autoExpand);
33619 }else if(autoExpand){
33625 tryActivate : function(start, step){
33626 var items = this.items;
33627 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33628 var item = items.get(i);
33629 if(!item.disabled && item.canActivate){
33630 this.setActiveItem(item, false);
33638 onMouseOver : function(e){
33640 if(t = this.findTargetItem(e)){
33641 if(t.canActivate && !t.disabled){
33642 this.setActiveItem(t, true);
33645 this.fireEvent("mouseover", this, e, t);
33649 onMouseOut : function(e){
33651 if(t = this.findTargetItem(e)){
33652 if(t == this.activeItem && t.shouldDeactivate(e)){
33653 this.activeItem.deactivate();
33654 delete this.activeItem;
33657 this.fireEvent("mouseout", this, e, t);
33661 * Read-only. Returns true if the menu is currently displayed, else false.
33664 isVisible : function(){
33665 return this.el && !this.hidden;
33669 * Displays this menu relative to another element
33670 * @param {String/HTMLElement/Roo.Element} element The element to align to
33671 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33672 * the element (defaults to this.defaultAlign)
33673 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33675 show : function(el, pos, parentMenu){
33676 this.parentMenu = parentMenu;
33680 this.fireEvent("beforeshow", this);
33681 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33685 * Displays this menu at a specific xy position
33686 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
33687 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33689 showAt : function(xy, parentMenu, /* private: */_e){
33690 this.parentMenu = parentMenu;
33695 this.fireEvent("beforeshow", this);
33696 xy = this.el.adjustForConstraints(xy);
33700 this.hidden = false;
33702 this.fireEvent("show", this);
33705 focus : function(){
33707 this.doFocus.defer(50, this);
33711 doFocus : function(){
33713 this.focusEl.focus();
33718 * Hides this menu and optionally all parent menus
33719 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
33721 hide : function(deep){
33722 if(this.el && this.isVisible()){
33723 this.fireEvent("beforehide", this);
33724 if(this.activeItem){
33725 this.activeItem.deactivate();
33726 this.activeItem = null;
33729 this.hidden = true;
33730 this.fireEvent("hide", this);
33732 if(deep === true && this.parentMenu){
33733 this.parentMenu.hide(true);
33738 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
33739 * Any of the following are valid:
33741 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
33742 * <li>An HTMLElement object which will be converted to a menu item</li>
33743 * <li>A menu item config object that will be created as a new menu item</li>
33744 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
33745 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
33750 var menu = new Roo.menu.Menu();
33752 // Create a menu item to add by reference
33753 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
33755 // Add a bunch of items at once using different methods.
33756 // Only the last item added will be returned.
33757 var item = menu.add(
33758 menuItem, // add existing item by ref
33759 'Dynamic Item', // new TextItem
33760 '-', // new separator
33761 { text: 'Config Item' } // new item by config
33764 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
33765 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
33768 var a = arguments, l = a.length, item;
33769 for(var i = 0; i < l; i++){
33771 if(el.render){ // some kind of Item
33772 item = this.addItem(el);
33773 }else if(typeof el == "string"){ // string
33774 if(el == "separator" || el == "-"){
33775 item = this.addSeparator();
33777 item = this.addText(el);
33779 }else if(el.tagName || el.el){ // element
33780 item = this.addElement(el);
33781 }else if(typeof el == "object"){ // must be menu item config?
33782 item = this.addMenuItem(el);
33789 * Returns this menu's underlying {@link Roo.Element} object
33790 * @return {Roo.Element} The element
33792 getEl : function(){
33800 * Adds a separator bar to the menu
33801 * @return {Roo.menu.Item} The menu item that was added
33803 addSeparator : function(){
33804 return this.addItem(new Roo.menu.Separator());
33808 * Adds an {@link Roo.Element} object to the menu
33809 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
33810 * @return {Roo.menu.Item} The menu item that was added
33812 addElement : function(el){
33813 return this.addItem(new Roo.menu.BaseItem(el));
33817 * Adds an existing object based on {@link Roo.menu.Item} to the menu
33818 * @param {Roo.menu.Item} item The menu item to add
33819 * @return {Roo.menu.Item} The menu item that was added
33821 addItem : function(item){
33822 this.items.add(item);
33824 var li = document.createElement("li");
33825 li.className = "x-menu-list-item";
33826 this.ul.dom.appendChild(li);
33827 item.render(li, this);
33828 this.delayAutoWidth();
33834 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
33835 * @param {Object} config A MenuItem config object
33836 * @return {Roo.menu.Item} The menu item that was added
33838 addMenuItem : function(config){
33839 if(!(config instanceof Roo.menu.Item)){
33840 if(typeof config.checked == "boolean"){ // must be check menu item config?
33841 config = new Roo.menu.CheckItem(config);
33843 config = new Roo.menu.Item(config);
33846 return this.addItem(config);
33850 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
33851 * @param {String} text The text to display in the menu item
33852 * @return {Roo.menu.Item} The menu item that was added
33854 addText : function(text){
33855 return this.addItem(new Roo.menu.TextItem(text));
33859 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
33860 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
33861 * @param {Roo.menu.Item} item The menu item to add
33862 * @return {Roo.menu.Item} The menu item that was added
33864 insert : function(index, item){
33865 this.items.insert(index, item);
33867 var li = document.createElement("li");
33868 li.className = "x-menu-list-item";
33869 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
33870 item.render(li, this);
33871 this.delayAutoWidth();
33877 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
33878 * @param {Roo.menu.Item} item The menu item to remove
33880 remove : function(item){
33881 this.items.removeKey(item.id);
33886 * Removes and destroys all items in the menu
33888 removeAll : function(){
33890 while(f = this.items.first()){
33896 // MenuNav is a private utility class used internally by the Menu
33897 Roo.menu.MenuNav = function(menu){
33898 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
33899 this.scope = this.menu = menu;
33902 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
33903 doRelay : function(e, h){
33904 var k = e.getKey();
33905 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
33906 this.menu.tryActivate(0, 1);
33909 return h.call(this.scope || this, e, this.menu);
33912 up : function(e, m){
33913 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
33914 m.tryActivate(m.items.length-1, -1);
33918 down : function(e, m){
33919 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
33920 m.tryActivate(0, 1);
33924 right : function(e, m){
33926 m.activeItem.expandMenu(true);
33930 left : function(e, m){
33932 if(m.parentMenu && m.parentMenu.activeItem){
33933 m.parentMenu.activeItem.activate();
33937 enter : function(e, m){
33939 e.stopPropagation();
33940 m.activeItem.onClick(e);
33941 m.fireEvent("click", this, m.activeItem);
33947 * Ext JS Library 1.1.1
33948 * Copyright(c) 2006-2007, Ext JS, LLC.
33950 * Originally Released Under LGPL - original licence link has changed is not relivant.
33953 * <script type="text/javascript">
33957 * @class Roo.menu.MenuMgr
33958 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
33961 Roo.menu.MenuMgr = function(){
33962 var menus, active, groups = {}, attached = false, lastShow = new Date();
33964 // private - called when first menu is created
33967 active = new Roo.util.MixedCollection();
33968 Roo.get(document).addKeyListener(27, function(){
33969 if(active.length > 0){
33976 function hideAll(){
33977 if(active && active.length > 0){
33978 var c = active.clone();
33979 c.each(function(m){
33986 function onHide(m){
33988 if(active.length < 1){
33989 Roo.get(document).un("mousedown", onMouseDown);
33995 function onShow(m){
33996 var last = active.last();
33997 lastShow = new Date();
34000 Roo.get(document).on("mousedown", onMouseDown);
34004 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34005 m.parentMenu.activeChild = m;
34006 }else if(last && last.isVisible()){
34007 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34012 function onBeforeHide(m){
34014 m.activeChild.hide();
34016 if(m.autoHideTimer){
34017 clearTimeout(m.autoHideTimer);
34018 delete m.autoHideTimer;
34023 function onBeforeShow(m){
34024 var pm = m.parentMenu;
34025 if(!pm && !m.allowOtherMenus){
34027 }else if(pm && pm.activeChild && active != m){
34028 pm.activeChild.hide();
34033 function onMouseDown(e){
34034 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34040 function onBeforeCheck(mi, state){
34042 var g = groups[mi.group];
34043 for(var i = 0, l = g.length; i < l; i++){
34045 g[i].setChecked(false);
34054 * Hides all menus that are currently visible
34056 hideAll : function(){
34061 register : function(menu){
34065 menus[menu.id] = menu;
34066 menu.on("beforehide", onBeforeHide);
34067 menu.on("hide", onHide);
34068 menu.on("beforeshow", onBeforeShow);
34069 menu.on("show", onShow);
34070 var g = menu.group;
34071 if(g && menu.events["checkchange"]){
34075 groups[g].push(menu);
34076 menu.on("checkchange", onCheck);
34081 * Returns a {@link Roo.menu.Menu} object
34082 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34083 * be used to generate and return a new Menu instance.
34085 get : function(menu){
34086 if(typeof menu == "string"){ // menu id
34087 return menus[menu];
34088 }else if(menu.events){ // menu instance
34090 }else if(typeof menu.length == 'number'){ // array of menu items?
34091 return new Roo.menu.Menu({items:menu});
34092 }else{ // otherwise, must be a config
34093 return new Roo.menu.Menu(menu);
34098 unregister : function(menu){
34099 delete menus[menu.id];
34100 menu.un("beforehide", onBeforeHide);
34101 menu.un("hide", onHide);
34102 menu.un("beforeshow", onBeforeShow);
34103 menu.un("show", onShow);
34104 var g = menu.group;
34105 if(g && menu.events["checkchange"]){
34106 groups[g].remove(menu);
34107 menu.un("checkchange", onCheck);
34112 registerCheckable : function(menuItem){
34113 var g = menuItem.group;
34118 groups[g].push(menuItem);
34119 menuItem.on("beforecheckchange", onBeforeCheck);
34124 unregisterCheckable : function(menuItem){
34125 var g = menuItem.group;
34127 groups[g].remove(menuItem);
34128 menuItem.un("beforecheckchange", onBeforeCheck);
34134 * Ext JS Library 1.1.1
34135 * Copyright(c) 2006-2007, Ext JS, LLC.
34137 * Originally Released Under LGPL - original licence link has changed is not relivant.
34140 * <script type="text/javascript">
34145 * @class Roo.menu.BaseItem
34146 * @extends Roo.Component
34147 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34148 * management and base configuration options shared by all menu components.
34150 * Creates a new BaseItem
34151 * @param {Object} config Configuration options
34153 Roo.menu.BaseItem = function(config){
34154 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34159 * Fires when this item is clicked
34160 * @param {Roo.menu.BaseItem} this
34161 * @param {Roo.EventObject} e
34166 * Fires when this item is activated
34167 * @param {Roo.menu.BaseItem} this
34171 * @event deactivate
34172 * Fires when this item is deactivated
34173 * @param {Roo.menu.BaseItem} this
34179 this.on("click", this.handler, this.scope, true);
34183 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34185 * @cfg {Function} handler
34186 * A function that will handle the click event of this menu item (defaults to undefined)
34189 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34191 canActivate : false,
34193 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34195 activeClass : "x-menu-item-active",
34197 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34199 hideOnClick : true,
34201 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34206 ctype: "Roo.menu.BaseItem",
34209 actionMode : "container",
34212 render : function(container, parentMenu){
34213 this.parentMenu = parentMenu;
34214 Roo.menu.BaseItem.superclass.render.call(this, container);
34215 this.container.menuItemId = this.id;
34219 onRender : function(container, position){
34220 this.el = Roo.get(this.el);
34221 container.dom.appendChild(this.el.dom);
34225 onClick : function(e){
34226 if(!this.disabled && this.fireEvent("click", this, e) !== false
34227 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34228 this.handleClick(e);
34235 activate : function(){
34239 var li = this.container;
34240 li.addClass(this.activeClass);
34241 this.region = li.getRegion().adjust(2, 2, -2, -2);
34242 this.fireEvent("activate", this);
34247 deactivate : function(){
34248 this.container.removeClass(this.activeClass);
34249 this.fireEvent("deactivate", this);
34253 shouldDeactivate : function(e){
34254 return !this.region || !this.region.contains(e.getPoint());
34258 handleClick : function(e){
34259 if(this.hideOnClick){
34260 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34265 expandMenu : function(autoActivate){
34270 hideMenu : function(){
34275 * Ext JS Library 1.1.1
34276 * Copyright(c) 2006-2007, Ext JS, LLC.
34278 * Originally Released Under LGPL - original licence link has changed is not relivant.
34281 * <script type="text/javascript">
34285 * @class Roo.menu.Adapter
34286 * @extends Roo.menu.BaseItem
34287 * 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.
34288 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34290 * Creates a new Adapter
34291 * @param {Object} config Configuration options
34293 Roo.menu.Adapter = function(component, config){
34294 Roo.menu.Adapter.superclass.constructor.call(this, config);
34295 this.component = component;
34297 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34299 canActivate : true,
34302 onRender : function(container, position){
34303 this.component.render(container);
34304 this.el = this.component.getEl();
34308 activate : function(){
34312 this.component.focus();
34313 this.fireEvent("activate", this);
34318 deactivate : function(){
34319 this.fireEvent("deactivate", this);
34323 disable : function(){
34324 this.component.disable();
34325 Roo.menu.Adapter.superclass.disable.call(this);
34329 enable : function(){
34330 this.component.enable();
34331 Roo.menu.Adapter.superclass.enable.call(this);
34335 * Ext JS Library 1.1.1
34336 * Copyright(c) 2006-2007, Ext JS, LLC.
34338 * Originally Released Under LGPL - original licence link has changed is not relivant.
34341 * <script type="text/javascript">
34345 * @class Roo.menu.TextItem
34346 * @extends Roo.menu.BaseItem
34347 * Adds a static text string to a menu, usually used as either a heading or group separator.
34349 * Creates a new TextItem
34350 * @param {String} text The text to display
34352 Roo.menu.TextItem = function(text){
34354 Roo.menu.TextItem.superclass.constructor.call(this);
34357 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34359 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34361 hideOnClick : false,
34363 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34365 itemCls : "x-menu-text",
34368 onRender : function(){
34369 var s = document.createElement("span");
34370 s.className = this.itemCls;
34371 s.innerHTML = this.text;
34373 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34377 * Ext JS Library 1.1.1
34378 * Copyright(c) 2006-2007, Ext JS, LLC.
34380 * Originally Released Under LGPL - original licence link has changed is not relivant.
34383 * <script type="text/javascript">
34387 * @class Roo.menu.Separator
34388 * @extends Roo.menu.BaseItem
34389 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34390 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34392 * @param {Object} config Configuration options
34394 Roo.menu.Separator = function(config){
34395 Roo.menu.Separator.superclass.constructor.call(this, config);
34398 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34400 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34402 itemCls : "x-menu-sep",
34404 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34406 hideOnClick : false,
34409 onRender : function(li){
34410 var s = document.createElement("span");
34411 s.className = this.itemCls;
34412 s.innerHTML = " ";
34414 li.addClass("x-menu-sep-li");
34415 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34419 * Ext JS Library 1.1.1
34420 * Copyright(c) 2006-2007, Ext JS, LLC.
34422 * Originally Released Under LGPL - original licence link has changed is not relivant.
34425 * <script type="text/javascript">
34428 * @class Roo.menu.Item
34429 * @extends Roo.menu.BaseItem
34430 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34431 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34432 * activation and click handling.
34434 * Creates a new Item
34435 * @param {Object} config Configuration options
34437 Roo.menu.Item = function(config){
34438 Roo.menu.Item.superclass.constructor.call(this, config);
34440 this.menu = Roo.menu.MenuMgr.get(this.menu);
34443 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34445 * @cfg {String} icon
34446 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34449 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34451 itemCls : "x-menu-item",
34453 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34455 canActivate : true,
34457 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34460 // doc'd in BaseItem
34464 ctype: "Roo.menu.Item",
34467 onRender : function(container, position){
34468 var el = document.createElement("a");
34469 el.hideFocus = true;
34470 el.unselectable = "on";
34471 el.href = this.href || "#";
34472 if(this.hrefTarget){
34473 el.target = this.hrefTarget;
34475 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34476 el.innerHTML = String.format(
34477 '<img src="{0}" class="x-menu-item-icon {2}" />{1}',
34478 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || '');
34480 Roo.menu.Item.superclass.onRender.call(this, container, position);
34484 * Sets the text to display in this menu item
34485 * @param {String} text The text to display
34487 setText : function(text){
34490 this.el.update(String.format(
34491 '<img src="{0}" class="x-menu-item-icon {2}">{1}',
34492 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34493 this.parentMenu.autoWidth();
34498 handleClick : function(e){
34499 if(!this.href){ // if no link defined, stop the event automatically
34502 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34506 activate : function(autoExpand){
34507 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34517 shouldDeactivate : function(e){
34518 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34519 if(this.menu && this.menu.isVisible()){
34520 return !this.menu.getEl().getRegion().contains(e.getPoint());
34528 deactivate : function(){
34529 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34534 expandMenu : function(autoActivate){
34535 if(!this.disabled && this.menu){
34536 clearTimeout(this.hideTimer);
34537 delete this.hideTimer;
34538 if(!this.menu.isVisible() && !this.showTimer){
34539 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34540 }else if (this.menu.isVisible() && autoActivate){
34541 this.menu.tryActivate(0, 1);
34547 deferExpand : function(autoActivate){
34548 delete this.showTimer;
34549 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34551 this.menu.tryActivate(0, 1);
34556 hideMenu : function(){
34557 clearTimeout(this.showTimer);
34558 delete this.showTimer;
34559 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34560 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34565 deferHide : function(){
34566 delete this.hideTimer;
34571 * Ext JS Library 1.1.1
34572 * Copyright(c) 2006-2007, Ext JS, LLC.
34574 * Originally Released Under LGPL - original licence link has changed is not relivant.
34577 * <script type="text/javascript">
34581 * @class Roo.menu.CheckItem
34582 * @extends Roo.menu.Item
34583 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34585 * Creates a new CheckItem
34586 * @param {Object} config Configuration options
34588 Roo.menu.CheckItem = function(config){
34589 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34592 * @event beforecheckchange
34593 * Fires before the checked value is set, providing an opportunity to cancel if needed
34594 * @param {Roo.menu.CheckItem} this
34595 * @param {Boolean} checked The new checked value that will be set
34597 "beforecheckchange" : true,
34599 * @event checkchange
34600 * Fires after the checked value has been set
34601 * @param {Roo.menu.CheckItem} this
34602 * @param {Boolean} checked The checked value that was set
34604 "checkchange" : true
34606 if(this.checkHandler){
34607 this.on('checkchange', this.checkHandler, this.scope);
34610 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34612 * @cfg {String} group
34613 * All check items with the same group name will automatically be grouped into a single-select
34614 * radio button group (defaults to '')
34617 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34619 itemCls : "x-menu-item x-menu-check-item",
34621 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34623 groupClass : "x-menu-group-item",
34626 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34627 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34628 * initialized with checked = true will be rendered as checked.
34633 ctype: "Roo.menu.CheckItem",
34636 onRender : function(c){
34637 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34639 this.el.addClass(this.groupClass);
34641 Roo.menu.MenuMgr.registerCheckable(this);
34643 this.checked = false;
34644 this.setChecked(true, true);
34649 destroy : function(){
34651 Roo.menu.MenuMgr.unregisterCheckable(this);
34653 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
34657 * Set the checked state of this item
34658 * @param {Boolean} checked The new checked value
34659 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
34661 setChecked : function(state, suppressEvent){
34662 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
34663 if(this.container){
34664 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
34666 this.checked = state;
34667 if(suppressEvent !== true){
34668 this.fireEvent("checkchange", this, state);
34674 handleClick : function(e){
34675 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
34676 this.setChecked(!this.checked);
34678 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
34682 * Ext JS Library 1.1.1
34683 * Copyright(c) 2006-2007, Ext JS, LLC.
34685 * Originally Released Under LGPL - original licence link has changed is not relivant.
34688 * <script type="text/javascript">
34692 * @class Roo.menu.DateItem
34693 * @extends Roo.menu.Adapter
34694 * A menu item that wraps the {@link Roo.DatPicker} component.
34696 * Creates a new DateItem
34697 * @param {Object} config Configuration options
34699 Roo.menu.DateItem = function(config){
34700 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
34701 /** The Roo.DatePicker object @type Roo.DatePicker */
34702 this.picker = this.component;
34703 this.addEvents({select: true});
34705 this.picker.on("render", function(picker){
34706 picker.getEl().swallowEvent("click");
34707 picker.container.addClass("x-menu-date-item");
34710 this.picker.on("select", this.onSelect, this);
34713 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
34715 onSelect : function(picker, date){
34716 this.fireEvent("select", this, date, picker);
34717 Roo.menu.DateItem.superclass.handleClick.call(this);
34721 * Ext JS Library 1.1.1
34722 * Copyright(c) 2006-2007, Ext JS, LLC.
34724 * Originally Released Under LGPL - original licence link has changed is not relivant.
34727 * <script type="text/javascript">
34731 * @class Roo.menu.ColorItem
34732 * @extends Roo.menu.Adapter
34733 * A menu item that wraps the {@link Roo.ColorPalette} component.
34735 * Creates a new ColorItem
34736 * @param {Object} config Configuration options
34738 Roo.menu.ColorItem = function(config){
34739 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
34740 /** The Roo.ColorPalette object @type Roo.ColorPalette */
34741 this.palette = this.component;
34742 this.relayEvents(this.palette, ["select"]);
34743 if(this.selectHandler){
34744 this.on('select', this.selectHandler, this.scope);
34747 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
34749 * Ext JS Library 1.1.1
34750 * Copyright(c) 2006-2007, Ext JS, LLC.
34752 * Originally Released Under LGPL - original licence link has changed is not relivant.
34755 * <script type="text/javascript">
34760 * @class Roo.menu.DateMenu
34761 * @extends Roo.menu.Menu
34762 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
34764 * Creates a new DateMenu
34765 * @param {Object} config Configuration options
34767 Roo.menu.DateMenu = function(config){
34768 Roo.menu.DateMenu.superclass.constructor.call(this, config);
34770 var di = new Roo.menu.DateItem(config);
34773 * The {@link Roo.DatePicker} instance for this DateMenu
34776 this.picker = di.picker;
34779 * @param {DatePicker} picker
34780 * @param {Date} date
34782 this.relayEvents(di, ["select"]);
34784 this.on('beforeshow', function(){
34786 this.picker.hideMonthPicker(true);
34790 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
34794 * Ext JS Library 1.1.1
34795 * Copyright(c) 2006-2007, Ext JS, LLC.
34797 * Originally Released Under LGPL - original licence link has changed is not relivant.
34800 * <script type="text/javascript">
34805 * @class Roo.menu.ColorMenu
34806 * @extends Roo.menu.Menu
34807 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
34809 * Creates a new ColorMenu
34810 * @param {Object} config Configuration options
34812 Roo.menu.ColorMenu = function(config){
34813 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
34815 var ci = new Roo.menu.ColorItem(config);
34818 * The {@link Roo.ColorPalette} instance for this ColorMenu
34819 * @type ColorPalette
34821 this.palette = ci.palette;
34824 * @param {ColorPalette} palette
34825 * @param {String} color
34827 this.relayEvents(ci, ["select"]);
34829 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
34831 * Ext JS Library 1.1.1
34832 * Copyright(c) 2006-2007, Ext JS, LLC.
34834 * Originally Released Under LGPL - original licence link has changed is not relivant.
34837 * <script type="text/javascript">
34841 * @class Roo.form.Field
34842 * @extends Roo.BoxComponent
34843 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
34845 * Creates a new Field
34846 * @param {Object} config Configuration options
34848 Roo.form.Field = function(config){
34849 Roo.form.Field.superclass.constructor.call(this, config);
34852 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
34854 * @cfg {String} fieldLabel Label to use when rendering a form.
34857 * @cfg {String} qtip Mouse over tip
34861 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
34863 invalidClass : "x-form-invalid",
34865 * @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")
34867 invalidText : "The value in this field is invalid",
34869 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
34871 focusClass : "x-form-focus",
34873 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
34874 automatic validation (defaults to "keyup").
34876 validationEvent : "keyup",
34878 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
34880 validateOnBlur : true,
34882 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
34884 validationDelay : 250,
34886 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
34887 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
34889 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
34891 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
34893 fieldClass : "x-form-field",
34895 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
34898 ----------- ----------------------------------------------------------------------
34899 qtip Display a quick tip when the user hovers over the field
34900 title Display a default browser title attribute popup
34901 under Add a block div beneath the field containing the error text
34902 side Add an error icon to the right of the field with a popup on hover
34903 [element id] Add the error text directly to the innerHTML of the specified element
34906 msgTarget : 'qtip',
34908 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
34913 * @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.
34918 * @cfg {Boolean} disabled True to disable the field (defaults to false).
34923 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
34925 inputType : undefined,
34928 * @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).
34930 tabIndex : undefined,
34933 isFormField : true,
34938 * @property {Roo.Element} fieldEl
34939 * Element Containing the rendered Field (with label etc.)
34942 * @cfg {Mixed} value A value to initialize this field with.
34947 * @cfg {String} name The field's HTML name attribute.
34950 * @cfg {String} cls A CSS class to apply to the field's underlying element.
34954 initComponent : function(){
34955 Roo.form.Field.superclass.initComponent.call(this);
34959 * Fires when this field receives input focus.
34960 * @param {Roo.form.Field} this
34965 * Fires when this field loses input focus.
34966 * @param {Roo.form.Field} this
34970 * @event specialkey
34971 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
34972 * {@link Roo.EventObject#getKey} to determine which key was pressed.
34973 * @param {Roo.form.Field} this
34974 * @param {Roo.EventObject} e The event object
34979 * Fires just before the field blurs if the field value has changed.
34980 * @param {Roo.form.Field} this
34981 * @param {Mixed} newValue The new value
34982 * @param {Mixed} oldValue The original value
34987 * Fires after the field has been marked as invalid.
34988 * @param {Roo.form.Field} this
34989 * @param {String} msg The validation message
34994 * Fires after the field has been validated with no errors.
34995 * @param {Roo.form.Field} this
35002 * Returns the name attribute of the field if available
35003 * @return {String} name The field name
35005 getName: function(){
35006 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35010 onRender : function(ct, position){
35011 Roo.form.Field.superclass.onRender.call(this, ct, position);
35013 var cfg = this.getAutoCreate();
35015 cfg.name = this.name || this.id;
35017 if(this.inputType){
35018 cfg.type = this.inputType;
35020 this.el = ct.createChild(cfg, position);
35022 var type = this.el.dom.type;
35024 if(type == 'password'){
35027 this.el.addClass('x-form-'+type);
35030 this.el.dom.readOnly = true;
35032 if(this.tabIndex !== undefined){
35033 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35036 this.el.addClass([this.fieldClass, this.cls]);
35041 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35042 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35043 * @return {Roo.form.Field} this
35045 applyTo : function(target){
35046 this.allowDomMove = false;
35047 this.el = Roo.get(target);
35048 this.render(this.el.dom.parentNode);
35053 initValue : function(){
35054 if(this.value !== undefined){
35055 this.setValue(this.value);
35056 }else if(this.el.dom.value.length > 0){
35057 this.setValue(this.el.dom.value);
35062 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35064 isDirty : function() {
35065 if(this.disabled) {
35068 return String(this.getValue()) !== String(this.originalValue);
35072 afterRender : function(){
35073 Roo.form.Field.superclass.afterRender.call(this);
35078 fireKey : function(e){
35079 if(e.isNavKeyPress()){
35080 this.fireEvent("specialkey", this, e);
35085 * Resets the current field value to the originally loaded value and clears any validation messages
35087 reset : function(){
35088 this.setValue(this.originalValue);
35089 this.clearInvalid();
35093 initEvents : function(){
35094 this.el.on(Roo.isIE ? "keydown" : "keypress", this.fireKey, this);
35095 this.el.on("focus", this.onFocus, this);
35096 this.el.on("blur", this.onBlur, this);
35098 // reference to original value for reset
35099 this.originalValue = this.getValue();
35103 onFocus : function(){
35104 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35105 this.el.addClass(this.focusClass);
35107 if(!this.hasFocus){
35108 this.hasFocus = true;
35109 this.startValue = this.getValue();
35110 this.fireEvent("focus", this);
35114 beforeBlur : Roo.emptyFn,
35117 onBlur : function(){
35119 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35120 this.el.removeClass(this.focusClass);
35122 this.hasFocus = false;
35123 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35126 var v = this.getValue();
35127 if(String(v) !== String(this.startValue)){
35128 this.fireEvent('change', this, v, this.startValue);
35130 this.fireEvent("blur", this);
35134 * Returns whether or not the field value is currently valid
35135 * @param {Boolean} preventMark True to disable marking the field invalid
35136 * @return {Boolean} True if the value is valid, else false
35138 isValid : function(preventMark){
35142 var restore = this.preventMark;
35143 this.preventMark = preventMark === true;
35144 var v = this.validateValue(this.processValue(this.getRawValue()));
35145 this.preventMark = restore;
35150 * Validates the field value
35151 * @return {Boolean} True if the value is valid, else false
35153 validate : function(){
35154 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35155 this.clearInvalid();
35161 processValue : function(value){
35166 // Subclasses should provide the validation implementation by overriding this
35167 validateValue : function(value){
35172 * Mark this field as invalid
35173 * @param {String} msg The validation message
35175 markInvalid : function(msg){
35176 if(!this.rendered || this.preventMark){ // not rendered
35179 this.el.addClass(this.invalidClass);
35180 msg = msg || this.invalidText;
35181 switch(this.msgTarget){
35183 this.el.dom.qtip = msg;
35184 this.el.dom.qclass = 'x-form-invalid-tip';
35185 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35186 Roo.QuickTips.enable();
35190 this.el.dom.title = msg;
35194 var elp = this.el.findParent('.x-form-element', 5, true);
35195 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35196 this.errorEl.setWidth(elp.getWidth(true)-20);
35198 this.errorEl.update(msg);
35199 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35202 if(!this.errorIcon){
35203 var elp = this.el.findParent('.x-form-element', 5, true);
35204 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35206 this.alignErrorIcon();
35207 this.errorIcon.dom.qtip = msg;
35208 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35209 this.errorIcon.show();
35210 this.on('resize', this.alignErrorIcon, this);
35213 var t = Roo.getDom(this.msgTarget);
35215 t.style.display = this.msgDisplay;
35218 this.fireEvent('invalid', this, msg);
35222 alignErrorIcon : function(){
35223 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35227 * Clear any invalid styles/messages for this field
35229 clearInvalid : function(){
35230 if(!this.rendered || this.preventMark){ // not rendered
35233 this.el.removeClass(this.invalidClass);
35234 switch(this.msgTarget){
35236 this.el.dom.qtip = '';
35239 this.el.dom.title = '';
35243 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35247 if(this.errorIcon){
35248 this.errorIcon.dom.qtip = '';
35249 this.errorIcon.hide();
35250 this.un('resize', this.alignErrorIcon, this);
35254 var t = Roo.getDom(this.msgTarget);
35256 t.style.display = 'none';
35259 this.fireEvent('valid', this);
35263 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35264 * @return {Mixed} value The field value
35266 getRawValue : function(){
35267 var v = this.el.getValue();
35268 if(v === this.emptyText){
35275 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35276 * @return {Mixed} value The field value
35278 getValue : function(){
35279 var v = this.el.getValue();
35280 if(v === this.emptyText || v === undefined){
35287 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35288 * @param {Mixed} value The value to set
35290 setRawValue : function(v){
35291 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35295 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35296 * @param {Mixed} value The value to set
35298 setValue : function(v){
35301 this.el.dom.value = (v === null || v === undefined ? '' : v);
35306 adjustSize : function(w, h){
35307 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35308 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35312 adjustWidth : function(tag, w){
35313 tag = tag.toLowerCase();
35314 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35315 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35316 if(tag == 'input'){
35319 if(tag = 'textarea'){
35322 }else if(Roo.isOpera){
35323 if(tag == 'input'){
35326 if(tag = 'textarea'){
35336 // anything other than normal should be considered experimental
35337 Roo.form.Field.msgFx = {
35339 show: function(msgEl, f){
35340 msgEl.setDisplayed('block');
35343 hide : function(msgEl, f){
35344 msgEl.setDisplayed(false).update('');
35349 show: function(msgEl, f){
35350 msgEl.slideIn('t', {stopFx:true});
35353 hide : function(msgEl, f){
35354 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35359 show: function(msgEl, f){
35360 msgEl.fixDisplay();
35361 msgEl.alignTo(f.el, 'tl-tr');
35362 msgEl.slideIn('l', {stopFx:true});
35365 hide : function(msgEl, f){
35366 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35371 * Ext JS Library 1.1.1
35372 * Copyright(c) 2006-2007, Ext JS, LLC.
35374 * Originally Released Under LGPL - original licence link has changed is not relivant.
35377 * <script type="text/javascript">
35382 * @class Roo.form.TextField
35383 * @extends Roo.form.Field
35384 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35385 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35387 * Creates a new TextField
35388 * @param {Object} config Configuration options
35390 Roo.form.TextField = function(config){
35391 Roo.form.TextField.superclass.constructor.call(this, config);
35395 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35396 * according to the default logic, but this event provides a hook for the developer to apply additional
35397 * logic at runtime to resize the field if needed.
35398 * @param {Roo.form.Field} this This text field
35399 * @param {Number} width The new field width
35405 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35407 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35411 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35415 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35419 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35423 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35427 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35429 disableKeyFilter : false,
35431 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35435 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35439 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35441 maxLength : Number.MAX_VALUE,
35443 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35445 minLengthText : "The minimum length for this field is {0}",
35447 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35449 maxLengthText : "The maximum length for this field is {0}",
35451 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35453 selectOnFocus : false,
35455 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35457 blankText : "This field is required",
35459 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35460 * If available, this function will be called only after the basic validators all return true, and will be passed the
35461 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35465 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35466 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35467 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35471 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35475 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35479 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35480 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35482 emptyClass : 'x-form-empty-field',
35485 initEvents : function(){
35486 Roo.form.TextField.superclass.initEvents.call(this);
35487 if(this.validationEvent == 'keyup'){
35488 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35489 this.el.on('keyup', this.filterValidation, this);
35491 else if(this.validationEvent !== false){
35492 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35494 if(this.selectOnFocus || this.emptyText){
35495 this.on("focus", this.preFocus, this);
35496 if(this.emptyText){
35497 this.on('blur', this.postBlur, this);
35498 this.applyEmptyText();
35501 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35502 this.el.on("keypress", this.filterKeys, this);
35505 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35506 this.el.on("click", this.autoSize, this);
35510 processValue : function(value){
35511 if(this.stripCharsRe){
35512 var newValue = value.replace(this.stripCharsRe, '');
35513 if(newValue !== value){
35514 this.setRawValue(newValue);
35521 filterValidation : function(e){
35522 if(!e.isNavKeyPress()){
35523 this.validationTask.delay(this.validationDelay);
35528 onKeyUp : function(e){
35529 if(!e.isNavKeyPress()){
35535 * Resets the current field value to the originally-loaded value and clears any validation messages.
35536 * Also adds emptyText and emptyClass if the original value was blank.
35538 reset : function(){
35539 Roo.form.TextField.superclass.reset.call(this);
35540 this.applyEmptyText();
35543 applyEmptyText : function(){
35544 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35545 this.setRawValue(this.emptyText);
35546 this.el.addClass(this.emptyClass);
35551 preFocus : function(){
35552 if(this.emptyText){
35553 if(this.el.dom.value == this.emptyText){
35554 this.setRawValue('');
35556 this.el.removeClass(this.emptyClass);
35558 if(this.selectOnFocus){
35559 this.el.dom.select();
35564 postBlur : function(){
35565 this.applyEmptyText();
35569 filterKeys : function(e){
35570 var k = e.getKey();
35571 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35574 var c = e.getCharCode(), cc = String.fromCharCode(c);
35575 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35578 if(!this.maskRe.test(cc)){
35583 setValue : function(v){
35584 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35585 this.el.removeClass(this.emptyClass);
35587 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35588 this.applyEmptyText();
35593 * Validates a value according to the field's validation rules and marks the field as invalid
35594 * if the validation fails
35595 * @param {Mixed} value The value to validate
35596 * @return {Boolean} True if the value is valid, else false
35598 validateValue : function(value){
35599 if(value.length < 1 || value === this.emptyText){ // if it's blank
35600 if(this.allowBlank){
35601 this.clearInvalid();
35604 this.markInvalid(this.blankText);
35608 if(value.length < this.minLength){
35609 this.markInvalid(String.format(this.minLengthText, this.minLength));
35612 if(value.length > this.maxLength){
35613 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35617 var vt = Roo.form.VTypes;
35618 if(!vt[this.vtype](value, this)){
35619 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35623 if(typeof this.validator == "function"){
35624 var msg = this.validator(value);
35626 this.markInvalid(msg);
35630 if(this.regex && !this.regex.test(value)){
35631 this.markInvalid(this.regexText);
35638 * Selects text in this field
35639 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
35640 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
35642 selectText : function(start, end){
35643 var v = this.getRawValue();
35645 start = start === undefined ? 0 : start;
35646 end = end === undefined ? v.length : end;
35647 var d = this.el.dom;
35648 if(d.setSelectionRange){
35649 d.setSelectionRange(start, end);
35650 }else if(d.createTextRange){
35651 var range = d.createTextRange();
35652 range.moveStart("character", start);
35653 range.moveEnd("character", v.length-end);
35660 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
35661 * This only takes effect if grow = true, and fires the autosize event.
35663 autoSize : function(){
35664 if(!this.grow || !this.rendered){
35668 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
35671 var v = el.dom.value;
35672 var d = document.createElement('div');
35673 d.appendChild(document.createTextNode(v));
35677 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
35678 this.el.setWidth(w);
35679 this.fireEvent("autosize", this, w);
35683 * Ext JS Library 1.1.1
35684 * Copyright(c) 2006-2007, Ext JS, LLC.
35686 * Originally Released Under LGPL - original licence link has changed is not relivant.
35689 * <script type="text/javascript">
35693 * @class Roo.form.Hidden
35694 * @extends Roo.form.TextField
35695 * Simple Hidden element used on forms
35697 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
35700 * Creates a new Hidden form element.
35701 * @param {Object} config Configuration options
35706 // easy hidden field...
35707 Roo.form.Hidden = function(config){
35708 Roo.form.Hidden.superclass.constructor.call(this, config);
35711 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
35713 inputType: 'hidden',
35716 labelSeparator: '',
35718 itemCls : 'x-form-item-display-none'
35726 * Ext JS Library 1.1.1
35727 * Copyright(c) 2006-2007, Ext JS, LLC.
35729 * Originally Released Under LGPL - original licence link has changed is not relivant.
35732 * <script type="text/javascript">
35736 * @class Roo.form.TriggerField
35737 * @extends Roo.form.TextField
35738 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
35739 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
35740 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
35741 * for which you can provide a custom implementation. For example:
35743 var trigger = new Roo.form.TriggerField();
35744 trigger.onTriggerClick = myTriggerFn;
35745 trigger.applyTo('my-field');
35748 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
35749 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
35750 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
35751 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
35753 * Create a new TriggerField.
35754 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
35755 * to the base TextField)
35757 Roo.form.TriggerField = function(config){
35758 this.mimicing = false;
35759 Roo.form.TriggerField.superclass.constructor.call(this, config);
35762 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
35764 * @cfg {String} triggerClass A CSS class to apply to the trigger
35767 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35768 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
35770 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
35772 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
35776 /** @cfg {Boolean} grow @hide */
35777 /** @cfg {Number} growMin @hide */
35778 /** @cfg {Number} growMax @hide */
35784 autoSize: Roo.emptyFn,
35788 deferHeight : true,
35791 actionMode : 'wrap',
35793 onResize : function(w, h){
35794 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
35795 if(typeof w == 'number'){
35796 this.el.setWidth(this.adjustWidth('input', w - this.trigger.getWidth()));
35801 adjustSize : Roo.BoxComponent.prototype.adjustSize,
35804 getResizeEl : function(){
35809 getPositionEl : function(){
35814 alignErrorIcon : function(){
35815 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
35819 onRender : function(ct, position){
35820 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
35821 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
35822 this.trigger = this.wrap.createChild(this.triggerConfig ||
35823 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
35824 if(this.hideTrigger){
35825 this.trigger.setDisplayed(false);
35827 this.initTrigger();
35829 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
35834 initTrigger : function(){
35835 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
35836 this.trigger.addClassOnOver('x-form-trigger-over');
35837 this.trigger.addClassOnClick('x-form-trigger-click');
35841 onDestroy : function(){
35843 this.trigger.removeAllListeners();
35844 this.trigger.remove();
35847 this.wrap.remove();
35849 Roo.form.TriggerField.superclass.onDestroy.call(this);
35853 onFocus : function(){
35854 Roo.form.TriggerField.superclass.onFocus.call(this);
35855 if(!this.mimicing){
35856 this.wrap.addClass('x-trigger-wrap-focus');
35857 this.mimicing = true;
35858 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
35859 if(this.monitorTab){
35860 this.el.on("keydown", this.checkTab, this);
35866 checkTab : function(e){
35867 if(e.getKey() == e.TAB){
35868 this.triggerBlur();
35873 onBlur : function(){
35878 mimicBlur : function(e, t){
35879 if(!this.wrap.contains(t) && this.validateBlur()){
35880 this.triggerBlur();
35885 triggerBlur : function(){
35886 this.mimicing = false;
35887 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
35888 if(this.monitorTab){
35889 this.el.un("keydown", this.checkTab, this);
35891 this.wrap.removeClass('x-trigger-wrap-focus');
35892 Roo.form.TriggerField.superclass.onBlur.call(this);
35896 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
35897 validateBlur : function(e, t){
35902 onDisable : function(){
35903 Roo.form.TriggerField.superclass.onDisable.call(this);
35905 this.wrap.addClass('x-item-disabled');
35910 onEnable : function(){
35911 Roo.form.TriggerField.superclass.onEnable.call(this);
35913 this.wrap.removeClass('x-item-disabled');
35918 onShow : function(){
35919 var ae = this.getActionEl();
35922 ae.dom.style.display = '';
35923 ae.dom.style.visibility = 'visible';
35929 onHide : function(){
35930 var ae = this.getActionEl();
35931 ae.dom.style.display = 'none';
35935 * The function that should handle the trigger's click event. This method does nothing by default until overridden
35936 * by an implementing function.
35938 * @param {EventObject} e
35940 onTriggerClick : Roo.emptyFn
35943 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
35944 // to be extended by an implementing class. For an example of implementing this class, see the custom
35945 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
35946 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
35947 initComponent : function(){
35948 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
35950 this.triggerConfig = {
35951 tag:'span', cls:'x-form-twin-triggers', cn:[
35952 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
35953 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
35957 getTrigger : function(index){
35958 return this.triggers[index];
35961 initTrigger : function(){
35962 var ts = this.trigger.select('.x-form-trigger', true);
35963 this.wrap.setStyle('overflow', 'hidden');
35964 var triggerField = this;
35965 ts.each(function(t, all, index){
35966 t.hide = function(){
35967 var w = triggerField.wrap.getWidth();
35968 this.dom.style.display = 'none';
35969 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
35971 t.show = function(){
35972 var w = triggerField.wrap.getWidth();
35973 this.dom.style.display = '';
35974 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
35976 var triggerIndex = 'Trigger'+(index+1);
35978 if(this['hide'+triggerIndex]){
35979 t.dom.style.display = 'none';
35981 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
35982 t.addClassOnOver('x-form-trigger-over');
35983 t.addClassOnClick('x-form-trigger-click');
35985 this.triggers = ts.elements;
35988 onTrigger1Click : Roo.emptyFn,
35989 onTrigger2Click : Roo.emptyFn
35992 * Ext JS Library 1.1.1
35993 * Copyright(c) 2006-2007, Ext JS, LLC.
35995 * Originally Released Under LGPL - original licence link has changed is not relivant.
35998 * <script type="text/javascript">
36002 * @class Roo.form.TextArea
36003 * @extends Roo.form.TextField
36004 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36005 * support for auto-sizing.
36007 * Creates a new TextArea
36008 * @param {Object} config Configuration options
36010 Roo.form.TextArea = function(config){
36011 Roo.form.TextArea.superclass.constructor.call(this, config);
36012 // these are provided exchanges for backwards compat
36013 // minHeight/maxHeight were replaced by growMin/growMax to be
36014 // compatible with TextField growing config values
36015 if(this.minHeight !== undefined){
36016 this.growMin = this.minHeight;
36018 if(this.maxHeight !== undefined){
36019 this.growMax = this.maxHeight;
36023 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36025 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36029 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36033 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36034 * in the field (equivalent to setting overflow: hidden, defaults to false)
36036 preventScrollbars: false,
36038 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36039 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36043 onRender : function(ct, position){
36045 this.defaultAutoCreate = {
36047 style:"width:300px;height:60px;",
36048 autocomplete: "off"
36051 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36053 this.textSizeEl = Roo.DomHelper.append(document.body, {
36054 tag: "pre", cls: "x-form-grow-sizer"
36056 if(this.preventScrollbars){
36057 this.el.setStyle("overflow", "hidden");
36059 this.el.setHeight(this.growMin);
36063 onDestroy : function(){
36064 if(this.textSizeEl){
36065 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36067 Roo.form.TextArea.superclass.onDestroy.call(this);
36071 onKeyUp : function(e){
36072 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36078 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36079 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36081 autoSize : function(){
36082 if(!this.grow || !this.textSizeEl){
36086 var v = el.dom.value;
36087 var ts = this.textSizeEl;
36090 ts.appendChild(document.createTextNode(v));
36093 Roo.fly(ts).setWidth(this.el.getWidth());
36095 v = "  ";
36098 v = v.replace(/\n/g, '<p> </p>');
36100 v += " \n ";
36103 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36104 if(h != this.lastHeight){
36105 this.lastHeight = h;
36106 this.el.setHeight(h);
36107 this.fireEvent("autosize", this, h);
36112 * Ext JS Library 1.1.1
36113 * Copyright(c) 2006-2007, Ext JS, LLC.
36115 * Originally Released Under LGPL - original licence link has changed is not relivant.
36118 * <script type="text/javascript">
36123 * @class Roo.form.NumberField
36124 * @extends Roo.form.TextField
36125 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36127 * Creates a new NumberField
36128 * @param {Object} config Configuration options
36130 Roo.form.NumberField = function(config){
36131 Roo.form.NumberField.superclass.constructor.call(this, config);
36134 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36136 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36138 fieldClass: "x-form-field x-form-num-field",
36140 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36142 allowDecimals : true,
36144 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36146 decimalSeparator : ".",
36148 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36150 decimalPrecision : 2,
36152 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36154 allowNegative : true,
36156 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36158 minValue : Number.NEGATIVE_INFINITY,
36160 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36162 maxValue : Number.MAX_VALUE,
36164 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36166 minText : "The minimum value for this field is {0}",
36168 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36170 maxText : "The maximum value for this field is {0}",
36172 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36173 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36175 nanText : "{0} is not a valid number",
36178 initEvents : function(){
36179 Roo.form.NumberField.superclass.initEvents.call(this);
36180 var allowed = "0123456789";
36181 if(this.allowDecimals){
36182 allowed += this.decimalSeparator;
36184 if(this.allowNegative){
36187 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36188 var keyPress = function(e){
36189 var k = e.getKey();
36190 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36193 var c = e.getCharCode();
36194 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36198 this.el.on("keypress", keyPress, this);
36202 validateValue : function(value){
36203 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36206 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36209 var num = this.parseValue(value);
36211 this.markInvalid(String.format(this.nanText, value));
36214 if(num < this.minValue){
36215 this.markInvalid(String.format(this.minText, this.minValue));
36218 if(num > this.maxValue){
36219 this.markInvalid(String.format(this.maxText, this.maxValue));
36225 getValue : function(){
36226 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36230 parseValue : function(value){
36231 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36232 return isNaN(value) ? '' : value;
36236 fixPrecision : function(value){
36237 var nan = isNaN(value);
36238 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36239 return nan ? '' : value;
36241 return parseFloat(value).toFixed(this.decimalPrecision);
36244 setValue : function(v){
36245 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36249 decimalPrecisionFcn : function(v){
36250 return Math.floor(v);
36253 beforeBlur : function(){
36254 var v = this.parseValue(this.getRawValue());
36256 this.setValue(this.fixPrecision(v));
36261 * Ext JS Library 1.1.1
36262 * Copyright(c) 2006-2007, Ext JS, LLC.
36264 * Originally Released Under LGPL - original licence link has changed is not relivant.
36267 * <script type="text/javascript">
36271 * @class Roo.form.DateField
36272 * @extends Roo.form.TriggerField
36273 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36275 * Create a new DateField
36276 * @param {Object} config
36278 Roo.form.DateField = function(config){
36279 Roo.form.DateField.superclass.constructor.call(this, config);
36285 * Fires when a date is selected
36286 * @param {Roo.form.DateField} combo This combo box
36287 * @param {Date} date The date selected
36294 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36295 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36296 this.ddMatch = null;
36297 if(this.disabledDates){
36298 var dd = this.disabledDates;
36300 for(var i = 0; i < dd.length; i++){
36302 if(i != dd.length-1) re += "|";
36304 this.ddMatch = new RegExp(re + ")");
36308 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36310 * @cfg {String} format
36311 * The default date format string which can be overriden for localization support. The format must be
36312 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36316 * @cfg {String} altFormats
36317 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36318 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36320 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36322 * @cfg {Array} disabledDays
36323 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36325 disabledDays : null,
36327 * @cfg {String} disabledDaysText
36328 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36330 disabledDaysText : "Disabled",
36332 * @cfg {Array} disabledDates
36333 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36334 * expression so they are very powerful. Some examples:
36336 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36337 * <li>["03/08", "09/16"] would disable those days for every year</li>
36338 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36339 * <li>["03/../2006"] would disable every day in March 2006</li>
36340 * <li>["^03"] would disable every day in every March</li>
36342 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36343 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36345 disabledDates : null,
36347 * @cfg {String} disabledDatesText
36348 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36350 disabledDatesText : "Disabled",
36352 * @cfg {Date/String} minValue
36353 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36354 * valid format (defaults to null).
36358 * @cfg {Date/String} maxValue
36359 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36360 * valid format (defaults to null).
36364 * @cfg {String} minText
36365 * The error text to display when the date in the cell is before minValue (defaults to
36366 * 'The date in this field must be after {minValue}').
36368 minText : "The date in this field must be equal to or after {0}",
36370 * @cfg {String} maxText
36371 * The error text to display when the date in the cell is after maxValue (defaults to
36372 * 'The date in this field must be before {maxValue}').
36374 maxText : "The date in this field must be equal to or before {0}",
36376 * @cfg {String} invalidText
36377 * The error text to display when the date in the field is invalid (defaults to
36378 * '{value} is not a valid date - it must be in the format {format}').
36380 invalidText : "{0} is not a valid date - it must be in the format {1}",
36382 * @cfg {String} triggerClass
36383 * An additional CSS class used to style the trigger button. The trigger will always get the
36384 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36385 * which displays a calendar icon).
36387 triggerClass : 'x-form-date-trigger',
36391 * @cfg {bool} useIso
36392 * if enabled, then the date field will use a hidden field to store the
36393 * real value as iso formated date. default (false)
36397 * @cfg {String/Object} autoCreate
36398 * A DomHelper element spec, or true for a default element spec (defaults to
36399 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36402 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36405 hiddenField: false,
36407 onRender : function(ct, position)
36409 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36411 this.el.dom.removeAttribute('name');
36412 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36414 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36415 // prevent input submission
36416 this.hiddenName = this.name;
36423 validateValue : function(value)
36425 value = this.formatDate(value);
36426 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36429 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36432 var svalue = value;
36433 value = this.parseDate(value);
36435 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36438 var time = value.getTime();
36439 if(this.minValue && time < this.minValue.getTime()){
36440 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36443 if(this.maxValue && time > this.maxValue.getTime()){
36444 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36447 if(this.disabledDays){
36448 var day = value.getDay();
36449 for(var i = 0; i < this.disabledDays.length; i++) {
36450 if(day === this.disabledDays[i]){
36451 this.markInvalid(this.disabledDaysText);
36456 var fvalue = this.formatDate(value);
36457 if(this.ddMatch && this.ddMatch.test(fvalue)){
36458 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36465 // Provides logic to override the default TriggerField.validateBlur which just returns true
36466 validateBlur : function(){
36467 return !this.menu || !this.menu.isVisible();
36471 * Returns the current date value of the date field.
36472 * @return {Date} The date value
36474 getValue : function(){
36476 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36480 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36481 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36482 * (the default format used is "m/d/y").
36485 //All of these calls set the same date value (May 4, 2006)
36487 //Pass a date object:
36488 var dt = new Date('5/4/06');
36489 dateField.setValue(dt);
36491 //Pass a date string (default format):
36492 dateField.setValue('5/4/06');
36494 //Pass a date string (custom format):
36495 dateField.format = 'Y-m-d';
36496 dateField.setValue('2006-5-4');
36498 * @param {String/Date} date The date or valid date string
36500 setValue : function(date){
36501 if (this.hiddenField) {
36502 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36504 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36508 parseDate : function(value){
36509 if(!value || value instanceof Date){
36512 var v = Date.parseDate(value, this.format);
36513 if(!v && this.altFormats){
36514 if(!this.altFormatsArray){
36515 this.altFormatsArray = this.altFormats.split("|");
36517 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36518 v = Date.parseDate(value, this.altFormatsArray[i]);
36525 formatDate : function(date, fmt){
36526 return (!date || !(date instanceof Date)) ?
36527 date : date.dateFormat(fmt || this.format);
36532 select: function(m, d){
36534 this.fireEvent('select', this, d);
36536 show : function(){ // retain focus styling
36540 this.focus.defer(10, this);
36541 var ml = this.menuListeners;
36542 this.menu.un("select", ml.select, this);
36543 this.menu.un("show", ml.show, this);
36544 this.menu.un("hide", ml.hide, this);
36549 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36550 onTriggerClick : function(){
36554 if(this.menu == null){
36555 this.menu = new Roo.menu.DateMenu();
36557 Roo.apply(this.menu.picker, {
36558 showClear: this.allowBlank,
36559 minDate : this.minValue,
36560 maxDate : this.maxValue,
36561 disabledDatesRE : this.ddMatch,
36562 disabledDatesText : this.disabledDatesText,
36563 disabledDays : this.disabledDays,
36564 disabledDaysText : this.disabledDaysText,
36565 format : this.format,
36566 minText : String.format(this.minText, this.formatDate(this.minValue)),
36567 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36569 this.menu.on(Roo.apply({}, this.menuListeners, {
36572 this.menu.picker.setValue(this.getValue() || new Date());
36573 this.menu.show(this.el, "tl-bl?");
36576 beforeBlur : function(){
36577 var v = this.parseDate(this.getRawValue());
36583 /** @cfg {Boolean} grow @hide */
36584 /** @cfg {Number} growMin @hide */
36585 /** @cfg {Number} growMax @hide */
36592 * Ext JS Library 1.1.1
36593 * Copyright(c) 2006-2007, Ext JS, LLC.
36595 * Originally Released Under LGPL - original licence link has changed is not relivant.
36598 * <script type="text/javascript">
36603 * @class Roo.form.ComboBox
36604 * @extends Roo.form.TriggerField
36605 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36607 * Create a new ComboBox.
36608 * @param {Object} config Configuration options
36610 Roo.form.ComboBox = function(config){
36611 Roo.form.ComboBox.superclass.constructor.call(this, config);
36615 * Fires when the dropdown list is expanded
36616 * @param {Roo.form.ComboBox} combo This combo box
36621 * Fires when the dropdown list is collapsed
36622 * @param {Roo.form.ComboBox} combo This combo box
36626 * @event beforeselect
36627 * Fires before a list item is selected. Return false to cancel the selection.
36628 * @param {Roo.form.ComboBox} combo This combo box
36629 * @param {Roo.data.Record} record The data record returned from the underlying store
36630 * @param {Number} index The index of the selected item in the dropdown list
36632 'beforeselect' : true,
36635 * Fires when a list item is selected
36636 * @param {Roo.form.ComboBox} combo This combo box
36637 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
36638 * @param {Number} index The index of the selected item in the dropdown list
36642 * @event beforequery
36643 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
36644 * The event object passed has these properties:
36645 * @param {Roo.form.ComboBox} combo This combo box
36646 * @param {String} query The query
36647 * @param {Boolean} forceAll true to force "all" query
36648 * @param {Boolean} cancel true to cancel the query
36649 * @param {Object} e The query event object
36651 'beforequery': true
36653 if(this.transform){
36654 this.allowDomMove = false;
36655 var s = Roo.getDom(this.transform);
36656 if(!this.hiddenName){
36657 this.hiddenName = s.name;
36660 this.mode = 'local';
36661 var d = [], opts = s.options;
36662 for(var i = 0, len = opts.length;i < len; i++){
36664 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
36666 this.value = value;
36668 d.push([value, o.text]);
36670 this.store = new Roo.data.SimpleStore({
36672 fields: ['value', 'text'],
36675 this.valueField = 'value';
36676 this.displayField = 'text';
36678 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
36679 if(!this.lazyRender){
36680 this.target = true;
36681 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
36682 s.parentNode.removeChild(s); // remove it
36683 this.render(this.el.parentNode);
36685 s.parentNode.removeChild(s); // remove it
36690 this.store = Roo.factory(this.store, Roo.data);
36693 this.selectedIndex = -1;
36694 if(this.mode == 'local'){
36695 if(config.queryDelay === undefined){
36696 this.queryDelay = 10;
36698 if(config.minChars === undefined){
36704 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
36706 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
36709 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
36710 * rendering into an Roo.Editor, defaults to false)
36713 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
36714 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
36717 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
36720 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
36721 * the dropdown list (defaults to undefined, with no header element)
36725 * @cfg {String/Roo.Template} tpl The template to use to render the output
36729 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
36731 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
36733 listWidth: undefined,
36735 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
36736 * mode = 'remote' or 'text' if mode = 'local')
36738 displayField: undefined,
36740 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
36741 * mode = 'remote' or 'value' if mode = 'local').
36742 * Note: use of a valueField requires the user make a selection
36743 * in order for a value to be mapped.
36745 valueField: undefined,
36747 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
36748 * field's data value (defaults to the underlying DOM element's name)
36750 hiddenName: undefined,
36752 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
36756 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
36758 selectedClass: 'x-combo-selected',
36760 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36761 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
36762 * which displays a downward arrow icon).
36764 triggerClass : 'x-form-arrow-trigger',
36766 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
36770 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
36771 * anchor positions (defaults to 'tl-bl')
36773 listAlign: 'tl-bl?',
36775 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
36779 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
36780 * query specified by the allQuery config option (defaults to 'query')
36782 triggerAction: 'query',
36784 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
36785 * (defaults to 4, does not apply if editable = false)
36789 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
36790 * delay (typeAheadDelay) if it matches a known value (defaults to false)
36794 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
36795 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
36799 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
36800 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
36804 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
36805 * when editable = true (defaults to false)
36807 selectOnFocus:false,
36809 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
36811 queryParam: 'query',
36813 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
36814 * when mode = 'remote' (defaults to 'Loading...')
36816 loadingText: 'Loading...',
36818 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
36822 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
36826 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
36827 * traditional select (defaults to true)
36831 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
36835 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
36839 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
36840 * listWidth has a higher value)
36844 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
36845 * allow the user to set arbitrary text into the field (defaults to false)
36847 forceSelection:false,
36849 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
36850 * if typeAhead = true (defaults to 250)
36852 typeAheadDelay : 250,
36854 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
36855 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
36857 valueNotFoundText : undefined,
36859 * @cfg {bool} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
36861 blockFocus : false,
36864 * @cfg {bool} disableClear Disable showing of clear button.
36866 disableClear : false,
36869 onRender : function(ct, position){
36870 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
36871 if(this.hiddenName){
36872 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
36874 this.hiddenField.value =
36875 this.hiddenValue !== undefined ? this.hiddenValue :
36876 this.value !== undefined ? this.value : '';
36878 // prevent input submission
36879 this.el.dom.removeAttribute('name');
36882 this.el.dom.setAttribute('autocomplete', 'off');
36885 var cls = 'x-combo-list';
36887 this.list = new Roo.Layer({
36888 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
36891 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
36892 this.list.setWidth(lw);
36893 this.list.swallowEvent('mousewheel');
36894 this.assetHeight = 0;
36897 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
36898 this.assetHeight += this.header.getHeight();
36901 this.innerList = this.list.createChild({cls:cls+'-inner'});
36902 this.innerList.on('mouseover', this.onViewOver, this);
36903 this.innerList.on('mousemove', this.onViewMove, this);
36904 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
36906 if(this.allowBlank && !this.pageSize && !this.disableClear){
36907 this.footer = this.list.createChild({cls:cls+'-ft'});
36908 this.pageTb = new Roo.Toolbar(this.footer);
36912 this.footer = this.list.createChild({cls:cls+'-ft'});
36913 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
36914 {pageSize: this.pageSize});
36918 if (this.pageTb && this.allowBlank && !this.disableClear) {
36920 this.pageTb.add(new Roo.Toolbar.Fill(), {
36921 cls: 'x-btn-icon x-btn-clear',
36923 handler: function()
36926 _this.clearValue();
36927 _this.onSelect(false, -1);
36932 this.assetHeight += this.footer.getHeight();
36937 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
36940 this.view = new Roo.View(this.innerList, this.tpl, {
36941 singleSelect:true, store: this.store, selectedClass: this.selectedClass
36944 this.view.on('click', this.onViewClick, this);
36946 this.store.on('beforeload', this.onBeforeLoad, this);
36947 this.store.on('load', this.onLoad, this);
36948 this.store.on('loadexception', this.collapse, this);
36950 if(this.resizable){
36951 this.resizer = new Roo.Resizable(this.list, {
36952 pinned:true, handles:'se'
36954 this.resizer.on('resize', function(r, w, h){
36955 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
36956 this.listWidth = w;
36957 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
36958 this.restrictHeight();
36960 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
36962 if(!this.editable){
36963 this.editable = true;
36964 this.setEditable(false);
36969 initEvents : function(){
36970 Roo.form.ComboBox.superclass.initEvents.call(this);
36972 this.keyNav = new Roo.KeyNav(this.el, {
36973 "up" : function(e){
36974 this.inKeyMode = true;
36978 "down" : function(e){
36979 if(!this.isExpanded()){
36980 this.onTriggerClick();
36982 this.inKeyMode = true;
36987 "enter" : function(e){
36988 this.onViewClick();
36992 "esc" : function(e){
36996 "tab" : function(e){
36997 this.onViewClick(false);
37003 doRelay : function(foo, bar, hname){
37004 if(hname == 'down' || this.scope.isExpanded()){
37005 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37012 this.queryDelay = Math.max(this.queryDelay || 10,
37013 this.mode == 'local' ? 10 : 250);
37014 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37015 if(this.typeAhead){
37016 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37018 if(this.editable !== false){
37019 this.el.on("keyup", this.onKeyUp, this);
37021 if(this.forceSelection){
37022 this.on('blur', this.doForce, this);
37026 onDestroy : function(){
37028 this.view.setStore(null);
37029 this.view.el.removeAllListeners();
37030 this.view.el.remove();
37031 this.view.purgeListeners();
37034 this.list.destroy();
37037 this.store.un('beforeload', this.onBeforeLoad, this);
37038 this.store.un('load', this.onLoad, this);
37039 this.store.un('loadexception', this.collapse, this);
37041 Roo.form.ComboBox.superclass.onDestroy.call(this);
37045 fireKey : function(e){
37046 if(e.isNavKeyPress() && !this.list.isVisible()){
37047 this.fireEvent("specialkey", this, e);
37052 onResize: function(w, h){
37053 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37054 if(this.list && this.listWidth === undefined){
37055 var lw = Math.max(w, this.minListWidth);
37056 this.list.setWidth(lw);
37057 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37062 * Allow or prevent the user from directly editing the field text. If false is passed,
37063 * the user will only be able to select from the items defined in the dropdown list. This method
37064 * is the runtime equivalent of setting the 'editable' config option at config time.
37065 * @param {Boolean} value True to allow the user to directly edit the field text
37067 setEditable : function(value){
37068 if(value == this.editable){
37071 this.editable = value;
37073 this.el.dom.setAttribute('readOnly', true);
37074 this.el.on('mousedown', this.onTriggerClick, this);
37075 this.el.addClass('x-combo-noedit');
37077 this.el.dom.setAttribute('readOnly', false);
37078 this.el.un('mousedown', this.onTriggerClick, this);
37079 this.el.removeClass('x-combo-noedit');
37084 onBeforeLoad : function(){
37085 if(!this.hasFocus){
37088 this.innerList.update(this.loadingText ?
37089 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37090 this.restrictHeight();
37091 this.selectedIndex = -1;
37095 onLoad : function(){
37096 if(!this.hasFocus){
37099 if(this.store.getCount() > 0){
37101 this.restrictHeight();
37102 if(this.lastQuery == this.allQuery){
37104 this.el.dom.select();
37106 if(!this.selectByValue(this.value, true)){
37107 this.select(0, true);
37111 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37112 this.taTask.delay(this.typeAheadDelay);
37116 this.onEmptyResults();
37122 onTypeAhead : function(){
37123 if(this.store.getCount() > 0){
37124 var r = this.store.getAt(0);
37125 var newValue = r.data[this.displayField];
37126 var len = newValue.length;
37127 var selStart = this.getRawValue().length;
37128 if(selStart != len){
37129 this.setRawValue(newValue);
37130 this.selectText(selStart, newValue.length);
37136 onSelect : function(record, index){
37137 if(this.fireEvent('beforeselect', this, record, index) !== false){
37138 this.setFromData(index > -1 ? record.data : false);
37140 this.fireEvent('select', this, record, index);
37145 * Returns the currently selected field value or empty string if no value is set.
37146 * @return {String} value The selected value
37148 getValue : function(){
37149 if(this.valueField){
37150 return typeof this.value != 'undefined' ? this.value : '';
37152 return Roo.form.ComboBox.superclass.getValue.call(this);
37157 * Clears any text/value currently set in the field
37159 clearValue : function(){
37160 if(this.hiddenField){
37161 this.hiddenField.value = '';
37164 this.setRawValue('');
37165 this.lastSelectionText = '';
37166 this.applyEmptyText();
37170 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37171 * will be displayed in the field. If the value does not match the data value of an existing item,
37172 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37173 * Otherwise the field will be blank (although the value will still be set).
37174 * @param {String} value The value to match
37176 setValue : function(v){
37178 if(this.valueField){
37179 var r = this.findRecord(this.valueField, v);
37181 text = r.data[this.displayField];
37182 }else if(this.valueNotFoundText !== undefined){
37183 text = this.valueNotFoundText;
37186 this.lastSelectionText = text;
37187 if(this.hiddenField){
37188 this.hiddenField.value = v;
37190 Roo.form.ComboBox.superclass.setValue.call(this, text);
37194 * @property {Object} the last set data for the element
37199 * Sets the value of the field based on a object which is related to the record format for the store.
37200 * @param {Object} value the value to set as. or false on reset?
37202 setFromData : function(o){
37203 var dv = ''; // display value
37204 var vv = ''; // value value..
37206 if (this.displayField) {
37207 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37209 // this is an error condition!!!
37210 console.log('no value field set for '+ this.name);
37213 if(this.valueField){
37214 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37216 if(this.hiddenField){
37217 this.hiddenField.value = vv;
37219 this.lastSelectionText = dv;
37220 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37224 // no hidden field.. - we store the value in 'value', but still display
37225 // display field!!!!
37226 this.lastSelectionText = dv;
37227 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37233 reset : function(){
37234 // overridden so that last data is reset..
37235 this.setValue(this.originalValue);
37236 this.clearInvalid();
37237 this.lastData = false;
37240 findRecord : function(prop, value){
37242 if(this.store.getCount() > 0){
37243 this.store.each(function(r){
37244 if(r.data[prop] == value){
37254 onViewMove : function(e, t){
37255 this.inKeyMode = false;
37259 onViewOver : function(e, t){
37260 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37263 var item = this.view.findItemFromChild(t);
37265 var index = this.view.indexOf(item);
37266 this.select(index, false);
37271 onViewClick : function(doFocus){
37272 var index = this.view.getSelectedIndexes()[0];
37273 var r = this.store.getAt(index);
37275 this.onSelect(r, index);
37277 if(doFocus !== false && !this.blockFocus){
37283 restrictHeight : function(){
37284 this.innerList.dom.style.height = '';
37285 var inner = this.innerList.dom;
37286 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37287 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37288 this.list.beginUpdate();
37289 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37290 this.list.alignTo(this.el, this.listAlign);
37291 this.list.endUpdate();
37295 onEmptyResults : function(){
37300 * Returns true if the dropdown list is expanded, else false.
37302 isExpanded : function(){
37303 return this.list.isVisible();
37307 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37308 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37309 * @param {String} value The data value of the item to select
37310 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37311 * selected item if it is not currently in view (defaults to true)
37312 * @return {Boolean} True if the value matched an item in the list, else false
37314 selectByValue : function(v, scrollIntoView){
37315 if(v !== undefined && v !== null){
37316 var r = this.findRecord(this.valueField || this.displayField, v);
37318 this.select(this.store.indexOf(r), scrollIntoView);
37326 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37327 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37328 * @param {Number} index The zero-based index of the list item to select
37329 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37330 * selected item if it is not currently in view (defaults to true)
37332 select : function(index, scrollIntoView){
37333 this.selectedIndex = index;
37334 this.view.select(index);
37335 if(scrollIntoView !== false){
37336 var el = this.view.getNode(index);
37338 this.innerList.scrollChildIntoView(el, false);
37344 selectNext : function(){
37345 var ct = this.store.getCount();
37347 if(this.selectedIndex == -1){
37349 }else if(this.selectedIndex < ct-1){
37350 this.select(this.selectedIndex+1);
37356 selectPrev : function(){
37357 var ct = this.store.getCount();
37359 if(this.selectedIndex == -1){
37361 }else if(this.selectedIndex != 0){
37362 this.select(this.selectedIndex-1);
37368 onKeyUp : function(e){
37369 if(this.editable !== false && !e.isSpecialKey()){
37370 this.lastKey = e.getKey();
37371 this.dqTask.delay(this.queryDelay);
37376 validateBlur : function(){
37377 return !this.list || !this.list.isVisible();
37381 initQuery : function(){
37382 this.doQuery(this.getRawValue());
37386 doForce : function(){
37387 if(this.el.dom.value.length > 0){
37388 this.el.dom.value =
37389 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37390 this.applyEmptyText();
37395 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37396 * query allowing the query action to be canceled if needed.
37397 * @param {String} query The SQL query to execute
37398 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37399 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37400 * saved in the current store (defaults to false)
37402 doQuery : function(q, forceAll){
37403 if(q === undefined || q === null){
37408 forceAll: forceAll,
37412 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37416 forceAll = qe.forceAll;
37417 if(forceAll === true || (q.length >= this.minChars)){
37418 if(this.lastQuery != q){
37419 this.lastQuery = q;
37420 if(this.mode == 'local'){
37421 this.selectedIndex = -1;
37423 this.store.clearFilter();
37425 this.store.filter(this.displayField, q);
37429 this.store.baseParams[this.queryParam] = q;
37431 params: this.getParams(q)
37436 this.selectedIndex = -1;
37443 getParams : function(q){
37445 //p[this.queryParam] = q;
37448 p.limit = this.pageSize;
37454 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37456 collapse : function(){
37457 if(!this.isExpanded()){
37461 Roo.get(document).un('mousedown', this.collapseIf, this);
37462 Roo.get(document).un('mousewheel', this.collapseIf, this);
37463 this.fireEvent('collapse', this);
37467 collapseIf : function(e){
37468 if(!e.within(this.wrap) && !e.within(this.list)){
37474 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37476 expand : function(){
37477 if(this.isExpanded() || !this.hasFocus){
37480 this.list.alignTo(this.el, this.listAlign);
37482 Roo.get(document).on('mousedown', this.collapseIf, this);
37483 Roo.get(document).on('mousewheel', this.collapseIf, this);
37484 this.fireEvent('expand', this);
37488 // Implements the default empty TriggerField.onTriggerClick function
37489 onTriggerClick : function(){
37493 if(this.isExpanded()){
37495 if (!this.blockFocus) {
37500 this.hasFocus = true;
37501 if(this.triggerAction == 'all') {
37502 this.doQuery(this.allQuery, true);
37504 this.doQuery(this.getRawValue());
37506 if (!this.blockFocus) {
37513 * @cfg {Boolean} grow
37517 * @cfg {Number} growMin
37521 * @cfg {Number} growMax
37530 * Ext JS Library 1.1.1
37531 * Copyright(c) 2006-2007, Ext JS, LLC.
37533 * Originally Released Under LGPL - original licence link has changed is not relivant.
37536 * <script type="text/javascript">
37539 * @class Roo.form.Checkbox
37540 * @extends Roo.form.Field
37541 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
37543 * Creates a new Checkbox
37544 * @param {Object} config Configuration options
37546 Roo.form.Checkbox = function(config){
37547 Roo.form.Checkbox.superclass.constructor.call(this, config);
37551 * Fires when the checkbox is checked or unchecked.
37552 * @param {Roo.form.Checkbox} this This checkbox
37553 * @param {Boolean} checked The new checked value
37559 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
37561 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
37563 focusClass : undefined,
37565 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
37567 fieldClass: "x-form-field",
37569 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
37573 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37574 * {tag: "input", type: "checkbox", autocomplete: "off"})
37576 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
37578 * @cfg {String} boxLabel The text that appears beside the checkbox
37582 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
37586 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
37588 valueOff: '0', // value when not checked..
37590 actionMode : 'viewEl',
37593 itemCls : 'x-menu-check-item x-form-item',
37594 groupClass : 'x-menu-group-item',
37595 inputType : 'hidden',
37598 inSetChecked: false, // check that we are not calling self...
37600 inputElement: false, // real input element?
37601 basedOn: false, // ????
37603 isFormField: true, // not sure where this is needed!!!!
37605 onResize : function(){
37606 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
37607 if(!this.boxLabel){
37608 this.el.alignTo(this.wrap, 'c-c');
37612 initEvents : function(){
37613 Roo.form.Checkbox.superclass.initEvents.call(this);
37614 this.el.on("click", this.onClick, this);
37615 this.el.on("change", this.onClick, this);
37619 getResizeEl : function(){
37623 getPositionEl : function(){
37628 onRender : function(ct, position){
37629 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
37631 if(this.inputValue !== undefined){
37632 this.el.dom.value = this.inputValue;
37635 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
37636 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
37637 var viewEl = this.wrap.createChild({
37638 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
37639 this.viewEl = viewEl;
37640 this.wrap.on('click', this.onClick, this);
37642 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
37643 this.el.on('propertychange', this.setFromHidden, this); //ie
37648 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
37649 // viewEl.on('click', this.onClick, this);
37651 //if(this.checked){
37652 this.setChecked(this.checked);
37654 //this.checked = this.el.dom;
37660 initValue : Roo.emptyFn,
37663 * Returns the checked state of the checkbox.
37664 * @return {Boolean} True if checked, else false
37666 getValue : function(){
37668 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
37670 return this.valueOff;
37675 onClick : function(){
37676 this.setChecked(!this.checked);
37678 //if(this.el.dom.checked != this.checked){
37679 // this.setValue(this.el.dom.checked);
37684 * Sets the checked state of the checkbox.
37685 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
37687 setValue : function(v,suppressEvent){
37688 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
37689 //if(this.el && this.el.dom){
37690 // this.el.dom.checked = this.checked;
37691 // this.el.dom.defaultChecked = this.checked;
37693 this.setChecked(v === this.inputValue);
37694 //this.fireEvent("check", this, this.checked);
37697 setChecked : function(state,suppressEvent)
37699 if (this.inSetChecked) {
37700 this.checked = state;
37706 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
37708 this.checked = state;
37709 if(suppressEvent !== true){
37710 this.fireEvent('checkchange', this, state);
37712 this.inSetChecked = true;
37713 this.el.dom.value = state ? this.inputValue : this.valueOff;
37714 this.inSetChecked = false;
37717 // handle setting of hidden value by some other method!!?!?
37718 setFromHidden: function()
37723 //console.log("SET FROM HIDDEN");
37724 //alert('setFrom hidden');
37725 this.setValue(this.el.dom.value);
37728 onDestroy : function()
37731 Roo.get(this.viewEl).remove();
37734 Roo.form.Checkbox.superclass.onDestroy.call(this);
37739 * Ext JS Library 1.1.1
37740 * Copyright(c) 2006-2007, Ext JS, LLC.
37742 * Originally Released Under LGPL - original licence link has changed is not relivant.
37745 * <script type="text/javascript">
37749 * @class Roo.form.Radio
37750 * @extends Roo.form.Checkbox
37751 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
37752 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
37754 * Creates a new Radio
37755 * @param {Object} config Configuration options
37757 Roo.form.Radio = function(){
37758 Roo.form.Radio.superclass.constructor.apply(this, arguments);
37760 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
37761 inputType: 'radio',
37764 * If this radio is part of a group, it will return the selected value
37767 getGroupValue : function(){
37768 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
37770 });//<script type="text/javascript">
37773 * Ext JS Library 1.1.1
37774 * Copyright(c) 2006-2007, Ext JS, LLC.
37775 * licensing@extjs.com
37777 * http://www.extjs.com/license
37783 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
37784 * - IE ? - no idea how much works there.
37792 * @class Ext.form.HtmlEditor
37793 * @extends Ext.form.Field
37794 * Provides a lightweight HTML Editor component.
37795 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
37797 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
37798 * supported by this editor.</b><br/><br/>
37799 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
37800 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
37802 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
37804 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
37808 * @cfg {String} createLinkText The default text for the create link prompt
37810 createLinkText : 'Please enter the URL for the link:',
37812 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
37814 defaultLinkValue : 'http:/'+'/',
37820 // private properties
37821 validationEvent : false,
37823 initialized : false,
37825 sourceEditMode : false,
37826 onFocus : Roo.emptyFn,
37828 hideMode:'offsets',
37829 defaultAutoCreate : {
37831 style:"width:500px;height:300px;",
37832 autocomplete: "off"
37836 initComponent : function(){
37839 * @event initialize
37840 * Fires when the editor is fully initialized (including the iframe)
37841 * @param {HtmlEditor} this
37846 * Fires when the editor is first receives the focus. Any insertion must wait
37847 * until after this event.
37848 * @param {HtmlEditor} this
37852 * @event beforesync
37853 * Fires before the textarea is updated with content from the editor iframe. Return false
37854 * to cancel the sync.
37855 * @param {HtmlEditor} this
37856 * @param {String} html
37860 * @event beforepush
37861 * Fires before the iframe editor is updated with content from the textarea. Return false
37862 * to cancel the push.
37863 * @param {HtmlEditor} this
37864 * @param {String} html
37869 * Fires when the textarea is updated with content from the editor iframe.
37870 * @param {HtmlEditor} this
37871 * @param {String} html
37876 * Fires when the iframe editor is updated with content from the textarea.
37877 * @param {HtmlEditor} this
37878 * @param {String} html
37882 * @event editmodechange
37883 * Fires when the editor switches edit modes
37884 * @param {HtmlEditor} this
37885 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
37887 editmodechange: true,
37889 * @event editorevent
37890 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
37891 * @param {HtmlEditor} this
37898 * Protected method that will not generally be called directly. It
37899 * is called when the editor creates its toolbar. Override this method if you need to
37900 * add custom toolbar buttons.
37901 * @param {HtmlEditor} editor
37903 createToolbar : function(editor){
37904 if (!editor.toolbars || !editor.toolbars.length) {
37905 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
37908 for (var i =0 ; i < editor.toolbars.length;i++) {
37909 editor.toolbars[i].init(editor);
37916 * Protected method that will not generally be called directly. It
37917 * is called when the editor initializes the iframe with HTML contents. Override this method if you
37918 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
37920 getDocMarkup : function(){
37921 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
37925 onRender : function(ct, position){
37926 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
37927 this.el.dom.style.border = '0 none';
37928 this.el.dom.setAttribute('tabIndex', -1);
37929 this.el.addClass('x-hidden');
37930 if(Roo.isIE){ // fix IE 1px bogus margin
37931 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
37933 this.wrap = this.el.wrap({
37934 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
37937 this.frameId = Roo.id();
37938 this.createToolbar(this);
37945 var iframe = this.wrap.createChild({
37948 name: this.frameId,
37949 frameBorder : 'no',
37950 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
37953 // console.log(iframe);
37954 //this.wrap.dom.appendChild(iframe);
37956 this.iframe = iframe.dom;
37958 this.assignDocWin();
37960 this.doc.designMode = 'on';
37963 this.doc.write(this.getDocMarkup());
37967 var task = { // must defer to wait for browser to be ready
37969 //console.log("run task?" + this.doc.readyState);
37970 this.assignDocWin();
37971 if(this.doc.body || this.doc.readyState == 'complete'){
37975 this.doc.designMode="on";
37979 Roo.TaskMgr.stop(task);
37980 this.initEditor.defer(10, this);
37987 Roo.TaskMgr.start(task);
37990 this.setSize(this.el.getSize());
37995 onResize : function(w, h){
37996 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
37997 if(this.el && this.iframe){
37998 if(typeof w == 'number'){
37999 var aw = w - this.wrap.getFrameWidth('lr');
38000 this.el.setWidth(this.adjustWidth('textarea', aw));
38001 this.iframe.style.width = aw + 'px';
38003 if(typeof h == 'number'){
38005 for (var i =0; i < this.toolbars.length;i++) {
38006 // fixme - ask toolbars for heights?
38007 tbh += this.toolbars[i].tb.el.getHeight();
38013 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38014 this.el.setHeight(this.adjustWidth('textarea', ah));
38015 this.iframe.style.height = ah + 'px';
38017 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38024 * Toggles the editor between standard and source edit mode.
38025 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38027 toggleSourceEdit : function(sourceEditMode){
38029 this.sourceEditMode = sourceEditMode === true;
38031 if(this.sourceEditMode){
38034 this.iframe.className = 'x-hidden';
38035 this.el.removeClass('x-hidden');
38036 this.el.dom.removeAttribute('tabIndex');
38041 this.iframe.className = '';
38042 this.el.addClass('x-hidden');
38043 this.el.dom.setAttribute('tabIndex', -1);
38046 this.setSize(this.wrap.getSize());
38047 this.fireEvent('editmodechange', this, this.sourceEditMode);
38050 // private used internally
38051 createLink : function(){
38052 var url = prompt(this.createLinkText, this.defaultLinkValue);
38053 if(url && url != 'http:/'+'/'){
38054 this.relayCmd('createlink', url);
38058 // private (for BoxComponent)
38059 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38061 // private (for BoxComponent)
38062 getResizeEl : function(){
38066 // private (for BoxComponent)
38067 getPositionEl : function(){
38072 initEvents : function(){
38073 this.originalValue = this.getValue();
38077 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38080 markInvalid : Roo.emptyFn,
38082 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38085 clearInvalid : Roo.emptyFn,
38087 setValue : function(v){
38088 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38093 * Protected method that will not generally be called directly. If you need/want
38094 * custom HTML cleanup, this is the method you should override.
38095 * @param {String} html The HTML to be cleaned
38096 * return {String} The cleaned HTML
38098 cleanHtml : function(html){
38099 html = String(html);
38100 if(html.length > 5){
38101 if(Roo.isSafari){ // strip safari nonsense
38102 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38105 if(html == ' '){
38112 * Protected method that will not generally be called directly. Syncs the contents
38113 * of the editor iframe with the textarea.
38115 syncValue : function(){
38116 if(this.initialized){
38117 var bd = (this.doc.body || this.doc.documentElement);
38118 var html = bd.innerHTML;
38120 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38121 var m = bs.match(/text-align:(.*?);/i);
38123 html = '<div style="'+m[0]+'">' + html + '</div>';
38126 html = this.cleanHtml(html);
38127 if(this.fireEvent('beforesync', this, html) !== false){
38128 this.el.dom.value = html;
38129 this.fireEvent('sync', this, html);
38135 * Protected method that will not generally be called directly. Pushes the value of the textarea
38136 * into the iframe editor.
38138 pushValue : function(){
38139 if(this.initialized){
38140 var v = this.el.dom.value;
38144 if(this.fireEvent('beforepush', this, v) !== false){
38145 (this.doc.body || this.doc.documentElement).innerHTML = v;
38146 this.fireEvent('push', this, v);
38152 deferFocus : function(){
38153 this.focus.defer(10, this);
38157 focus : function(){
38158 if(this.win && !this.sourceEditMode){
38165 assignDocWin: function()
38167 var iframe = this.iframe;
38170 this.doc = iframe.contentWindow.document;
38171 this.win = iframe.contentWindow;
38173 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38174 this.win = Roo.get(this.frameId).dom.contentWindow;
38179 initEditor : function(){
38180 //console.log("INIT EDITOR");
38181 this.assignDocWin();
38185 this.doc.designMode="on";
38187 this.doc.write(this.getDocMarkup());
38190 var dbody = (this.doc.body || this.doc.documentElement);
38191 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38192 // this copies styles from the containing element into thsi one..
38193 // not sure why we need all of this..
38194 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38195 ss['background-attachment'] = 'fixed'; // w3c
38196 dbody.bgProperties = 'fixed'; // ie
38197 Roo.DomHelper.applyStyles(dbody, ss);
38198 Roo.EventManager.on(this.doc, {
38199 'mousedown': this.onEditorEvent,
38200 'dblclick': this.onEditorEvent,
38201 'click': this.onEditorEvent,
38202 'keyup': this.onEditorEvent,
38207 Roo.EventManager.on(this.doc, 'keypress', this.applyCommand, this);
38209 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38210 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38212 this.initialized = true;
38214 this.fireEvent('initialize', this);
38219 onDestroy : function(){
38225 for (var i =0; i < this.toolbars.length;i++) {
38226 // fixme - ask toolbars for heights?
38227 this.toolbars[i].onDestroy();
38230 this.wrap.dom.innerHTML = '';
38231 this.wrap.remove();
38236 onFirstFocus : function(){
38238 this.assignDocWin();
38241 this.activated = true;
38242 for (var i =0; i < this.toolbars.length;i++) {
38243 this.toolbars[i].onFirstFocus();
38246 if(Roo.isGecko){ // prevent silly gecko errors
38248 var s = this.win.getSelection();
38249 if(!s.focusNode || s.focusNode.nodeType != 3){
38250 var r = s.getRangeAt(0);
38251 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38256 this.execCmd('useCSS', true);
38257 this.execCmd('styleWithCSS', false);
38260 this.fireEvent('activate', this);
38264 adjustFont: function(btn){
38265 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38266 //if(Roo.isSafari){ // safari
38269 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38270 if(Roo.isSafari){ // safari
38271 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38272 v = (v < 10) ? 10 : v;
38273 v = (v > 48) ? 48 : v;
38274 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38279 v = Math.max(1, v+adjust);
38281 this.execCmd('FontSize', v );
38284 onEditorEvent : function(e){
38285 this.fireEvent('editorevent', this, e);
38286 // this.updateToolbar();
38290 insertTag : function(tg)
38292 // could be a bit smarter... -> wrap the current selected tRoo..
38294 this.execCmd("formatblock", tg);
38298 insertText : function(txt)
38302 range = this.createRange();
38303 range.deleteContents();
38304 //alert(Sender.getAttribute('label'));
38306 range.insertNode(this.doc.createTextNode(txt));
38310 relayBtnCmd : function(btn){
38311 this.relayCmd(btn.cmd);
38315 * Executes a Midas editor command on the editor document and performs necessary focus and
38316 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38317 * @param {String} cmd The Midas command
38318 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38320 relayCmd : function(cmd, value){
38322 this.execCmd(cmd, value);
38323 this.fireEvent('editorevent', this);
38324 //this.updateToolbar();
38329 * Executes a Midas editor command directly on the editor document.
38330 * For visual commands, you should use {@link #relayCmd} instead.
38331 * <b>This should only be called after the editor is initialized.</b>
38332 * @param {String} cmd The Midas command
38333 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38335 execCmd : function(cmd, value){
38336 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38341 applyCommand : function(e){
38343 var c = e.getCharCode(), cmd;
38345 c = String.fromCharCode(c);
38361 e.preventDefault();
38368 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38370 * @param {String} text
38372 insertAtCursor : function(text){
38373 if(!this.activated){
38378 var r = this.doc.selection.createRange();
38385 }else if(Roo.isGecko || Roo.isOpera){
38387 this.execCmd('InsertHTML', text);
38389 }else if(Roo.isSafari){
38390 this.execCmd('InsertText', text);
38396 fixKeys : function(){ // load time branching for fastest keydown performance
38398 return function(e){
38399 var k = e.getKey(), r;
38402 r = this.doc.selection.createRange();
38405 r.pasteHTML('    ');
38408 }else if(k == e.ENTER){
38409 r = this.doc.selection.createRange();
38411 var target = r.parentElement();
38412 if(!target || target.tagName.toLowerCase() != 'li'){
38414 r.pasteHTML('<br />');
38421 }else if(Roo.isOpera){
38422 return function(e){
38423 var k = e.getKey();
38427 this.execCmd('InsertHTML','    ');
38431 }else if(Roo.isSafari){
38432 return function(e){
38433 var k = e.getKey();
38436 this.execCmd('InsertText','\t');
38443 getAllAncestors: function()
38445 var p = this.getSelectedNode();
38448 a.push(p); // push blank onto stack..
38449 p = this.getParentElement();
38453 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38457 a.push(this.doc.body);
38461 lastSelNode : false,
38464 getSelection : function()
38466 this.assignDocWin();
38467 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38470 getSelectedNode: function()
38472 // this may only work on Gecko!!!
38474 // should we cache this!!!!
38479 var range = this.createRange(this.getSelection());
38482 var parent = range.parentElement();
38484 var testRange = range.duplicate();
38485 testRange.moveToElementText(parent);
38486 if (testRange.inRange(range)) {
38489 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
38492 parent = parent.parentElement;
38498 var ar = range.endContainer.childNodes;
38500 ar = range.commonAncestorContainer.childNodes;
38501 //alert(ar.length);
38504 var other_nodes = [];
38505 var has_other_nodes = false;
38506 for (var i=0;i<ar.length;i++) {
38507 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
38510 // fullly contained node.
38512 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
38517 // probably selected..
38518 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
38519 other_nodes.push(ar[i]);
38522 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
38527 has_other_nodes = true;
38529 if (!nodes.length && other_nodes.length) {
38530 nodes= other_nodes;
38532 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
38538 createRange: function(sel)
38540 // this has strange effects when using with
38541 // top toolbar - not sure if it's a great idea.
38542 //this.editor.contentWindow.focus();
38543 if (typeof sel != "undefined") {
38545 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
38547 return this.doc.createRange();
38550 return this.doc.createRange();
38553 getParentElement: function()
38556 this.assignDocWin();
38557 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
38559 var range = this.createRange(sel);
38562 var p = range.commonAncestorContainer;
38563 while (p.nodeType == 3) { // text node
38575 // BC Hacks - cause I cant work out what i was trying to do..
38576 rangeIntersectsNode : function(range, node)
38578 var nodeRange = node.ownerDocument.createRange();
38580 nodeRange.selectNode(node);
38583 nodeRange.selectNodeContents(node);
38586 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
38587 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
38589 rangeCompareNode : function(range, node) {
38590 var nodeRange = node.ownerDocument.createRange();
38592 nodeRange.selectNode(node);
38594 nodeRange.selectNodeContents(node);
38596 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
38597 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
38599 if (nodeIsBefore && !nodeIsAfter)
38601 if (!nodeIsBefore && nodeIsAfter)
38603 if (nodeIsBefore && nodeIsAfter)
38611 // hide stuff that is not compatible
38625 * @event specialkey
38629 * @cfg {String} fieldClass @hide
38632 * @cfg {String} focusClass @hide
38635 * @cfg {String} autoCreate @hide
38638 * @cfg {String} inputType @hide
38641 * @cfg {String} invalidClass @hide
38644 * @cfg {String} invalidText @hide
38647 * @cfg {String} msgFx @hide
38650 * @cfg {String} validateOnBlur @hide
38652 });// <script type="text/javascript">
38655 * Ext JS Library 1.1.1
38656 * Copyright(c) 2006-2007, Ext JS, LLC.
38662 * @class Roo.form.HtmlEditorToolbar1
38667 new Roo.form.HtmlEditor({
38670 new Roo.form.HtmlEditorToolbar1({
38671 disable : { fonts: 1 , format: 1, ..., ... , ...],
38677 * @cfg {Object} disable List of elements to disable..
38678 * @cfg {Array} btns List of additional buttons.
38682 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
38685 Roo.form.HtmlEditor.ToolbarStandard = function(config)
38688 Roo.apply(this, config);
38689 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
38690 // dont call parent... till later.
38693 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
38701 * @cfg {Object} disable List of toolbar elements to disable
38706 * @cfg {Array} fontFamilies An array of available font families
38724 // "á" , ?? a acute?
38729 "°" // , // degrees
38731 // "é" , // e ecute
38732 // "ú" , // u ecute?
38735 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
38736 "input:submit", "input:button", "select", "textarea", "label" ],
38739 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
38741 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
38744 * @cfg {String} defaultFont default font to use.
38746 defaultFont: 'tahoma',
38748 fontSelect : false,
38751 formatCombo : false,
38753 init : function(editor)
38755 this.editor = editor;
38758 var fid = editor.frameId;
38760 function btn(id, toggle, handler){
38761 var xid = fid + '-'+ id ;
38765 cls : 'x-btn-icon x-edit-'+id,
38766 enableToggle:toggle !== false,
38767 scope: editor, // was editor...
38768 handler:handler||editor.relayBtnCmd,
38769 clickEvent:'mousedown',
38770 tooltip: etb.buttonTips[id] || undefined, ///tips ???
38777 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
38779 // stop form submits
38780 tb.el.on('click', function(e){
38781 e.preventDefault(); // what does this do?
38784 if(!this.disable.font && !Roo.isSafari){
38785 /* why no safari for fonts
38786 editor.fontSelect = tb.el.createChild({
38789 cls:'x-font-select',
38790 html: editor.createFontOptions()
38792 editor.fontSelect.on('change', function(){
38793 var font = editor.fontSelect.dom.value;
38794 editor.relayCmd('fontname', font);
38795 editor.deferFocus();
38798 editor.fontSelect.dom,
38803 if(!this.disable.formats){
38804 this.formatCombo = new Roo.form.ComboBox({
38805 store: new Roo.data.SimpleStore({
38808 data : this.formats // from states.js
38811 //autoCreate : {tag: "div", size: "20"},
38812 displayField:'tag',
38816 triggerAction: 'all',
38817 emptyText:'Add tag',
38818 selectOnFocus:true,
38821 'select': function(c, r, i) {
38822 editor.insertTag(r.get('tag'));
38828 tb.addField(this.formatCombo);
38832 if(!this.disable.format){
38839 if(!this.disable.fontSize){
38844 btn('increasefontsize', false, editor.adjustFont),
38845 btn('decreasefontsize', false, editor.adjustFont)
38850 if(this.disable.colors){
38853 id:editor.frameId +'-forecolor',
38854 cls:'x-btn-icon x-edit-forecolor',
38855 clickEvent:'mousedown',
38856 tooltip: this.buttonTips['forecolor'] || undefined,
38858 menu : new Roo.menu.ColorMenu({
38859 allowReselect: true,
38860 focus: Roo.emptyFn,
38863 selectHandler: function(cp, color){
38864 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
38865 editor.deferFocus();
38868 clickEvent:'mousedown'
38871 id:editor.frameId +'backcolor',
38872 cls:'x-btn-icon x-edit-backcolor',
38873 clickEvent:'mousedown',
38874 tooltip: this.buttonTips['backcolor'] || undefined,
38876 menu : new Roo.menu.ColorMenu({
38877 focus: Roo.emptyFn,
38880 allowReselect: true,
38881 selectHandler: function(cp, color){
38883 editor.execCmd('useCSS', false);
38884 editor.execCmd('hilitecolor', color);
38885 editor.execCmd('useCSS', true);
38886 editor.deferFocus();
38888 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
38889 Roo.isSafari || Roo.isIE ? '#'+color : color);
38890 editor.deferFocus();
38894 clickEvent:'mousedown'
38899 // now add all the items...
38902 if(!this.disable.alignments){
38905 btn('justifyleft'),
38906 btn('justifycenter'),
38907 btn('justifyright')
38911 //if(!Roo.isSafari){
38912 if(!this.disable.links){
38915 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
38919 if(!this.disable.lists){
38922 btn('insertorderedlist'),
38923 btn('insertunorderedlist')
38926 if(!this.disable.sourceEdit){
38929 btn('sourceedit', true, function(btn){
38930 this.toggleSourceEdit(btn.pressed);
38937 // special menu.. - needs to be tidied up..
38938 if (!this.disable.special) {
38941 cls: 'x-edit-none',
38946 for (var i =0; i < this.specialChars.length; i++) {
38947 smenu.menu.items.push({
38949 text: this.specialChars[i],
38950 handler: function(a,b) {
38951 editor.insertAtCursor(String.fromCharCode(a.text.replace('&#','').replace(';', '')));
38963 for(var i =0; i< this.btns.length;i++) {
38964 var b = this.btns[i];
38965 b.cls = 'x-edit-none';
38974 // disable everything...
38976 this.tb.items.each(function(item){
38977 if(item.id != editor.frameId+ '-sourceedit'){
38981 this.rendered = true;
38983 // the all the btns;
38984 editor.on('editorevent', this.updateToolbar, this);
38985 // other toolbars need to implement this..
38986 //editor.on('editmodechange', this.updateToolbar, this);
38992 * Protected method that will not generally be called directly. It triggers
38993 * a toolbar update by reading the markup state of the current selection in the editor.
38995 updateToolbar: function(){
38997 if(!this.editor.activated){
38998 this.editor.onFirstFocus();
39002 var btns = this.tb.items.map,
39003 doc = this.editor.doc,
39004 frameId = this.editor.frameId;
39006 if(!this.disable.font && !Roo.isSafari){
39008 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39009 if(name != this.fontSelect.dom.value){
39010 this.fontSelect.dom.value = name;
39014 if(!this.disable.format){
39015 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39016 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39017 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39019 if(!this.disable.alignments){
39020 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39021 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39022 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39024 if(!Roo.isSafari && !this.disable.lists){
39025 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39026 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39029 var ans = this.editor.getAllAncestors();
39030 if (this.formatCombo) {
39033 var store = this.formatCombo.store;
39034 this.formatCombo.setValue("");
39035 for (var i =0; i < ans.length;i++) {
39036 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), true).length) {
39038 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39046 // hides menus... - so this cant be on a menu...
39047 Roo.menu.MenuMgr.hideAll();
39049 //this.editorsyncValue();
39053 createFontOptions : function(){
39054 var buf = [], fs = this.fontFamilies, ff, lc;
39055 for(var i = 0, len = fs.length; i< len; i++){
39057 lc = ff.toLowerCase();
39059 '<option value="',lc,'" style="font-family:',ff,';"',
39060 (this.defaultFont == lc ? ' selected="true">' : '>'),
39065 return buf.join('');
39068 toggleSourceEdit : function(sourceEditMode){
39069 if(sourceEditMode === undefined){
39070 sourceEditMode = !this.sourceEditMode;
39072 this.sourceEditMode = sourceEditMode === true;
39073 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39074 // just toggle the button?
39075 if(btn.pressed !== this.editor.sourceEditMode){
39076 btn.toggle(this.editor.sourceEditMode);
39080 if(this.sourceEditMode){
39081 this.tb.items.each(function(item){
39082 if(item.cmd != 'sourceedit'){
39088 if(this.initialized){
39089 this.tb.items.each(function(item){
39095 // tell the editor that it's been pressed..
39096 this.editor.toggleSourceEdit(sourceEditMode);
39100 * Object collection of toolbar tooltips for the buttons in the editor. The key
39101 * is the command id associated with that button and the value is a valid QuickTips object.
39106 title: 'Bold (Ctrl+B)',
39107 text: 'Make the selected text bold.',
39108 cls: 'x-html-editor-tip'
39111 title: 'Italic (Ctrl+I)',
39112 text: 'Make the selected text italic.',
39113 cls: 'x-html-editor-tip'
39121 title: 'Bold (Ctrl+B)',
39122 text: 'Make the selected text bold.',
39123 cls: 'x-html-editor-tip'
39126 title: 'Italic (Ctrl+I)',
39127 text: 'Make the selected text italic.',
39128 cls: 'x-html-editor-tip'
39131 title: 'Underline (Ctrl+U)',
39132 text: 'Underline the selected text.',
39133 cls: 'x-html-editor-tip'
39135 increasefontsize : {
39136 title: 'Grow Text',
39137 text: 'Increase the font size.',
39138 cls: 'x-html-editor-tip'
39140 decreasefontsize : {
39141 title: 'Shrink Text',
39142 text: 'Decrease the font size.',
39143 cls: 'x-html-editor-tip'
39146 title: 'Text Highlight Color',
39147 text: 'Change the background color of the selected text.',
39148 cls: 'x-html-editor-tip'
39151 title: 'Font Color',
39152 text: 'Change the color of the selected text.',
39153 cls: 'x-html-editor-tip'
39156 title: 'Align Text Left',
39157 text: 'Align text to the left.',
39158 cls: 'x-html-editor-tip'
39161 title: 'Center Text',
39162 text: 'Center text in the editor.',
39163 cls: 'x-html-editor-tip'
39166 title: 'Align Text Right',
39167 text: 'Align text to the right.',
39168 cls: 'x-html-editor-tip'
39170 insertunorderedlist : {
39171 title: 'Bullet List',
39172 text: 'Start a bulleted list.',
39173 cls: 'x-html-editor-tip'
39175 insertorderedlist : {
39176 title: 'Numbered List',
39177 text: 'Start a numbered list.',
39178 cls: 'x-html-editor-tip'
39181 title: 'Hyperlink',
39182 text: 'Make the selected text a hyperlink.',
39183 cls: 'x-html-editor-tip'
39186 title: 'Source Edit',
39187 text: 'Switch to source editing mode.',
39188 cls: 'x-html-editor-tip'
39192 onDestroy : function(){
39195 this.tb.items.each(function(item){
39197 item.menu.removeAll();
39199 item.menu.el.destroy();
39207 onFirstFocus: function() {
39208 this.tb.items.each(function(item){
39217 // <script type="text/javascript">
39220 * Ext JS Library 1.1.1
39221 * Copyright(c) 2006-2007, Ext JS, LLC.
39228 * @class Roo.form.HtmlEditor.ToolbarContext
39233 new Roo.form.HtmlEditor({
39236 new Roo.form.HtmlEditor.ToolbarStandard(),
39237 new Roo.form.HtmlEditor.ToolbarContext()
39242 * @config : {Object} disable List of elements to disable.. (not done yet.)
39247 Roo.form.HtmlEditor.ToolbarContext = function(config)
39250 Roo.apply(this, config);
39251 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39252 // dont call parent... till later.
39254 Roo.form.HtmlEditor.ToolbarContext.types = {
39266 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39328 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
39333 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
39397 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
39405 * @cfg {Object} disable List of toolbar elements to disable
39414 init : function(editor)
39416 this.editor = editor;
39419 var fid = editor.frameId;
39421 function btn(id, toggle, handler){
39422 var xid = fid + '-'+ id ;
39426 cls : 'x-btn-icon x-edit-'+id,
39427 enableToggle:toggle !== false,
39428 scope: editor, // was editor...
39429 handler:handler||editor.relayBtnCmd,
39430 clickEvent:'mousedown',
39431 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39435 // create a new element.
39436 var wdiv = editor.wrap.createChild({
39438 }, editor.wrap.dom.firstChild.nextSibling, true);
39440 // can we do this more than once??
39442 // stop form submits
39445 // disable everything...
39446 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39447 this.toolbars = {};
39449 for (var i in ty) {
39450 this.toolbars[i] = this.buildToolbar(ty[i],i);
39452 this.tb = this.toolbars.BODY;
39456 this.rendered = true;
39458 // the all the btns;
39459 editor.on('editorevent', this.updateToolbar, this);
39460 // other toolbars need to implement this..
39461 //editor.on('editmodechange', this.updateToolbar, this);
39467 * Protected method that will not generally be called directly. It triggers
39468 * a toolbar update by reading the markup state of the current selection in the editor.
39470 updateToolbar: function(){
39472 if(!this.editor.activated){
39473 this.editor.onFirstFocus();
39478 var ans = this.editor.getAllAncestors();
39481 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39482 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
39483 sel = sel ? sel : this.editor.doc.body;
39484 sel = sel.tagName.length ? sel : this.editor.doc.body;
39485 var tn = sel.tagName.toUpperCase();
39486 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
39487 tn = sel.tagName.toUpperCase();
39488 if (this.tb.name == tn) {
39489 return; // no change
39492 ///console.log("show: " + tn);
39493 this.tb = this.toolbars[tn];
39495 this.tb.fields.each(function(e) {
39496 e.setValue(sel.getAttribute(e.name));
39498 this.tb.selectedNode = sel;
39501 Roo.menu.MenuMgr.hideAll();
39503 //this.editorsyncValue();
39508 onDestroy : function(){
39511 this.tb.items.each(function(item){
39513 item.menu.removeAll();
39515 item.menu.el.destroy();
39523 onFirstFocus: function() {
39524 // need to do this for all the toolbars..
39525 this.tb.items.each(function(item){
39529 buildToolbar: function(tlist, nm)
39531 var editor = this.editor;
39532 // create a new element.
39533 var wdiv = editor.wrap.createChild({
39535 }, editor.wrap.dom.firstChild.nextSibling, true);
39538 var tb = new Roo.Toolbar(wdiv);
39539 tb.add(nm+ ": ");
39540 for (var i in tlist) {
39541 var item = tlist[i];
39542 tb.add(item.title + ": ");
39547 tb.addField( new Roo.form.ComboBox({
39548 store: new Roo.data.SimpleStore({
39551 data : item.opts // from states.js
39554 displayField:'val',
39558 triggerAction: 'all',
39559 emptyText:'Select',
39560 selectOnFocus:true,
39561 width: item.width ? item.width : 130,
39563 'select': function(c, r, i) {
39564 tb.selectedNode.setAttribute(c.name, r.get('val'));
39575 tb.addField( new Roo.form.TextField({
39578 //allowBlank:false,
39583 tb.addField( new Roo.form.TextField({
39589 'change' : function(f, nv, ov) {
39590 tb.selectedNode.setAttribute(f.name, nv);
39596 tb.el.on('click', function(e){
39597 e.preventDefault(); // what does this do?
39599 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
39602 // dont need to disable them... as they will get hidden
39619 * Ext JS Library 1.1.1
39620 * Copyright(c) 2006-2007, Ext JS, LLC.
39622 * Originally Released Under LGPL - original licence link has changed is not relivant.
39625 * <script type="text/javascript">
39629 * @class Roo.form.BasicForm
39630 * @extends Roo.util.Observable
39631 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
39633 * @param {String/HTMLElement/Roo.Element} el The form element or its id
39634 * @param {Object} config Configuration options
39636 Roo.form.BasicForm = function(el, config){
39637 this.allItems = [];
39638 this.childForms = [];
39639 Roo.apply(this, config);
39641 * The Roo.form.Field items in this form.
39642 * @type MixedCollection
39646 this.items = new Roo.util.MixedCollection(false, function(o){
39647 return o.id || (o.id = Roo.id());
39651 * @event beforeaction
39652 * Fires before any action is performed. Return false to cancel the action.
39653 * @param {Form} this
39654 * @param {Action} action The action to be performed
39656 beforeaction: true,
39658 * @event actionfailed
39659 * Fires when an action fails.
39660 * @param {Form} this
39661 * @param {Action} action The action that failed
39663 actionfailed : true,
39665 * @event actioncomplete
39666 * Fires when an action is completed.
39667 * @param {Form} this
39668 * @param {Action} action The action that completed
39670 actioncomplete : true
39675 Roo.form.BasicForm.superclass.constructor.call(this);
39678 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
39680 * @cfg {String} method
39681 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
39684 * @cfg {DataReader} reader
39685 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
39686 * This is optional as there is built-in support for processing JSON.
39689 * @cfg {DataReader} errorReader
39690 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
39691 * This is completely optional as there is built-in support for processing JSON.
39694 * @cfg {String} url
39695 * The URL to use for form actions if one isn't supplied in the action options.
39698 * @cfg {Boolean} fileUpload
39699 * Set to true if this form is a file upload.
39702 * @cfg {Object} baseParams
39703 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
39706 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
39711 activeAction : null,
39714 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
39715 * or setValues() data instead of when the form was first created.
39717 trackResetOnLoad : false,
39721 * childForms - used for multi-tab forms
39724 childForms : false,
39727 * allItems - full list of fields.
39733 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
39734 * element by passing it or its id or mask the form itself by passing in true.
39737 waitMsgTarget : undefined,
39740 initEl : function(el){
39741 this.el = Roo.get(el);
39742 this.id = this.el.id || Roo.id();
39743 this.el.on('submit', this.onSubmit, this);
39744 this.el.addClass('x-form');
39748 onSubmit : function(e){
39753 * Returns true if client-side validation on the form is successful.
39756 isValid : function(){
39758 this.items.each(function(f){
39767 * Returns true if any fields in this form have changed since their original load.
39770 isDirty : function(){
39772 this.items.each(function(f){
39782 * Performs a predefined action (submit or load) or custom actions you define on this form.
39783 * @param {String} actionName The name of the action type
39784 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
39785 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
39786 * accept other config options):
39788 Property Type Description
39789 ---------------- --------------- ----------------------------------------------------------------------------------
39790 url String The url for the action (defaults to the form's url)
39791 method String The form method to use (defaults to the form's method, or POST if not defined)
39792 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
39793 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
39794 validate the form on the client (defaults to false)
39796 * @return {BasicForm} this
39798 doAction : function(action, options){
39799 if(typeof action == 'string'){
39800 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
39802 if(this.fireEvent('beforeaction', this, action) !== false){
39803 this.beforeAction(action);
39804 action.run.defer(100, action);
39810 * Shortcut to do a submit action.
39811 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39812 * @return {BasicForm} this
39814 submit : function(options){
39815 this.doAction('submit', options);
39820 * Shortcut to do a load action.
39821 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39822 * @return {BasicForm} this
39824 load : function(options){
39825 this.doAction('load', options);
39830 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
39831 * @param {Record} record The record to edit
39832 * @return {BasicForm} this
39834 updateRecord : function(record){
39835 record.beginEdit();
39836 var fs = record.fields;
39837 fs.each(function(f){
39838 var field = this.findField(f.name);
39840 record.set(f.name, field.getValue());
39848 * Loads an Roo.data.Record into this form.
39849 * @param {Record} record The record to load
39850 * @return {BasicForm} this
39852 loadRecord : function(record){
39853 this.setValues(record.data);
39858 beforeAction : function(action){
39859 var o = action.options;
39861 if(this.waitMsgTarget === true){
39862 this.el.mask(o.waitMsg, 'x-mask-loading');
39863 }else if(this.waitMsgTarget){
39864 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
39865 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
39867 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
39873 afterAction : function(action, success){
39874 this.activeAction = null;
39875 var o = action.options;
39877 if(this.waitMsgTarget === true){
39879 }else if(this.waitMsgTarget){
39880 this.waitMsgTarget.unmask();
39882 Roo.MessageBox.updateProgress(1);
39883 Roo.MessageBox.hide();
39890 Roo.callback(o.success, o.scope, [this, action]);
39891 this.fireEvent('actioncomplete', this, action);
39893 Roo.callback(o.failure, o.scope, [this, action]);
39894 this.fireEvent('actionfailed', this, action);
39899 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
39900 * @param {String} id The value to search for
39903 findField : function(id){
39904 var field = this.items.get(id);
39906 this.items.each(function(f){
39907 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
39913 return field || null;
39917 * Add a secondary form to this one,
39918 * Used to provide tabbed forms. One form is primary, with hidden values
39919 * which mirror the elements from the other forms.
39921 * @param {Roo.form.Form} form to add.
39924 addForm : function(form){
39926 this.childForms.push(form);
39927 Roo.each(form.allItems, function (fe) {
39929 if (this.findField(fe.name)) { // already added..
39932 this.add( new Roo.form.Hidden({
39939 * Mark fields in this form invalid in bulk.
39940 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
39941 * @return {BasicForm} this
39943 markInvalid : function(errors){
39944 if(errors instanceof Array){
39945 for(var i = 0, len = errors.length; i < len; i++){
39946 var fieldError = errors[i];
39947 var f = this.findField(fieldError.id);
39949 f.markInvalid(fieldError.msg);
39955 if(typeof errors[id] != 'function' && (field = this.findField(id))){
39956 field.markInvalid(errors[id]);
39960 Roo.each(this.childForms || [], function (f) {
39961 f.markInvalid(errors);
39968 * Set values for fields in this form in bulk.
39969 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
39970 * @return {BasicForm} this
39972 setValues : function(values){
39973 if(values instanceof Array){ // array of objects
39974 for(var i = 0, len = values.length; i < len; i++){
39976 var f = this.findField(v.id);
39978 f.setValue(v.value);
39979 if(this.trackResetOnLoad){
39980 f.originalValue = f.getValue();
39984 }else{ // object hash
39987 if(typeof values[id] != 'function' && (field = this.findField(id))){
39989 if (field.setFromData &&
39990 field.valueField &&
39991 field.displayField &&
39992 // combos' with local stores can
39993 // be queried via setValue()
39994 // to set their value..
39995 (field.store && !field.store.isLocal)
39999 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40000 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40001 field.setFromData(sd);
40004 field.setValue(values[id]);
40008 if(this.trackResetOnLoad){
40009 field.originalValue = field.getValue();
40015 Roo.each(this.childForms || [], function (f) {
40016 f.setValues(values);
40023 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40024 * they are returned as an array.
40025 * @param {Boolean} asString
40028 getValues : function(asString){
40029 if (this.childForms) {
40030 // copy values from the child forms
40031 Roo.each(this.childForms, function (f) {
40033 Roo.each(f.allFields, function (e) {
40034 if (e.name && e.getValue && this.findField(e.name)) {
40035 this.findField(e.name).setValue(e.getValue());
40044 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40045 if(asString === true){
40048 return Roo.urlDecode(fs);
40052 * Clears all invalid messages in this form.
40053 * @return {BasicForm} this
40055 clearInvalid : function(){
40056 this.items.each(function(f){
40060 Roo.each(this.childForms || [], function (f) {
40069 * Resets this form.
40070 * @return {BasicForm} this
40072 reset : function(){
40073 this.items.each(function(f){
40077 Roo.each(this.childForms || [], function (f) {
40086 * Add Roo.form components to this form.
40087 * @param {Field} field1
40088 * @param {Field} field2 (optional)
40089 * @param {Field} etc (optional)
40090 * @return {BasicForm} this
40093 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40099 * Removes a field from the items collection (does NOT remove its markup).
40100 * @param {Field} field
40101 * @return {BasicForm} this
40103 remove : function(field){
40104 this.items.remove(field);
40109 * Looks at the fields in this form, checks them for an id attribute,
40110 * and calls applyTo on the existing dom element with that id.
40111 * @return {BasicForm} this
40113 render : function(){
40114 this.items.each(function(f){
40115 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40123 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40124 * @param {Object} values
40125 * @return {BasicForm} this
40127 applyToFields : function(o){
40128 this.items.each(function(f){
40135 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40136 * @param {Object} values
40137 * @return {BasicForm} this
40139 applyIfToFields : function(o){
40140 this.items.each(function(f){
40148 Roo.BasicForm = Roo.form.BasicForm;/*
40150 * Ext JS Library 1.1.1
40151 * Copyright(c) 2006-2007, Ext JS, LLC.
40153 * Originally Released Under LGPL - original licence link has changed is not relivant.
40156 * <script type="text/javascript">
40160 * @class Roo.form.Form
40161 * @extends Roo.form.BasicForm
40162 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40164 * @param {Object} config Configuration options
40166 Roo.form.Form = function(config){
40168 if (config.items) {
40169 xitems = config.items;
40170 delete config.items;
40174 Roo.form.Form.superclass.constructor.call(this, null, config);
40175 this.url = this.url || this.action;
40177 this.root = new Roo.form.Layout(Roo.applyIf({
40181 this.active = this.root;
40183 * Array of all the buttons that have been added to this form via {@link addButton}
40187 this.allItems = [];
40190 * @event clientvalidation
40191 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40192 * @param {Form} this
40193 * @param {Boolean} valid true if the form has passed client-side validation
40195 clientvalidation: true,
40198 * Fires when the form is rendered
40199 * @param {Roo.form.Form} form
40204 Roo.each(xitems, this.addxtype, this);
40210 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40212 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40215 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40218 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40220 buttonAlign:'center',
40223 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40228 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40229 * This property cascades to child containers if not set.
40234 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40235 * fires a looping event with that state. This is required to bind buttons to the valid
40236 * state using the config value formBind:true on the button.
40238 monitorValid : false,
40241 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40247 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40248 * fields are added and the column is closed. If no fields are passed the column remains open
40249 * until end() is called.
40250 * @param {Object} config The config to pass to the column
40251 * @param {Field} field1 (optional)
40252 * @param {Field} field2 (optional)
40253 * @param {Field} etc (optional)
40254 * @return Column The column container object
40256 column : function(c){
40257 var col = new Roo.form.Column(c);
40259 if(arguments.length > 1){ // duplicate code required because of Opera
40260 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40267 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40268 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40269 * until end() is called.
40270 * @param {Object} config The config to pass to the fieldset
40271 * @param {Field} field1 (optional)
40272 * @param {Field} field2 (optional)
40273 * @param {Field} etc (optional)
40274 * @return FieldSet The fieldset container object
40276 fieldset : function(c){
40277 var fs = new Roo.form.FieldSet(c);
40279 if(arguments.length > 1){ // duplicate code required because of Opera
40280 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40287 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
40288 * fields are added and the container is closed. If no fields are passed the container remains open
40289 * until end() is called.
40290 * @param {Object} config The config to pass to the Layout
40291 * @param {Field} field1 (optional)
40292 * @param {Field} field2 (optional)
40293 * @param {Field} etc (optional)
40294 * @return Layout The container object
40296 container : function(c){
40297 var l = new Roo.form.Layout(c);
40299 if(arguments.length > 1){ // duplicate code required because of Opera
40300 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40307 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
40308 * @param {Object} container A Roo.form.Layout or subclass of Layout
40309 * @return {Form} this
40311 start : function(c){
40312 // cascade label info
40313 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
40314 this.active.stack.push(c);
40315 c.ownerCt = this.active;
40321 * Closes the current open container
40322 * @return {Form} this
40325 if(this.active == this.root){
40328 this.active = this.active.ownerCt;
40333 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
40334 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
40335 * as the label of the field.
40336 * @param {Field} field1
40337 * @param {Field} field2 (optional)
40338 * @param {Field} etc. (optional)
40339 * @return {Form} this
40342 this.active.stack.push.apply(this.active.stack, arguments);
40343 this.allItems.push.apply(this.allItems,arguments);
40345 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
40346 if(a[i].isFormField){
40351 Roo.form.Form.superclass.add.apply(this, r);
40361 * Find any element that has been added to a form, using it's ID or name
40362 * This can include framesets, columns etc. along with regular fields..
40363 * @param {String} id - id or name to find.
40365 * @return {Element} e - or false if nothing found.
40367 findbyId : function(id)
40373 Ext.each(this.allItems, function(f){
40374 if (f.id == id || f.name == id ){
40385 * Render this form into the passed container. This should only be called once!
40386 * @param {String/HTMLElement/Element} container The element this component should be rendered into
40387 * @return {Form} this
40389 render : function(ct){
40391 var o = this.autoCreate || {
40393 method : this.method || 'POST',
40394 id : this.id || Roo.id()
40396 this.initEl(ct.createChild(o));
40398 this.root.render(this.el);
40400 this.items.each(function(f){
40401 f.render('x-form-el-'+f.id);
40404 if(this.buttons.length > 0){
40405 // tables are required to maintain order and for correct IE layout
40406 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
40407 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
40408 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
40410 var tr = tb.getElementsByTagName('tr')[0];
40411 for(var i = 0, len = this.buttons.length; i < len; i++) {
40412 var b = this.buttons[i];
40413 var td = document.createElement('td');
40414 td.className = 'x-form-btn-td';
40415 b.render(tr.appendChild(td));
40418 if(this.monitorValid){ // initialize after render
40419 this.startMonitoring();
40421 this.fireEvent('rendered', this);
40426 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
40427 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
40428 * object or a valid Roo.DomHelper element config
40429 * @param {Function} handler The function called when the button is clicked
40430 * @param {Object} scope (optional) The scope of the handler function
40431 * @return {Roo.Button}
40433 addButton : function(config, handler, scope){
40437 minWidth: this.minButtonWidth,
40440 if(typeof config == "string"){
40443 Roo.apply(bc, config);
40445 var btn = new Roo.Button(null, bc);
40446 this.buttons.push(btn);
40451 * Adds a series of form elements (using the xtype property as the factory method.
40452 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
40453 * @param {Object} config
40456 addxtype : function()
40458 var ar = Array.prototype.slice.call(arguments, 0);
40460 for(var i = 0; i < ar.length; i++) {
40462 continue; // skip -- if this happends something invalid got sent, we
40463 // should ignore it, as basically that interface element will not show up
40464 // and that should be pretty obvious!!
40467 if (Roo.form[ar[i].xtype]) {
40469 var fe = Roo.factory(ar[i], Roo.form);
40475 fe.store.form = this;
40480 this.allItems.push(fe);
40481 if (fe.items && fe.addxtype) {
40482 fe.addxtype.apply(fe, fe.items);
40492 // console.log('adding ' + ar[i].xtype);
40494 if (ar[i].xtype == 'Button') {
40495 //console.log('adding button');
40496 //console.log(ar[i]);
40497 this.addButton(ar[i]);
40498 this.allItems.push(fe);
40502 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
40503 alert('end is not supported on xtype any more, use items');
40505 // //console.log('adding end');
40513 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
40514 * option "monitorValid"
40516 startMonitoring : function(){
40519 Roo.TaskMgr.start({
40520 run : this.bindHandler,
40521 interval : this.monitorPoll || 200,
40528 * Stops monitoring of the valid state of this form
40530 stopMonitoring : function(){
40531 this.bound = false;
40535 bindHandler : function(){
40537 return false; // stops binding
40540 this.items.each(function(f){
40541 if(!f.isValid(true)){
40546 for(var i = 0, len = this.buttons.length; i < len; i++){
40547 var btn = this.buttons[i];
40548 if(btn.formBind === true && btn.disabled === valid){
40549 btn.setDisabled(!valid);
40552 this.fireEvent('clientvalidation', this, valid);
40566 Roo.Form = Roo.form.Form;
40569 * Ext JS Library 1.1.1
40570 * Copyright(c) 2006-2007, Ext JS, LLC.
40572 * Originally Released Under LGPL - original licence link has changed is not relivant.
40575 * <script type="text/javascript">
40579 * @class Roo.form.Action
40580 * Internal Class used to handle form actions
40582 * @param {Roo.form.BasicForm} el The form element or its id
40583 * @param {Object} config Configuration options
40587 // define the action interface
40588 Roo.form.Action = function(form, options){
40590 this.options = options || {};
40593 * Client Validation Failed
40596 Roo.form.Action.CLIENT_INVALID = 'client';
40598 * Server Validation Failed
40601 Roo.form.Action.SERVER_INVALID = 'server';
40603 * Connect to Server Failed
40606 Roo.form.Action.CONNECT_FAILURE = 'connect';
40608 * Reading Data from Server Failed
40611 Roo.form.Action.LOAD_FAILURE = 'load';
40613 Roo.form.Action.prototype = {
40615 failureType : undefined,
40616 response : undefined,
40617 result : undefined,
40619 // interface method
40620 run : function(options){
40624 // interface method
40625 success : function(response){
40629 // interface method
40630 handleResponse : function(response){
40634 // default connection failure
40635 failure : function(response){
40636 this.response = response;
40637 this.failureType = Roo.form.Action.CONNECT_FAILURE;
40638 this.form.afterAction(this, false);
40641 processResponse : function(response){
40642 this.response = response;
40643 if(!response.responseText){
40646 this.result = this.handleResponse(response);
40647 return this.result;
40650 // utility functions used internally
40651 getUrl : function(appendParams){
40652 var url = this.options.url || this.form.url || this.form.el.dom.action;
40654 var p = this.getParams();
40656 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
40662 getMethod : function(){
40663 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
40666 getParams : function(){
40667 var bp = this.form.baseParams;
40668 var p = this.options.params;
40670 if(typeof p == "object"){
40671 p = Roo.urlEncode(Roo.applyIf(p, bp));
40672 }else if(typeof p == 'string' && bp){
40673 p += '&' + Roo.urlEncode(bp);
40676 p = Roo.urlEncode(bp);
40681 createCallback : function(){
40683 success: this.success,
40684 failure: this.failure,
40686 timeout: (this.form.timeout*1000),
40687 upload: this.form.fileUpload ? this.success : undefined
40692 Roo.form.Action.Submit = function(form, options){
40693 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
40696 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
40700 var o = this.options;
40701 var method = this.getMethod();
40702 var isPost = method == 'POST';
40703 if(o.clientValidation === false || this.form.isValid()){
40704 Roo.Ajax.request(Roo.apply(this.createCallback(), {
40705 form:this.form.el.dom,
40706 url:this.getUrl(!isPost),
40708 params:isPost ? this.getParams() : null,
40709 isUpload: this.form.fileUpload
40712 }else if (o.clientValidation !== false){ // client validation failed
40713 this.failureType = Roo.form.Action.CLIENT_INVALID;
40714 this.form.afterAction(this, false);
40718 success : function(response){
40719 var result = this.processResponse(response);
40720 if(result === true || result.success){
40721 this.form.afterAction(this, true);
40725 this.form.markInvalid(result.errors);
40726 this.failureType = Roo.form.Action.SERVER_INVALID;
40728 this.form.afterAction(this, false);
40731 handleResponse : function(response){
40732 if(this.form.errorReader){
40733 var rs = this.form.errorReader.read(response);
40736 for(var i = 0, len = rs.records.length; i < len; i++) {
40737 var r = rs.records[i];
40738 errors[i] = r.data;
40741 if(errors.length < 1){
40745 success : rs.success,
40751 ret = Roo.decode(response.responseText);
40755 errorMsg: "Failed to read server message: " + response.responseText,
40765 Roo.form.Action.Load = function(form, options){
40766 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
40767 this.reader = this.form.reader;
40770 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
40774 Roo.Ajax.request(Roo.apply(
40775 this.createCallback(), {
40776 method:this.getMethod(),
40777 url:this.getUrl(false),
40778 params:this.getParams()
40782 success : function(response){
40783 var result = this.processResponse(response);
40784 if(result === true || !result.success || !result.data){
40785 this.failureType = Roo.form.Action.LOAD_FAILURE;
40786 this.form.afterAction(this, false);
40789 this.form.clearInvalid();
40790 this.form.setValues(result.data);
40791 this.form.afterAction(this, true);
40794 handleResponse : function(response){
40795 if(this.form.reader){
40796 var rs = this.form.reader.read(response);
40797 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
40799 success : rs.success,
40803 return Roo.decode(response.responseText);
40807 Roo.form.Action.ACTION_TYPES = {
40808 'load' : Roo.form.Action.Load,
40809 'submit' : Roo.form.Action.Submit
40812 * Ext JS Library 1.1.1
40813 * Copyright(c) 2006-2007, Ext JS, LLC.
40815 * Originally Released Under LGPL - original licence link has changed is not relivant.
40818 * <script type="text/javascript">
40822 * @class Roo.form.Layout
40823 * @extends Roo.Component
40824 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
40826 * @param {Object} config Configuration options
40828 Roo.form.Layout = function(config){
40830 if (config.items) {
40831 xitems = config.items;
40832 delete config.items;
40834 Roo.form.Layout.superclass.constructor.call(this, config);
40836 Roo.each(xitems, this.addxtype, this);
40840 Roo.extend(Roo.form.Layout, Roo.Component, {
40842 * @cfg {String/Object} autoCreate
40843 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
40846 * @cfg {String/Object/Function} style
40847 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
40848 * a function which returns such a specification.
40851 * @cfg {String} labelAlign
40852 * Valid values are "left," "top" and "right" (defaults to "left")
40855 * @cfg {Number} labelWidth
40856 * Fixed width in pixels of all field labels (defaults to undefined)
40859 * @cfg {Boolean} clear
40860 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
40864 * @cfg {String} labelSeparator
40865 * The separator to use after field labels (defaults to ':')
40867 labelSeparator : ':',
40869 * @cfg {Boolean} hideLabels
40870 * True to suppress the display of field labels in this layout (defaults to false)
40872 hideLabels : false,
40875 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
40880 onRender : function(ct, position){
40881 if(this.el){ // from markup
40882 this.el = Roo.get(this.el);
40883 }else { // generate
40884 var cfg = this.getAutoCreate();
40885 this.el = ct.createChild(cfg, position);
40888 this.el.applyStyles(this.style);
40890 if(this.labelAlign){
40891 this.el.addClass('x-form-label-'+this.labelAlign);
40893 if(this.hideLabels){
40894 this.labelStyle = "display:none";
40895 this.elementStyle = "padding-left:0;";
40897 if(typeof this.labelWidth == 'number'){
40898 this.labelStyle = "width:"+this.labelWidth+"px;";
40899 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
40901 if(this.labelAlign == 'top'){
40902 this.labelStyle = "width:auto;";
40903 this.elementStyle = "padding-left:0;";
40906 var stack = this.stack;
40907 var slen = stack.length;
40909 if(!this.fieldTpl){
40910 var t = new Roo.Template(
40911 '<div class="x-form-item {5}">',
40912 '<label for="{0}" style="{2}">{1}{4}</label>',
40913 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
40915 '</div><div class="x-form-clear-left"></div>'
40917 t.disableFormats = true;
40919 Roo.form.Layout.prototype.fieldTpl = t;
40921 for(var i = 0; i < slen; i++) {
40922 if(stack[i].isFormField){
40923 this.renderField(stack[i]);
40925 this.renderComponent(stack[i]);
40930 this.el.createChild({cls:'x-form-clear'});
40935 renderField : function(f){
40936 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
40939 f.labelStyle||this.labelStyle||'', //2
40940 this.elementStyle||'', //3
40941 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
40942 f.itemCls||this.itemCls||'' //5
40943 ], true).getPrevSibling());
40947 renderComponent : function(c){
40948 c.render(c.isLayout ? this.el : this.el.createChild());
40951 * Adds a object form elements (using the xtype property as the factory method.)
40952 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
40953 * @param {Object} config
40955 addxtype : function(o)
40957 // create the lement.
40958 o.form = this.form;
40959 var fe = Roo.factory(o, Roo.form);
40960 this.form.allItems.push(fe);
40961 this.stack.push(fe);
40963 if (fe.isFormField) {
40964 this.form.items.add(fe);
40972 * @class Roo.form.Column
40973 * @extends Roo.form.Layout
40974 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
40976 * @param {Object} config Configuration options
40978 Roo.form.Column = function(config){
40979 Roo.form.Column.superclass.constructor.call(this, config);
40982 Roo.extend(Roo.form.Column, Roo.form.Layout, {
40984 * @cfg {Number/String} width
40985 * The fixed width of the column in pixels or CSS value (defaults to "auto")
40988 * @cfg {String/Object} autoCreate
40989 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
40993 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
40996 onRender : function(ct, position){
40997 Roo.form.Column.superclass.onRender.call(this, ct, position);
40999 this.el.setWidth(this.width);
41006 * @class Roo.form.Row
41007 * @extends Roo.form.Layout
41008 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41010 * @param {Object} config Configuration options
41014 Roo.form.Row = function(config){
41015 Roo.form.Row.superclass.constructor.call(this, config);
41018 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41020 * @cfg {Number/String} width
41021 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41024 * @cfg {Number/String} height
41025 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41027 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41031 onRender : function(ct, position){
41032 //console.log('row render');
41034 var t = new Roo.Template(
41035 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41036 '<label for="{0}" style="{2}">{1}{4}</label>',
41037 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41041 t.disableFormats = true;
41043 Roo.form.Layout.prototype.rowTpl = t;
41045 this.fieldTpl = this.rowTpl;
41047 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41048 var labelWidth = 100;
41050 if ((this.labelAlign != 'top')) {
41051 if (typeof this.labelWidth == 'number') {
41052 labelWidth = this.labelWidth
41054 this.padWidth = 20 + labelWidth;
41058 Roo.form.Column.superclass.onRender.call(this, ct, position);
41060 this.el.setWidth(this.width);
41063 this.el.setHeight(this.height);
41068 renderField : function(f){
41069 f.fieldEl = this.fieldTpl.append(this.el, [
41070 f.id, f.fieldLabel,
41071 f.labelStyle||this.labelStyle||'',
41072 this.elementStyle||'',
41073 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
41074 f.itemCls||this.itemCls||'',
41075 f.width ? f.width + this.padWidth : 160 + this.padWidth
41082 * @class Roo.form.FieldSet
41083 * @extends Roo.form.Layout
41084 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
41086 * @param {Object} config Configuration options
41088 Roo.form.FieldSet = function(config){
41089 Roo.form.FieldSet.superclass.constructor.call(this, config);
41092 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
41094 * @cfg {String} legend
41095 * The text to display as the legend for the FieldSet (defaults to '')
41098 * @cfg {String/Object} autoCreate
41099 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
41103 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
41106 onRender : function(ct, position){
41107 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
41109 this.setLegend(this.legend);
41114 setLegend : function(text){
41116 this.el.child('legend').update(text);
41121 * Ext JS Library 1.1.1
41122 * Copyright(c) 2006-2007, Ext JS, LLC.
41124 * Originally Released Under LGPL - original licence link has changed is not relivant.
41127 * <script type="text/javascript">
41130 * @class Roo.form.VTypes
41131 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
41134 Roo.form.VTypes = function(){
41135 // closure these in so they are only created once.
41136 var alpha = /^[a-zA-Z_]+$/;
41137 var alphanum = /^[a-zA-Z0-9_]+$/;
41138 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
41139 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
41141 // All these messages and functions are configurable
41144 * The function used to validate email addresses
41145 * @param {String} value The email address
41147 'email' : function(v){
41148 return email.test(v);
41151 * The error text to display when the email validation function returns false
41154 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
41156 * The keystroke filter mask to be applied on email input
41159 'emailMask' : /[a-z0-9_\.\-@]/i,
41162 * The function used to validate URLs
41163 * @param {String} value The URL
41165 'url' : function(v){
41166 return url.test(v);
41169 * The error text to display when the url validation function returns false
41172 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
41175 * The function used to validate alpha values
41176 * @param {String} value The value
41178 'alpha' : function(v){
41179 return alpha.test(v);
41182 * The error text to display when the alpha validation function returns false
41185 'alphaText' : 'This field should only contain letters and _',
41187 * The keystroke filter mask to be applied on alpha input
41190 'alphaMask' : /[a-z_]/i,
41193 * The function used to validate alphanumeric values
41194 * @param {String} value The value
41196 'alphanum' : function(v){
41197 return alphanum.test(v);
41200 * The error text to display when the alphanumeric validation function returns false
41203 'alphanumText' : 'This field should only contain letters, numbers and _',
41205 * The keystroke filter mask to be applied on alphanumeric input
41208 'alphanumMask' : /[a-z0-9_]/i
41210 }();//<script type="text/javascript">
41213 * @class Roo.form.FCKeditor
41214 * @extends Roo.form.TextArea
41215 * Wrapper around the FCKEditor http://www.fckeditor.net
41217 * Creates a new FCKeditor
41218 * @param {Object} config Configuration options
41220 Roo.form.FCKeditor = function(config){
41221 Roo.form.FCKeditor.superclass.constructor.call(this, config);
41224 * @event editorinit
41225 * Fired when the editor is initialized - you can add extra handlers here..
41226 * @param {FCKeditor} this
41227 * @param {Object} the FCK object.
41234 Roo.form.FCKeditor.editors = { };
41235 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
41237 //defaultAutoCreate : {
41238 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
41242 * @cfg {Object} fck options - see fck manual for details.
41247 * @cfg {Object} fck toolbar set (Basic or Default)
41249 toolbarSet : 'Basic',
41251 * @cfg {Object} fck BasePath
41253 basePath : '/fckeditor/',
41261 onRender : function(ct, position)
41264 this.defaultAutoCreate = {
41266 style:"width:300px;height:60px;",
41267 autocomplete: "off"
41270 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
41273 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
41274 if(this.preventScrollbars){
41275 this.el.setStyle("overflow", "hidden");
41277 this.el.setHeight(this.growMin);
41280 //console.log('onrender' + this.getId() );
41281 Roo.form.FCKeditor.editors[this.getId()] = this;
41284 this.replaceTextarea() ;
41288 getEditor : function() {
41289 return this.fckEditor;
41292 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
41293 * @param {Mixed} value The value to set
41297 setValue : function(value)
41299 //console.log('setValue: ' + value);
41301 if(typeof(value) == 'undefined') { // not sure why this is happending...
41304 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41306 //if(!this.el || !this.getEditor()) {
41307 // this.value = value;
41308 //this.setValue.defer(100,this,[value]);
41312 if(!this.getEditor()) {
41316 this.getEditor().SetData(value);
41323 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
41324 * @return {Mixed} value The field value
41326 getValue : function()
41329 if (this.frame && this.frame.dom.style.display == 'none') {
41330 return Roo.form.FCKeditor.superclass.getValue.call(this);
41333 if(!this.el || !this.getEditor()) {
41335 // this.getValue.defer(100,this);
41340 var value=this.getEditor().GetData();
41341 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41342 return Roo.form.FCKeditor.superclass.getValue.call(this);
41348 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
41349 * @return {Mixed} value The field value
41351 getRawValue : function()
41353 if (this.frame && this.frame.dom.style.display == 'none') {
41354 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41357 if(!this.el || !this.getEditor()) {
41358 //this.getRawValue.defer(100,this);
41365 var value=this.getEditor().GetData();
41366 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
41367 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41371 setSize : function(w,h) {
41375 //if (this.frame && this.frame.dom.style.display == 'none') {
41376 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41379 //if(!this.el || !this.getEditor()) {
41380 // this.setSize.defer(100,this, [w,h]);
41386 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41388 this.frame.dom.setAttribute('width', w);
41389 this.frame.dom.setAttribute('height', h);
41390 this.frame.setSize(w,h);
41394 toggleSourceEdit : function(value) {
41398 this.el.dom.style.display = value ? '' : 'none';
41399 this.frame.dom.style.display = value ? 'none' : '';
41404 focus: function(tag)
41406 if (this.frame.dom.style.display == 'none') {
41407 return Roo.form.FCKeditor.superclass.focus.call(this);
41409 if(!this.el || !this.getEditor()) {
41410 this.focus.defer(100,this, [tag]);
41417 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
41418 this.getEditor().Focus();
41420 if (!this.getEditor().Selection.GetSelection()) {
41421 this.focus.defer(100,this, [tag]);
41426 var r = this.getEditor().EditorDocument.createRange();
41427 r.setStart(tgs[0],0);
41428 r.setEnd(tgs[0],0);
41429 this.getEditor().Selection.GetSelection().removeAllRanges();
41430 this.getEditor().Selection.GetSelection().addRange(r);
41431 this.getEditor().Focus();
41438 replaceTextarea : function()
41440 if ( document.getElementById( this.getId() + '___Frame' ) )
41442 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
41444 // We must check the elements firstly using the Id and then the name.
41445 var oTextarea = document.getElementById( this.getId() );
41447 var colElementsByName = document.getElementsByName( this.getId() ) ;
41449 oTextarea.style.display = 'none' ;
41451 if ( oTextarea.tabIndex ) {
41452 this.TabIndex = oTextarea.tabIndex ;
41455 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
41456 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
41457 this.frame = Roo.get(this.getId() + '___Frame')
41460 _getConfigHtml : function()
41464 for ( var o in this.fckconfig ) {
41465 sConfig += sConfig.length > 0 ? '&' : '';
41466 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
41469 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
41473 _getIFrameHtml : function()
41475 var sFile = 'fckeditor.html' ;
41476 /* no idea what this is about..
41479 if ( (/fcksource=true/i).test( window.top.location.search ) )
41480 sFile = 'fckeditor.original.html' ;
41485 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
41486 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
41489 var html = '<iframe id="' + this.getId() +
41490 '___Frame" src="' + sLink +
41491 '" width="' + this.width +
41492 '" height="' + this.height + '"' +
41493 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
41494 ' frameborder="0" scrolling="no"></iframe>' ;
41499 _insertHtmlBefore : function( html, element )
41501 if ( element.insertAdjacentHTML ) {
41503 element.insertAdjacentHTML( 'beforeBegin', html ) ;
41505 var oRange = document.createRange() ;
41506 oRange.setStartBefore( element ) ;
41507 var oFragment = oRange.createContextualFragment( html );
41508 element.parentNode.insertBefore( oFragment, element ) ;
41521 //Roo.reg('fckeditor', Roo.form.FCKeditor);
41523 function FCKeditor_OnComplete(editorInstance){
41524 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
41525 f.fckEditor = editorInstance;
41526 //console.log("loaded");
41527 f.fireEvent('editorinit', f, editorInstance);
41547 //<script type="text/javascript">
41549 * @class Roo.form.GridField
41550 * @extends Roo.form.Field
41551 * Embed a grid (or editable grid into a form)
41554 * Creates a new GridField
41555 * @param {Object} config Configuration options
41557 Roo.form.GridField = function(config){
41558 Roo.form.GridField.superclass.constructor.call(this, config);
41562 Roo.extend(Roo.form.GridField, Roo.form.Field, {
41564 * @cfg {Number} width - used to restrict width of grid..
41568 * @cfg {Number} height - used to restrict height of grid..
41572 * @cfg {Object} xgrid (xtype'd description of grid) Grid or EditorGrid
41576 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41577 * {tag: "input", type: "checkbox", autocomplete: "off"})
41579 // defaultAutoCreate : { tag: 'div' },
41580 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
41582 * @cfg {String} addTitle Text to include for adding a title.
41586 onResize : function(){
41587 Roo.form.Field.superclass.onResize.apply(this, arguments);
41590 initEvents : function(){
41591 // Roo.form.Checkbox.superclass.initEvents.call(this);
41592 // has no events...
41597 getResizeEl : function(){
41601 getPositionEl : function(){
41606 onRender : function(ct, position){
41608 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
41609 var style = this.style;
41612 Roo.form.DisplayImage.superclass.onRender.call(this, ct, position);
41613 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
41614 this.viewEl = this.wrap.createChild({ tag: 'div' });
41616 this.viewEl.applyStyles(style);
41619 this.viewEl.setWidth(this.width);
41622 this.viewEl.setHeight(this.height);
41624 //if(this.inputValue !== undefined){
41625 //this.setValue(this.value);
41628 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
41631 this.grid.render();
41632 this.grid.getDataSource().on('remove', this.refreshValue, this);
41633 this.grid.getDataSource().on('update', this.refreshValue, this);
41634 this.grid.on('afteredit', this.refreshValue, this);
41640 * Sets the value of the item.
41641 * @param {String} either an object or a string..
41643 setValue : function(v){
41645 v = v || []; // empty set..
41646 // this does not seem smart - it really only affects memoryproxy grids..
41647 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
41648 var ds = this.grid.getDataSource();
41649 // assumes a json reader..
41651 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
41652 ds.loadData( data);
41654 Roo.form.GridField.superclass.setValue.call(this, v);
41655 this.refreshValue();
41656 // should load data in the grid really....
41660 refreshValue: function() {
41662 this.grid.getDataSource().each(function(r) {
41665 this.el.dom.value = Roo.encode(val);
41671 });//<script type="text/javasscript">
41675 * @class Roo.DDView
41676 * A DnD enabled version of Roo.View.
41677 * @param {Element/String} container The Element in which to create the View.
41678 * @param {String} tpl The template string used to create the markup for each element of the View
41679 * @param {Object} config The configuration properties. These include all the config options of
41680 * {@link Roo.View} plus some specific to this class.<br>
41682 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
41683 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
41685 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
41686 .x-view-drag-insert-above {
41687 border-top:1px dotted #3366cc;
41689 .x-view-drag-insert-below {
41690 border-bottom:1px dotted #3366cc;
41696 Roo.DDView = function(container, tpl, config) {
41697 Roo.DDView.superclass.constructor.apply(this, arguments);
41698 this.getEl().setStyle("outline", "0px none");
41699 this.getEl().unselectable();
41700 if (this.dragGroup) {
41701 this.setDraggable(this.dragGroup.split(","));
41703 if (this.dropGroup) {
41704 this.setDroppable(this.dropGroup.split(","));
41706 if (this.deletable) {
41707 this.setDeletable();
41709 this.isDirtyFlag = false;
41715 Roo.extend(Roo.DDView, Roo.View, {
41716 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
41717 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
41718 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
41719 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
41723 reset: Roo.emptyFn,
41725 clearInvalid: Roo.form.Field.prototype.clearInvalid,
41727 validate: function() {
41731 destroy: function() {
41732 this.purgeListeners();
41733 this.getEl.removeAllListeners();
41734 this.getEl().remove();
41735 if (this.dragZone) {
41736 if (this.dragZone.destroy) {
41737 this.dragZone.destroy();
41740 if (this.dropZone) {
41741 if (this.dropZone.destroy) {
41742 this.dropZone.destroy();
41747 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
41748 getName: function() {
41752 /** Loads the View from a JSON string representing the Records to put into the Store. */
41753 setValue: function(v) {
41755 throw "DDView.setValue(). DDView must be constructed with a valid Store";
41758 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
41759 this.store.proxy = new Roo.data.MemoryProxy(data);
41763 /** @return {String} a parenthesised list of the ids of the Records in the View. */
41764 getValue: function() {
41766 this.store.each(function(rec) {
41767 result += rec.id + ',';
41769 return result.substr(0, result.length - 1) + ')';
41772 getIds: function() {
41773 var i = 0, result = new Array(this.store.getCount());
41774 this.store.each(function(rec) {
41775 result[i++] = rec.id;
41780 isDirty: function() {
41781 return this.isDirtyFlag;
41785 * Part of the Roo.dd.DropZone interface. If no target node is found, the
41786 * whole Element becomes the target, and this causes the drop gesture to append.
41788 getTargetFromEvent : function(e) {
41789 var target = e.getTarget();
41790 while ((target !== null) && (target.parentNode != this.el.dom)) {
41791 target = target.parentNode;
41794 target = this.el.dom.lastChild || this.el.dom;
41800 * Create the drag data which consists of an object which has the property "ddel" as
41801 * the drag proxy element.
41803 getDragData : function(e) {
41804 var target = this.findItemFromChild(e.getTarget());
41806 this.handleSelection(e);
41807 var selNodes = this.getSelectedNodes();
41810 copy: this.copy || (this.allowCopy && e.ctrlKey),
41814 var selectedIndices = this.getSelectedIndexes();
41815 for (var i = 0; i < selectedIndices.length; i++) {
41816 dragData.records.push(this.store.getAt(selectedIndices[i]));
41818 if (selNodes.length == 1) {
41819 dragData.ddel = target.cloneNode(true); // the div element
41821 var div = document.createElement('div'); // create the multi element drag "ghost"
41822 div.className = 'multi-proxy';
41823 for (var i = 0, len = selNodes.length; i < len; i++) {
41824 div.appendChild(selNodes[i].cloneNode(true));
41826 dragData.ddel = div;
41828 //console.log(dragData)
41829 //console.log(dragData.ddel.innerHTML)
41832 //console.log('nodragData')
41836 /** Specify to which ddGroup items in this DDView may be dragged. */
41837 setDraggable: function(ddGroup) {
41838 if (ddGroup instanceof Array) {
41839 Roo.each(ddGroup, this.setDraggable, this);
41842 if (this.dragZone) {
41843 this.dragZone.addToGroup(ddGroup);
41845 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
41846 containerScroll: true,
41850 // Draggability implies selection. DragZone's mousedown selects the element.
41851 if (!this.multiSelect) { this.singleSelect = true; }
41853 // Wire the DragZone's handlers up to methods in *this*
41854 this.dragZone.getDragData = this.getDragData.createDelegate(this);
41858 /** Specify from which ddGroup this DDView accepts drops. */
41859 setDroppable: function(ddGroup) {
41860 if (ddGroup instanceof Array) {
41861 Roo.each(ddGroup, this.setDroppable, this);
41864 if (this.dropZone) {
41865 this.dropZone.addToGroup(ddGroup);
41867 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
41868 containerScroll: true,
41872 // Wire the DropZone's handlers up to methods in *this*
41873 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
41874 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
41875 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
41876 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
41877 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
41881 /** Decide whether to drop above or below a View node. */
41882 getDropPoint : function(e, n, dd){
41883 if (n == this.el.dom) { return "above"; }
41884 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
41885 var c = t + (b - t) / 2;
41886 var y = Roo.lib.Event.getPageY(e);
41894 onNodeEnter : function(n, dd, e, data){
41898 onNodeOver : function(n, dd, e, data){
41899 var pt = this.getDropPoint(e, n, dd);
41900 // set the insert point style on the target node
41901 var dragElClass = this.dropNotAllowed;
41904 if (pt == "above"){
41905 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
41906 targetElClass = "x-view-drag-insert-above";
41908 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
41909 targetElClass = "x-view-drag-insert-below";
41911 if (this.lastInsertClass != targetElClass){
41912 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
41913 this.lastInsertClass = targetElClass;
41916 return dragElClass;
41919 onNodeOut : function(n, dd, e, data){
41920 this.removeDropIndicators(n);
41923 onNodeDrop : function(n, dd, e, data){
41924 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
41927 var pt = this.getDropPoint(e, n, dd);
41928 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
41929 if (pt == "below") { insertAt++; }
41930 for (var i = 0; i < data.records.length; i++) {
41931 var r = data.records[i];
41932 var dup = this.store.getById(r.id);
41933 if (dup && (dd != this.dragZone)) {
41934 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
41937 this.store.insert(insertAt++, r.copy());
41939 data.source.isDirtyFlag = true;
41941 this.store.insert(insertAt++, r);
41943 this.isDirtyFlag = true;
41946 this.dragZone.cachedTarget = null;
41950 removeDropIndicators : function(n){
41952 Roo.fly(n).removeClass([
41953 "x-view-drag-insert-above",
41954 "x-view-drag-insert-below"]);
41955 this.lastInsertClass = "_noclass";
41960 * Utility method. Add a delete option to the DDView's context menu.
41961 * @param {String} imageUrl The URL of the "delete" icon image.
41963 setDeletable: function(imageUrl) {
41964 if (!this.singleSelect && !this.multiSelect) {
41965 this.singleSelect = true;
41967 var c = this.getContextMenu();
41968 this.contextMenu.on("itemclick", function(item) {
41971 this.remove(this.getSelectedIndexes());
41975 this.contextMenu.add({
41982 /** Return the context menu for this DDView. */
41983 getContextMenu: function() {
41984 if (!this.contextMenu) {
41985 // Create the View's context menu
41986 this.contextMenu = new Roo.menu.Menu({
41987 id: this.id + "-contextmenu"
41989 this.el.on("contextmenu", this.showContextMenu, this);
41991 return this.contextMenu;
41994 disableContextMenu: function() {
41995 if (this.contextMenu) {
41996 this.el.un("contextmenu", this.showContextMenu, this);
42000 showContextMenu: function(e, item) {
42001 item = this.findItemFromChild(e.getTarget());
42004 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
42005 this.contextMenu.showAt(e.getXY());
42010 * Remove {@link Roo.data.Record}s at the specified indices.
42011 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
42013 remove: function(selectedIndices) {
42014 selectedIndices = [].concat(selectedIndices);
42015 for (var i = 0; i < selectedIndices.length; i++) {
42016 var rec = this.store.getAt(selectedIndices[i]);
42017 this.store.remove(rec);
42022 * Double click fires the event, but also, if this is draggable, and there is only one other
42023 * related DropZone, it transfers the selected node.
42025 onDblClick : function(e){
42026 var item = this.findItemFromChild(e.getTarget());
42028 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
42031 if (this.dragGroup) {
42032 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
42033 while (targets.indexOf(this.dropZone) > -1) {
42034 targets.remove(this.dropZone);
42036 if (targets.length == 1) {
42037 this.dragZone.cachedTarget = null;
42038 var el = Roo.get(targets[0].getEl());
42039 var box = el.getBox(true);
42040 targets[0].onNodeDrop(el.dom, {
42042 xy: [box.x, box.y + box.height - 1]
42043 }, null, this.getDragData(e));
42049 handleSelection: function(e) {
42050 this.dragZone.cachedTarget = null;
42051 var item = this.findItemFromChild(e.getTarget());
42053 this.clearSelections(true);
42056 if (item && (this.multiSelect || this.singleSelect)){
42057 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
42058 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
42059 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
42060 this.unselect(item);
42062 this.select(item, this.multiSelect && e.ctrlKey);
42063 this.lastSelection = item;
42068 onItemClick : function(item, index, e){
42069 if(this.fireEvent("beforeclick", this, index, item, e) === false){
42075 unselect : function(nodeInfo, suppressEvent){
42076 var node = this.getNode(nodeInfo);
42077 if(node && this.isSelected(node)){
42078 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
42079 Roo.fly(node).removeClass(this.selectedClass);
42080 this.selections.remove(node);
42081 if(!suppressEvent){
42082 this.fireEvent("selectionchange", this, this.selections);
42090 * Ext JS Library 1.1.1
42091 * Copyright(c) 2006-2007, Ext JS, LLC.
42093 * Originally Released Under LGPL - original licence link has changed is not relivant.
42096 * <script type="text/javascript">
42100 * @class Roo.LayoutManager
42101 * @extends Roo.util.Observable
42102 * Base class for layout managers.
42104 Roo.LayoutManager = function(container, config){
42105 Roo.LayoutManager.superclass.constructor.call(this);
42106 this.el = Roo.get(container);
42107 // ie scrollbar fix
42108 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
42109 document.body.scroll = "no";
42110 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
42111 this.el.position('relative');
42113 this.id = this.el.id;
42114 this.el.addClass("x-layout-container");
42115 /** false to disable window resize monitoring @type Boolean */
42116 this.monitorWindowResize = true;
42121 * Fires when a layout is performed.
42122 * @param {Roo.LayoutManager} this
42126 * @event regionresized
42127 * Fires when the user resizes a region.
42128 * @param {Roo.LayoutRegion} region The resized region
42129 * @param {Number} newSize The new size (width for east/west, height for north/south)
42131 "regionresized" : true,
42133 * @event regioncollapsed
42134 * Fires when a region is collapsed.
42135 * @param {Roo.LayoutRegion} region The collapsed region
42137 "regioncollapsed" : true,
42139 * @event regionexpanded
42140 * Fires when a region is expanded.
42141 * @param {Roo.LayoutRegion} region The expanded region
42143 "regionexpanded" : true
42145 this.updating = false;
42146 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
42149 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
42151 * Returns true if this layout is currently being updated
42152 * @return {Boolean}
42154 isUpdating : function(){
42155 return this.updating;
42159 * Suspend the LayoutManager from doing auto-layouts while
42160 * making multiple add or remove calls
42162 beginUpdate : function(){
42163 this.updating = true;
42167 * Restore auto-layouts and optionally disable the manager from performing a layout
42168 * @param {Boolean} noLayout true to disable a layout update
42170 endUpdate : function(noLayout){
42171 this.updating = false;
42177 layout: function(){
42181 onRegionResized : function(region, newSize){
42182 this.fireEvent("regionresized", region, newSize);
42186 onRegionCollapsed : function(region){
42187 this.fireEvent("regioncollapsed", region);
42190 onRegionExpanded : function(region){
42191 this.fireEvent("regionexpanded", region);
42195 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
42196 * performs box-model adjustments.
42197 * @return {Object} The size as an object {width: (the width), height: (the height)}
42199 getViewSize : function(){
42201 if(this.el.dom != document.body){
42202 size = this.el.getSize();
42204 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
42206 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
42207 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
42212 * Returns the Element this layout is bound to.
42213 * @return {Roo.Element}
42215 getEl : function(){
42220 * Returns the specified region.
42221 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
42222 * @return {Roo.LayoutRegion}
42224 getRegion : function(target){
42225 return this.regions[target.toLowerCase()];
42228 onWindowResize : function(){
42229 if(this.monitorWindowResize){
42235 * Ext JS Library 1.1.1
42236 * Copyright(c) 2006-2007, Ext JS, LLC.
42238 * Originally Released Under LGPL - original licence link has changed is not relivant.
42241 * <script type="text/javascript">
42244 * @class Roo.BorderLayout
42245 * @extends Roo.LayoutManager
42246 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
42247 * please see: <br><br>
42248 * <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>
42249 * <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>
42252 var layout = new Roo.BorderLayout(document.body, {
42286 preferredTabWidth: 150
42291 var CP = Roo.ContentPanel;
42293 layout.beginUpdate();
42294 layout.add("north", new CP("north", "North"));
42295 layout.add("south", new CP("south", {title: "South", closable: true}));
42296 layout.add("west", new CP("west", {title: "West"}));
42297 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
42298 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
42299 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
42300 layout.getRegion("center").showPanel("center1");
42301 layout.endUpdate();
42304 <b>The container the layout is rendered into can be either the body element or any other element.
42305 If it is not the body element, the container needs to either be an absolute positioned element,
42306 or you will need to add "position:relative" to the css of the container. You will also need to specify
42307 the container size if it is not the body element.</b>
42310 * Create a new BorderLayout
42311 * @param {String/HTMLElement/Element} container The container this layout is bound to
42312 * @param {Object} config Configuration options
42314 Roo.BorderLayout = function(container, config){
42315 config = config || {};
42316 Roo.BorderLayout.superclass.constructor.call(this, container, config);
42317 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
42318 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
42319 var target = this.factory.validRegions[i];
42320 if(config[target]){
42321 this.addRegion(target, config[target]);
42326 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
42328 * Creates and adds a new region if it doesn't already exist.
42329 * @param {String} target The target region key (north, south, east, west or center).
42330 * @param {Object} config The regions config object
42331 * @return {BorderLayoutRegion} The new region
42333 addRegion : function(target, config){
42334 if(!this.regions[target]){
42335 var r = this.factory.create(target, this, config);
42336 this.bindRegion(target, r);
42338 return this.regions[target];
42342 bindRegion : function(name, r){
42343 this.regions[name] = r;
42344 r.on("visibilitychange", this.layout, this);
42345 r.on("paneladded", this.layout, this);
42346 r.on("panelremoved", this.layout, this);
42347 r.on("invalidated", this.layout, this);
42348 r.on("resized", this.onRegionResized, this);
42349 r.on("collapsed", this.onRegionCollapsed, this);
42350 r.on("expanded", this.onRegionExpanded, this);
42354 * Performs a layout update.
42356 layout : function(){
42357 if(this.updating) return;
42358 var size = this.getViewSize();
42359 var w = size.width;
42360 var h = size.height;
42365 //var x = 0, y = 0;
42367 var rs = this.regions;
42368 var north = rs["north"];
42369 var south = rs["south"];
42370 var west = rs["west"];
42371 var east = rs["east"];
42372 var center = rs["center"];
42373 //if(this.hideOnLayout){ // not supported anymore
42374 //c.el.setStyle("display", "none");
42376 if(north && north.isVisible()){
42377 var b = north.getBox();
42378 var m = north.getMargins();
42379 b.width = w - (m.left+m.right);
42382 centerY = b.height + b.y + m.bottom;
42383 centerH -= centerY;
42384 north.updateBox(this.safeBox(b));
42386 if(south && south.isVisible()){
42387 var b = south.getBox();
42388 var m = south.getMargins();
42389 b.width = w - (m.left+m.right);
42391 var totalHeight = (b.height + m.top + m.bottom);
42392 b.y = h - totalHeight + m.top;
42393 centerH -= totalHeight;
42394 south.updateBox(this.safeBox(b));
42396 if(west && west.isVisible()){
42397 var b = west.getBox();
42398 var m = west.getMargins();
42399 b.height = centerH - (m.top+m.bottom);
42401 b.y = centerY + m.top;
42402 var totalWidth = (b.width + m.left + m.right);
42403 centerX += totalWidth;
42404 centerW -= totalWidth;
42405 west.updateBox(this.safeBox(b));
42407 if(east && east.isVisible()){
42408 var b = east.getBox();
42409 var m = east.getMargins();
42410 b.height = centerH - (m.top+m.bottom);
42411 var totalWidth = (b.width + m.left + m.right);
42412 b.x = w - totalWidth + m.left;
42413 b.y = centerY + m.top;
42414 centerW -= totalWidth;
42415 east.updateBox(this.safeBox(b));
42418 var m = center.getMargins();
42420 x: centerX + m.left,
42421 y: centerY + m.top,
42422 width: centerW - (m.left+m.right),
42423 height: centerH - (m.top+m.bottom)
42425 //if(this.hideOnLayout){
42426 //center.el.setStyle("display", "block");
42428 center.updateBox(this.safeBox(centerBox));
42431 this.fireEvent("layout", this);
42435 safeBox : function(box){
42436 box.width = Math.max(0, box.width);
42437 box.height = Math.max(0, box.height);
42442 * Adds a ContentPanel (or subclass) to this layout.
42443 * @param {String} target The target region key (north, south, east, west or center).
42444 * @param {Roo.ContentPanel} panel The panel to add
42445 * @return {Roo.ContentPanel} The added panel
42447 add : function(target, panel){
42449 target = target.toLowerCase();
42450 return this.regions[target].add(panel);
42454 * Remove a ContentPanel (or subclass) to this layout.
42455 * @param {String} target The target region key (north, south, east, west or center).
42456 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
42457 * @return {Roo.ContentPanel} The removed panel
42459 remove : function(target, panel){
42460 target = target.toLowerCase();
42461 return this.regions[target].remove(panel);
42465 * Searches all regions for a panel with the specified id
42466 * @param {String} panelId
42467 * @return {Roo.ContentPanel} The panel or null if it wasn't found
42469 findPanel : function(panelId){
42470 var rs = this.regions;
42471 for(var target in rs){
42472 if(typeof rs[target] != "function"){
42473 var p = rs[target].getPanel(panelId);
42483 * Searches all regions for a panel with the specified id and activates (shows) it.
42484 * @param {String/ContentPanel} panelId The panels id or the panel itself
42485 * @return {Roo.ContentPanel} The shown panel or null
42487 showPanel : function(panelId) {
42488 var rs = this.regions;
42489 for(var target in rs){
42490 var r = rs[target];
42491 if(typeof r != "function"){
42492 if(r.hasPanel(panelId)){
42493 return r.showPanel(panelId);
42501 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
42502 * @param {Roo.state.Provider} provider (optional) An alternate state provider
42504 restoreState : function(provider){
42506 provider = Roo.state.Manager;
42508 var sm = new Roo.LayoutStateManager();
42509 sm.init(this, provider);
42513 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
42514 * object should contain properties for each region to add ContentPanels to, and each property's value should be
42515 * a valid ContentPanel config object. Example:
42517 // Create the main layout
42518 var layout = new Roo.BorderLayout('main-ct', {
42529 // Create and add multiple ContentPanels at once via configs
42532 id: 'source-files',
42534 title:'Ext Source Files',
42547 * @param {Object} regions An object containing ContentPanel configs by region name
42549 batchAdd : function(regions){
42550 this.beginUpdate();
42551 for(var rname in regions){
42552 var lr = this.regions[rname];
42554 this.addTypedPanels(lr, regions[rname]);
42561 addTypedPanels : function(lr, ps){
42562 if(typeof ps == 'string'){
42563 lr.add(new Roo.ContentPanel(ps));
42565 else if(ps instanceof Array){
42566 for(var i =0, len = ps.length; i < len; i++){
42567 this.addTypedPanels(lr, ps[i]);
42570 else if(!ps.events){ // raw config?
42572 delete ps.el; // prevent conflict
42573 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
42575 else { // panel object assumed!
42580 * Adds a xtype elements to the layout.
42584 xtype : 'ContentPanel',
42591 xtype : 'NestedLayoutPanel',
42597 items : [ ... list of content panels or nested layout panels.. ]
42601 * @param {Object} cfg Xtype definition of item to add.
42603 addxtype : function(cfg)
42605 // basically accepts a pannel...
42606 // can accept a layout region..!?!?
42607 // console.log('BorderLayout add ' + cfg.xtype)
42609 if (!cfg.xtype.match(/Panel$/)) {
42613 var region = cfg.region;
42619 xitems = cfg.items;
42626 case 'ContentPanel': // ContentPanel (el, cfg)
42627 if(cfg.autoCreate) {
42628 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42630 var el = this.el.createChild();
42631 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
42634 this.add(region, ret);
42638 case 'TreePanel': // our new panel!
42639 cfg.el = this.el.createChild();
42640 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42641 this.add(region, ret);
42644 case 'NestedLayoutPanel':
42645 // create a new Layout (which is a Border Layout...
42646 var el = this.el.createChild();
42647 var clayout = cfg.layout;
42649 clayout.items = clayout.items || [];
42650 // replace this exitems with the clayout ones..
42651 xitems = clayout.items;
42654 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
42655 cfg.background = false;
42657 var layout = new Roo.BorderLayout(el, clayout);
42659 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
42660 //console.log('adding nested layout panel ' + cfg.toSource());
42661 this.add(region, ret);
42667 // needs grid and region
42669 //var el = this.getRegion(region).el.createChild();
42670 var el = this.el.createChild();
42671 // create the grid first...
42673 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
42675 if (region == 'center' && this.active ) {
42676 cfg.background = false;
42678 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
42680 this.add(region, ret);
42681 if (cfg.background) {
42682 ret.on('activate', function(gp) {
42683 if (!gp.grid.rendered) {
42696 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
42698 // GridPanel (grid, cfg)
42701 this.beginUpdate();
42703 Roo.each(xitems, function(i) {
42713 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
42714 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
42715 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
42716 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
42719 var CP = Roo.ContentPanel;
42721 var layout = Roo.BorderLayout.create({
42725 panels: [new CP("north", "North")]
42734 panels: [new CP("west", {title: "West"})]
42743 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
42752 panels: [new CP("south", {title: "South", closable: true})]
42759 preferredTabWidth: 150,
42761 new CP("center1", {title: "Close Me", closable: true}),
42762 new CP("center2", {title: "Center Panel", closable: false})
42767 layout.getRegion("center").showPanel("center1");
42772 Roo.BorderLayout.create = function(config, targetEl){
42773 var layout = new Roo.BorderLayout(targetEl || document.body, config);
42774 layout.beginUpdate();
42775 var regions = Roo.BorderLayout.RegionFactory.validRegions;
42776 for(var j = 0, jlen = regions.length; j < jlen; j++){
42777 var lr = regions[j];
42778 if(layout.regions[lr] && config[lr].panels){
42779 var r = layout.regions[lr];
42780 var ps = config[lr].panels;
42781 layout.addTypedPanels(r, ps);
42784 layout.endUpdate();
42789 Roo.BorderLayout.RegionFactory = {
42791 validRegions : ["north","south","east","west","center"],
42794 create : function(target, mgr, config){
42795 target = target.toLowerCase();
42796 if(config.lightweight || config.basic){
42797 return new Roo.BasicLayoutRegion(mgr, config, target);
42801 return new Roo.NorthLayoutRegion(mgr, config);
42803 return new Roo.SouthLayoutRegion(mgr, config);
42805 return new Roo.EastLayoutRegion(mgr, config);
42807 return new Roo.WestLayoutRegion(mgr, config);
42809 return new Roo.CenterLayoutRegion(mgr, config);
42811 throw 'Layout region "'+target+'" not supported.';
42815 * Ext JS Library 1.1.1
42816 * Copyright(c) 2006-2007, Ext JS, LLC.
42818 * Originally Released Under LGPL - original licence link has changed is not relivant.
42821 * <script type="text/javascript">
42825 * @class Roo.BasicLayoutRegion
42826 * @extends Roo.util.Observable
42827 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
42828 * and does not have a titlebar, tabs or any other features. All it does is size and position
42829 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
42831 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
42833 this.position = pos;
42836 * @scope Roo.BasicLayoutRegion
42840 * @event beforeremove
42841 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
42842 * @param {Roo.LayoutRegion} this
42843 * @param {Roo.ContentPanel} panel The panel
42844 * @param {Object} e The cancel event object
42846 "beforeremove" : true,
42848 * @event invalidated
42849 * Fires when the layout for this region is changed.
42850 * @param {Roo.LayoutRegion} this
42852 "invalidated" : true,
42854 * @event visibilitychange
42855 * Fires when this region is shown or hidden
42856 * @param {Roo.LayoutRegion} this
42857 * @param {Boolean} visibility true or false
42859 "visibilitychange" : true,
42861 * @event paneladded
42862 * Fires when a panel is added.
42863 * @param {Roo.LayoutRegion} this
42864 * @param {Roo.ContentPanel} panel The panel
42866 "paneladded" : true,
42868 * @event panelremoved
42869 * Fires when a panel is removed.
42870 * @param {Roo.LayoutRegion} this
42871 * @param {Roo.ContentPanel} panel The panel
42873 "panelremoved" : true,
42876 * Fires when this region is collapsed.
42877 * @param {Roo.LayoutRegion} this
42879 "collapsed" : true,
42882 * Fires when this region is expanded.
42883 * @param {Roo.LayoutRegion} this
42888 * Fires when this region is slid into view.
42889 * @param {Roo.LayoutRegion} this
42891 "slideshow" : true,
42894 * Fires when this region slides out of view.
42895 * @param {Roo.LayoutRegion} this
42897 "slidehide" : true,
42899 * @event panelactivated
42900 * Fires when a panel is activated.
42901 * @param {Roo.LayoutRegion} this
42902 * @param {Roo.ContentPanel} panel The activated panel
42904 "panelactivated" : true,
42907 * Fires when the user resizes this region.
42908 * @param {Roo.LayoutRegion} this
42909 * @param {Number} newSize The new size (width for east/west, height for north/south)
42913 /** A collection of panels in this region. @type Roo.util.MixedCollection */
42914 this.panels = new Roo.util.MixedCollection();
42915 this.panels.getKey = this.getPanelId.createDelegate(this);
42917 this.activePanel = null;
42918 // ensure listeners are added...
42920 if (config.listeners || config.events) {
42921 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
42922 listeners : config.listeners || {},
42923 events : config.events || {}
42927 if(skipConfig !== true){
42928 this.applyConfig(config);
42932 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
42933 getPanelId : function(p){
42937 applyConfig : function(config){
42938 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
42939 this.config = config;
42944 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
42945 * the width, for horizontal (north, south) the height.
42946 * @param {Number} newSize The new width or height
42948 resizeTo : function(newSize){
42949 var el = this.el ? this.el :
42950 (this.activePanel ? this.activePanel.getEl() : null);
42952 switch(this.position){
42955 el.setWidth(newSize);
42956 this.fireEvent("resized", this, newSize);
42960 el.setHeight(newSize);
42961 this.fireEvent("resized", this, newSize);
42967 getBox : function(){
42968 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
42971 getMargins : function(){
42972 return this.margins;
42975 updateBox : function(box){
42977 var el = this.activePanel.getEl();
42978 el.dom.style.left = box.x + "px";
42979 el.dom.style.top = box.y + "px";
42980 this.activePanel.setSize(box.width, box.height);
42984 * Returns the container element for this region.
42985 * @return {Roo.Element}
42987 getEl : function(){
42988 return this.activePanel;
42992 * Returns true if this region is currently visible.
42993 * @return {Boolean}
42995 isVisible : function(){
42996 return this.activePanel ? true : false;
42999 setActivePanel : function(panel){
43000 panel = this.getPanel(panel);
43001 if(this.activePanel && this.activePanel != panel){
43002 this.activePanel.setActiveState(false);
43003 this.activePanel.getEl().setLeftTop(-10000,-10000);
43005 this.activePanel = panel;
43006 panel.setActiveState(true);
43008 panel.setSize(this.box.width, this.box.height);
43010 this.fireEvent("panelactivated", this, panel);
43011 this.fireEvent("invalidated");
43015 * Show the specified panel.
43016 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
43017 * @return {Roo.ContentPanel} The shown panel or null
43019 showPanel : function(panel){
43020 if(panel = this.getPanel(panel)){
43021 this.setActivePanel(panel);
43027 * Get the active panel for this region.
43028 * @return {Roo.ContentPanel} The active panel or null
43030 getActivePanel : function(){
43031 return this.activePanel;
43035 * Add the passed ContentPanel(s)
43036 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43037 * @return {Roo.ContentPanel} The panel added (if only one was added)
43039 add : function(panel){
43040 if(arguments.length > 1){
43041 for(var i = 0, len = arguments.length; i < len; i++) {
43042 this.add(arguments[i]);
43046 if(this.hasPanel(panel)){
43047 this.showPanel(panel);
43050 var el = panel.getEl();
43051 if(el.dom.parentNode != this.mgr.el.dom){
43052 this.mgr.el.dom.appendChild(el.dom);
43054 if(panel.setRegion){
43055 panel.setRegion(this);
43057 this.panels.add(panel);
43058 el.setStyle("position", "absolute");
43059 if(!panel.background){
43060 this.setActivePanel(panel);
43061 if(this.config.initialSize && this.panels.getCount()==1){
43062 this.resizeTo(this.config.initialSize);
43065 this.fireEvent("paneladded", this, panel);
43070 * Returns true if the panel is in this region.
43071 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43072 * @return {Boolean}
43074 hasPanel : function(panel){
43075 if(typeof panel == "object"){ // must be panel obj
43076 panel = panel.getId();
43078 return this.getPanel(panel) ? true : false;
43082 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
43083 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43084 * @param {Boolean} preservePanel Overrides the config preservePanel option
43085 * @return {Roo.ContentPanel} The panel that was removed
43087 remove : function(panel, preservePanel){
43088 panel = this.getPanel(panel);
43093 this.fireEvent("beforeremove", this, panel, e);
43094 if(e.cancel === true){
43097 var panelId = panel.getId();
43098 this.panels.removeKey(panelId);
43103 * Returns the panel specified or null if it's not in this region.
43104 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43105 * @return {Roo.ContentPanel}
43107 getPanel : function(id){
43108 if(typeof id == "object"){ // must be panel obj
43111 return this.panels.get(id);
43115 * Returns this regions position (north/south/east/west/center).
43118 getPosition: function(){
43119 return this.position;
43123 * Ext JS Library 1.1.1
43124 * Copyright(c) 2006-2007, Ext JS, LLC.
43126 * Originally Released Under LGPL - original licence link has changed is not relivant.
43129 * <script type="text/javascript">
43133 * @class Roo.LayoutRegion
43134 * @extends Roo.BasicLayoutRegion
43135 * This class represents a region in a layout manager.
43136 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
43137 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
43138 * @cfg {Boolean} floatable False to disable floating (defaults to true)
43139 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
43140 * @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})
43141 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
43142 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
43143 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
43144 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
43145 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
43146 * @cfg {String} title The title for the region (overrides panel titles)
43147 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
43148 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
43149 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
43150 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
43151 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
43152 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
43153 * the space available, similar to FireFox 1.5 tabs (defaults to false)
43154 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
43155 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
43156 * @cfg {Boolean} showPin True to show a pin button
43157 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
43158 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
43159 * @cfg {Boolean} disableTabTips True to disable tab tooltips
43160 * @cfg {Number} width For East/West panels
43161 * @cfg {Number} height For North/South panels
43162 * @cfg {Boolean} split To show the splitter
43164 Roo.LayoutRegion = function(mgr, config, pos){
43165 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
43166 var dh = Roo.DomHelper;
43167 /** This region's container element
43168 * @type Roo.Element */
43169 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
43170 /** This region's title element
43171 * @type Roo.Element */
43173 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
43174 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
43175 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
43177 this.titleEl.enableDisplayMode();
43178 /** This region's title text element
43179 * @type HTMLElement */
43180 this.titleTextEl = this.titleEl.dom.firstChild;
43181 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
43182 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
43183 this.closeBtn.enableDisplayMode();
43184 this.closeBtn.on("click", this.closeClicked, this);
43185 this.closeBtn.hide();
43187 this.createBody(config);
43188 this.visible = true;
43189 this.collapsed = false;
43191 if(config.hideWhenEmpty){
43193 this.on("paneladded", this.validateVisibility, this);
43194 this.on("panelremoved", this.validateVisibility, this);
43196 this.applyConfig(config);
43199 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
43201 createBody : function(){
43202 /** This region's body element
43203 * @type Roo.Element */
43204 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
43207 applyConfig : function(c){
43208 if(c.collapsible && this.position != "center" && !this.collapsedEl){
43209 var dh = Roo.DomHelper;
43210 if(c.titlebar !== false){
43211 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
43212 this.collapseBtn.on("click", this.collapse, this);
43213 this.collapseBtn.enableDisplayMode();
43215 if(c.showPin === true || this.showPin){
43216 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
43217 this.stickBtn.enableDisplayMode();
43218 this.stickBtn.on("click", this.expand, this);
43219 this.stickBtn.hide();
43222 /** This region's collapsed element
43223 * @type Roo.Element */
43224 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
43225 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
43227 if(c.floatable !== false){
43228 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
43229 this.collapsedEl.on("click", this.collapseClick, this);
43232 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
43233 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
43234 id: "message", unselectable: "on", style:{"float":"left"}});
43235 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
43237 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
43238 this.expandBtn.on("click", this.expand, this);
43240 if(this.collapseBtn){
43241 this.collapseBtn.setVisible(c.collapsible == true);
43243 this.cmargins = c.cmargins || this.cmargins ||
43244 (this.position == "west" || this.position == "east" ?
43245 {top: 0, left: 2, right:2, bottom: 0} :
43246 {top: 2, left: 0, right:0, bottom: 2});
43247 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43248 this.bottomTabs = c.tabPosition != "top";
43249 this.autoScroll = c.autoScroll || false;
43250 if(this.autoScroll){
43251 this.bodyEl.setStyle("overflow", "auto");
43253 this.bodyEl.setStyle("overflow", "hidden");
43255 //if(c.titlebar !== false){
43256 if((!c.titlebar && !c.title) || c.titlebar === false){
43257 this.titleEl.hide();
43259 this.titleEl.show();
43261 this.titleTextEl.innerHTML = c.title;
43265 this.duration = c.duration || .30;
43266 this.slideDuration = c.slideDuration || .45;
43269 this.collapse(true);
43276 * Returns true if this region is currently visible.
43277 * @return {Boolean}
43279 isVisible : function(){
43280 return this.visible;
43284 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
43285 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
43287 setCollapsedTitle : function(title){
43288 title = title || " ";
43289 if(this.collapsedTitleTextEl){
43290 this.collapsedTitleTextEl.innerHTML = title;
43294 getBox : function(){
43296 if(!this.collapsed){
43297 b = this.el.getBox(false, true);
43299 b = this.collapsedEl.getBox(false, true);
43304 getMargins : function(){
43305 return this.collapsed ? this.cmargins : this.margins;
43308 highlight : function(){
43309 this.el.addClass("x-layout-panel-dragover");
43312 unhighlight : function(){
43313 this.el.removeClass("x-layout-panel-dragover");
43316 updateBox : function(box){
43318 if(!this.collapsed){
43319 this.el.dom.style.left = box.x + "px";
43320 this.el.dom.style.top = box.y + "px";
43321 this.updateBody(box.width, box.height);
43323 this.collapsedEl.dom.style.left = box.x + "px";
43324 this.collapsedEl.dom.style.top = box.y + "px";
43325 this.collapsedEl.setSize(box.width, box.height);
43328 this.tabs.autoSizeTabs();
43332 updateBody : function(w, h){
43334 this.el.setWidth(w);
43335 w -= this.el.getBorderWidth("rl");
43336 if(this.config.adjustments){
43337 w += this.config.adjustments[0];
43341 this.el.setHeight(h);
43342 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
43343 h -= this.el.getBorderWidth("tb");
43344 if(this.config.adjustments){
43345 h += this.config.adjustments[1];
43347 this.bodyEl.setHeight(h);
43349 h = this.tabs.syncHeight(h);
43352 if(this.panelSize){
43353 w = w !== null ? w : this.panelSize.width;
43354 h = h !== null ? h : this.panelSize.height;
43356 if(this.activePanel){
43357 var el = this.activePanel.getEl();
43358 w = w !== null ? w : el.getWidth();
43359 h = h !== null ? h : el.getHeight();
43360 this.panelSize = {width: w, height: h};
43361 this.activePanel.setSize(w, h);
43363 if(Roo.isIE && this.tabs){
43364 this.tabs.el.repaint();
43369 * Returns the container element for this region.
43370 * @return {Roo.Element}
43372 getEl : function(){
43377 * Hides this region.
43380 if(!this.collapsed){
43381 this.el.dom.style.left = "-2000px";
43384 this.collapsedEl.dom.style.left = "-2000px";
43385 this.collapsedEl.hide();
43387 this.visible = false;
43388 this.fireEvent("visibilitychange", this, false);
43392 * Shows this region if it was previously hidden.
43395 if(!this.collapsed){
43398 this.collapsedEl.show();
43400 this.visible = true;
43401 this.fireEvent("visibilitychange", this, true);
43404 closeClicked : function(){
43405 if(this.activePanel){
43406 this.remove(this.activePanel);
43410 collapseClick : function(e){
43412 e.stopPropagation();
43415 e.stopPropagation();
43421 * Collapses this region.
43422 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
43424 collapse : function(skipAnim){
43425 if(this.collapsed) return;
43426 this.collapsed = true;
43428 this.split.el.hide();
43430 if(this.config.animate && skipAnim !== true){
43431 this.fireEvent("invalidated", this);
43432 this.animateCollapse();
43434 this.el.setLocation(-20000,-20000);
43436 this.collapsedEl.show();
43437 this.fireEvent("collapsed", this);
43438 this.fireEvent("invalidated", this);
43442 animateCollapse : function(){
43447 * Expands this region if it was previously collapsed.
43448 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
43449 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
43451 expand : function(e, skipAnim){
43452 if(e) e.stopPropagation();
43453 if(!this.collapsed || this.el.hasActiveFx()) return;
43455 this.afterSlideIn();
43458 this.collapsed = false;
43459 if(this.config.animate && skipAnim !== true){
43460 this.animateExpand();
43464 this.split.el.show();
43466 this.collapsedEl.setLocation(-2000,-2000);
43467 this.collapsedEl.hide();
43468 this.fireEvent("invalidated", this);
43469 this.fireEvent("expanded", this);
43473 animateExpand : function(){
43477 initTabs : function(){
43478 this.bodyEl.setStyle("overflow", "hidden");
43479 var ts = new Roo.TabPanel(this.bodyEl.dom, {
43480 tabPosition: this.bottomTabs ? 'bottom' : 'top',
43481 disableTooltips: this.config.disableTabTips
43483 if(this.config.hideTabs){
43484 ts.stripWrap.setDisplayed(false);
43487 ts.resizeTabs = this.config.resizeTabs === true;
43488 ts.minTabWidth = this.config.minTabWidth || 40;
43489 ts.maxTabWidth = this.config.maxTabWidth || 250;
43490 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
43491 ts.monitorResize = false;
43492 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43493 ts.bodyEl.addClass('x-layout-tabs-body');
43494 this.panels.each(this.initPanelAsTab, this);
43497 initPanelAsTab : function(panel){
43498 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
43499 this.config.closeOnTab && panel.isClosable());
43500 if(panel.tabTip !== undefined){
43501 ti.setTooltip(panel.tabTip);
43503 ti.on("activate", function(){
43504 this.setActivePanel(panel);
43506 if(this.config.closeOnTab){
43507 ti.on("beforeclose", function(t, e){
43509 this.remove(panel);
43515 updatePanelTitle : function(panel, title){
43516 if(this.activePanel == panel){
43517 this.updateTitle(title);
43520 var ti = this.tabs.getTab(panel.getEl().id);
43522 if(panel.tabTip !== undefined){
43523 ti.setTooltip(panel.tabTip);
43528 updateTitle : function(title){
43529 if(this.titleTextEl && !this.config.title){
43530 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
43534 setActivePanel : function(panel){
43535 panel = this.getPanel(panel);
43536 if(this.activePanel && this.activePanel != panel){
43537 this.activePanel.setActiveState(false);
43539 this.activePanel = panel;
43540 panel.setActiveState(true);
43541 if(this.panelSize){
43542 panel.setSize(this.panelSize.width, this.panelSize.height);
43545 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
43547 this.updateTitle(panel.getTitle());
43549 this.fireEvent("invalidated", this);
43551 this.fireEvent("panelactivated", this, panel);
43555 * Shows the specified panel.
43556 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
43557 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
43559 showPanel : function(panel){
43560 if(panel = this.getPanel(panel)){
43562 var tab = this.tabs.getTab(panel.getEl().id);
43563 if(tab.isHidden()){
43564 this.tabs.unhideTab(tab.id);
43568 this.setActivePanel(panel);
43575 * Get the active panel for this region.
43576 * @return {Roo.ContentPanel} The active panel or null
43578 getActivePanel : function(){
43579 return this.activePanel;
43582 validateVisibility : function(){
43583 if(this.panels.getCount() < 1){
43584 this.updateTitle(" ");
43585 this.closeBtn.hide();
43588 if(!this.isVisible()){
43595 * Adds the passed ContentPanel(s) to this region.
43596 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43597 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
43599 add : function(panel){
43600 if(arguments.length > 1){
43601 for(var i = 0, len = arguments.length; i < len; i++) {
43602 this.add(arguments[i]);
43606 if(this.hasPanel(panel)){
43607 this.showPanel(panel);
43610 panel.setRegion(this);
43611 this.panels.add(panel);
43612 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
43613 this.bodyEl.dom.appendChild(panel.getEl().dom);
43614 if(panel.background !== true){
43615 this.setActivePanel(panel);
43617 this.fireEvent("paneladded", this, panel);
43623 this.initPanelAsTab(panel);
43625 if(panel.background !== true){
43626 this.tabs.activate(panel.getEl().id);
43628 this.fireEvent("paneladded", this, panel);
43633 * Hides the tab for the specified panel.
43634 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43636 hidePanel : function(panel){
43637 if(this.tabs && (panel = this.getPanel(panel))){
43638 this.tabs.hideTab(panel.getEl().id);
43643 * Unhides the tab for a previously hidden panel.
43644 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43646 unhidePanel : function(panel){
43647 if(this.tabs && (panel = this.getPanel(panel))){
43648 this.tabs.unhideTab(panel.getEl().id);
43652 clearPanels : function(){
43653 while(this.panels.getCount() > 0){
43654 this.remove(this.panels.first());
43659 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
43660 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43661 * @param {Boolean} preservePanel Overrides the config preservePanel option
43662 * @return {Roo.ContentPanel} The panel that was removed
43664 remove : function(panel, preservePanel){
43665 panel = this.getPanel(panel);
43670 this.fireEvent("beforeremove", this, panel, e);
43671 if(e.cancel === true){
43674 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
43675 var panelId = panel.getId();
43676 this.panels.removeKey(panelId);
43678 document.body.appendChild(panel.getEl().dom);
43681 this.tabs.removeTab(panel.getEl().id);
43682 }else if (!preservePanel){
43683 this.bodyEl.dom.removeChild(panel.getEl().dom);
43685 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
43686 var p = this.panels.first();
43687 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
43688 tempEl.appendChild(p.getEl().dom);
43689 this.bodyEl.update("");
43690 this.bodyEl.dom.appendChild(p.getEl().dom);
43692 this.updateTitle(p.getTitle());
43694 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43695 this.setActivePanel(p);
43697 panel.setRegion(null);
43698 if(this.activePanel == panel){
43699 this.activePanel = null;
43701 if(this.config.autoDestroy !== false && preservePanel !== true){
43702 try{panel.destroy();}catch(e){}
43704 this.fireEvent("panelremoved", this, panel);
43709 * Returns the TabPanel component used by this region
43710 * @return {Roo.TabPanel}
43712 getTabs : function(){
43716 createTool : function(parentEl, className){
43717 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
43718 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
43719 btn.addClassOnOver("x-layout-tools-button-over");
43724 * Ext JS Library 1.1.1
43725 * Copyright(c) 2006-2007, Ext JS, LLC.
43727 * Originally Released Under LGPL - original licence link has changed is not relivant.
43730 * <script type="text/javascript">
43736 * @class Roo.SplitLayoutRegion
43737 * @extends Roo.LayoutRegion
43738 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
43740 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
43741 this.cursor = cursor;
43742 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
43745 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
43746 splitTip : "Drag to resize.",
43747 collapsibleSplitTip : "Drag to resize. Double click to hide.",
43748 useSplitTips : false,
43750 applyConfig : function(config){
43751 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
43754 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
43755 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
43756 /** The SplitBar for this region
43757 * @type Roo.SplitBar */
43758 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
43759 this.split.on("moved", this.onSplitMove, this);
43760 this.split.useShim = config.useShim === true;
43761 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
43762 if(this.useSplitTips){
43763 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
43765 if(config.collapsible){
43766 this.split.el.on("dblclick", this.collapse, this);
43769 if(typeof config.minSize != "undefined"){
43770 this.split.minSize = config.minSize;
43772 if(typeof config.maxSize != "undefined"){
43773 this.split.maxSize = config.maxSize;
43775 if(config.hideWhenEmpty || config.hidden || config.collapsed){
43776 this.hideSplitter();
43781 getHMaxSize : function(){
43782 var cmax = this.config.maxSize || 10000;
43783 var center = this.mgr.getRegion("center");
43784 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
43787 getVMaxSize : function(){
43788 var cmax = this.config.maxSize || 10000;
43789 var center = this.mgr.getRegion("center");
43790 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
43793 onSplitMove : function(split, newSize){
43794 this.fireEvent("resized", this, newSize);
43798 * Returns the {@link Roo.SplitBar} for this region.
43799 * @return {Roo.SplitBar}
43801 getSplitBar : function(){
43806 this.hideSplitter();
43807 Roo.SplitLayoutRegion.superclass.hide.call(this);
43810 hideSplitter : function(){
43812 this.split.el.setLocation(-2000,-2000);
43813 this.split.el.hide();
43819 this.split.el.show();
43821 Roo.SplitLayoutRegion.superclass.show.call(this);
43824 beforeSlide: function(){
43825 if(Roo.isGecko){// firefox overflow auto bug workaround
43826 this.bodyEl.clip();
43827 if(this.tabs) this.tabs.bodyEl.clip();
43828 if(this.activePanel){
43829 this.activePanel.getEl().clip();
43831 if(this.activePanel.beforeSlide){
43832 this.activePanel.beforeSlide();
43838 afterSlide : function(){
43839 if(Roo.isGecko){// firefox overflow auto bug workaround
43840 this.bodyEl.unclip();
43841 if(this.tabs) this.tabs.bodyEl.unclip();
43842 if(this.activePanel){
43843 this.activePanel.getEl().unclip();
43844 if(this.activePanel.afterSlide){
43845 this.activePanel.afterSlide();
43851 initAutoHide : function(){
43852 if(this.autoHide !== false){
43853 if(!this.autoHideHd){
43854 var st = new Roo.util.DelayedTask(this.slideIn, this);
43855 this.autoHideHd = {
43856 "mouseout": function(e){
43857 if(!e.within(this.el, true)){
43861 "mouseover" : function(e){
43867 this.el.on(this.autoHideHd);
43871 clearAutoHide : function(){
43872 if(this.autoHide !== false){
43873 this.el.un("mouseout", this.autoHideHd.mouseout);
43874 this.el.un("mouseover", this.autoHideHd.mouseover);
43878 clearMonitor : function(){
43879 Roo.get(document).un("click", this.slideInIf, this);
43882 // these names are backwards but not changed for compat
43883 slideOut : function(){
43884 if(this.isSlid || this.el.hasActiveFx()){
43887 this.isSlid = true;
43888 if(this.collapseBtn){
43889 this.collapseBtn.hide();
43891 this.closeBtnState = this.closeBtn.getStyle('display');
43892 this.closeBtn.hide();
43894 this.stickBtn.show();
43897 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
43898 this.beforeSlide();
43899 this.el.setStyle("z-index", 10001);
43900 this.el.slideIn(this.getSlideAnchor(), {
43901 callback: function(){
43903 this.initAutoHide();
43904 Roo.get(document).on("click", this.slideInIf, this);
43905 this.fireEvent("slideshow", this);
43912 afterSlideIn : function(){
43913 this.clearAutoHide();
43914 this.isSlid = false;
43915 this.clearMonitor();
43916 this.el.setStyle("z-index", "");
43917 if(this.collapseBtn){
43918 this.collapseBtn.show();
43920 this.closeBtn.setStyle('display', this.closeBtnState);
43922 this.stickBtn.hide();
43924 this.fireEvent("slidehide", this);
43927 slideIn : function(cb){
43928 if(!this.isSlid || this.el.hasActiveFx()){
43932 this.isSlid = false;
43933 this.beforeSlide();
43934 this.el.slideOut(this.getSlideAnchor(), {
43935 callback: function(){
43936 this.el.setLeftTop(-10000, -10000);
43938 this.afterSlideIn();
43946 slideInIf : function(e){
43947 if(!e.within(this.el)){
43952 animateCollapse : function(){
43953 this.beforeSlide();
43954 this.el.setStyle("z-index", 20000);
43955 var anchor = this.getSlideAnchor();
43956 this.el.slideOut(anchor, {
43957 callback : function(){
43958 this.el.setStyle("z-index", "");
43959 this.collapsedEl.slideIn(anchor, {duration:.3});
43961 this.el.setLocation(-10000,-10000);
43963 this.fireEvent("collapsed", this);
43970 animateExpand : function(){
43971 this.beforeSlide();
43972 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
43973 this.el.setStyle("z-index", 20000);
43974 this.collapsedEl.hide({
43977 this.el.slideIn(this.getSlideAnchor(), {
43978 callback : function(){
43979 this.el.setStyle("z-index", "");
43982 this.split.el.show();
43984 this.fireEvent("invalidated", this);
43985 this.fireEvent("expanded", this);
44013 getAnchor : function(){
44014 return this.anchors[this.position];
44017 getCollapseAnchor : function(){
44018 return this.canchors[this.position];
44021 getSlideAnchor : function(){
44022 return this.sanchors[this.position];
44025 getAlignAdj : function(){
44026 var cm = this.cmargins;
44027 switch(this.position){
44043 getExpandAdj : function(){
44044 var c = this.collapsedEl, cm = this.cmargins;
44045 switch(this.position){
44047 return [-(cm.right+c.getWidth()+cm.left), 0];
44050 return [cm.right+c.getWidth()+cm.left, 0];
44053 return [0, -(cm.top+cm.bottom+c.getHeight())];
44056 return [0, cm.top+cm.bottom+c.getHeight()];
44062 * Ext JS Library 1.1.1
44063 * Copyright(c) 2006-2007, Ext JS, LLC.
44065 * Originally Released Under LGPL - original licence link has changed is not relivant.
44068 * <script type="text/javascript">
44071 * These classes are private internal classes
44073 Roo.CenterLayoutRegion = function(mgr, config){
44074 Roo.LayoutRegion.call(this, mgr, config, "center");
44075 this.visible = true;
44076 this.minWidth = config.minWidth || 20;
44077 this.minHeight = config.minHeight || 20;
44080 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
44082 // center panel can't be hidden
44086 // center panel can't be hidden
44089 getMinWidth: function(){
44090 return this.minWidth;
44093 getMinHeight: function(){
44094 return this.minHeight;
44099 Roo.NorthLayoutRegion = function(mgr, config){
44100 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
44102 this.split.placement = Roo.SplitBar.TOP;
44103 this.split.orientation = Roo.SplitBar.VERTICAL;
44104 this.split.el.addClass("x-layout-split-v");
44106 var size = config.initialSize || config.height;
44107 if(typeof size != "undefined"){
44108 this.el.setHeight(size);
44111 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
44112 orientation: Roo.SplitBar.VERTICAL,
44113 getBox : function(){
44114 if(this.collapsed){
44115 return this.collapsedEl.getBox();
44117 var box = this.el.getBox();
44119 box.height += this.split.el.getHeight();
44124 updateBox : function(box){
44125 if(this.split && !this.collapsed){
44126 box.height -= this.split.el.getHeight();
44127 this.split.el.setLeft(box.x);
44128 this.split.el.setTop(box.y+box.height);
44129 this.split.el.setWidth(box.width);
44131 if(this.collapsed){
44132 this.updateBody(box.width, null);
44134 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44138 Roo.SouthLayoutRegion = function(mgr, config){
44139 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
44141 this.split.placement = Roo.SplitBar.BOTTOM;
44142 this.split.orientation = Roo.SplitBar.VERTICAL;
44143 this.split.el.addClass("x-layout-split-v");
44145 var size = config.initialSize || config.height;
44146 if(typeof size != "undefined"){
44147 this.el.setHeight(size);
44150 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
44151 orientation: Roo.SplitBar.VERTICAL,
44152 getBox : function(){
44153 if(this.collapsed){
44154 return this.collapsedEl.getBox();
44156 var box = this.el.getBox();
44158 var sh = this.split.el.getHeight();
44165 updateBox : function(box){
44166 if(this.split && !this.collapsed){
44167 var sh = this.split.el.getHeight();
44170 this.split.el.setLeft(box.x);
44171 this.split.el.setTop(box.y-sh);
44172 this.split.el.setWidth(box.width);
44174 if(this.collapsed){
44175 this.updateBody(box.width, null);
44177 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44181 Roo.EastLayoutRegion = function(mgr, config){
44182 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
44184 this.split.placement = Roo.SplitBar.RIGHT;
44185 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44186 this.split.el.addClass("x-layout-split-h");
44188 var size = config.initialSize || config.width;
44189 if(typeof size != "undefined"){
44190 this.el.setWidth(size);
44193 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
44194 orientation: Roo.SplitBar.HORIZONTAL,
44195 getBox : function(){
44196 if(this.collapsed){
44197 return this.collapsedEl.getBox();
44199 var box = this.el.getBox();
44201 var sw = this.split.el.getWidth();
44208 updateBox : function(box){
44209 if(this.split && !this.collapsed){
44210 var sw = this.split.el.getWidth();
44212 this.split.el.setLeft(box.x);
44213 this.split.el.setTop(box.y);
44214 this.split.el.setHeight(box.height);
44217 if(this.collapsed){
44218 this.updateBody(null, box.height);
44220 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44224 Roo.WestLayoutRegion = function(mgr, config){
44225 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
44227 this.split.placement = Roo.SplitBar.LEFT;
44228 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44229 this.split.el.addClass("x-layout-split-h");
44231 var size = config.initialSize || config.width;
44232 if(typeof size != "undefined"){
44233 this.el.setWidth(size);
44236 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
44237 orientation: Roo.SplitBar.HORIZONTAL,
44238 getBox : function(){
44239 if(this.collapsed){
44240 return this.collapsedEl.getBox();
44242 var box = this.el.getBox();
44244 box.width += this.split.el.getWidth();
44249 updateBox : function(box){
44250 if(this.split && !this.collapsed){
44251 var sw = this.split.el.getWidth();
44253 this.split.el.setLeft(box.x+box.width);
44254 this.split.el.setTop(box.y);
44255 this.split.el.setHeight(box.height);
44257 if(this.collapsed){
44258 this.updateBody(null, box.height);
44260 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44265 * Ext JS Library 1.1.1
44266 * Copyright(c) 2006-2007, Ext JS, LLC.
44268 * Originally Released Under LGPL - original licence link has changed is not relivant.
44271 * <script type="text/javascript">
44276 * Private internal class for reading and applying state
44278 Roo.LayoutStateManager = function(layout){
44279 // default empty state
44288 Roo.LayoutStateManager.prototype = {
44289 init : function(layout, provider){
44290 this.provider = provider;
44291 var state = provider.get(layout.id+"-layout-state");
44293 var wasUpdating = layout.isUpdating();
44295 layout.beginUpdate();
44297 for(var key in state){
44298 if(typeof state[key] != "function"){
44299 var rstate = state[key];
44300 var r = layout.getRegion(key);
44303 r.resizeTo(rstate.size);
44305 if(rstate.collapsed == true){
44308 r.expand(null, true);
44314 layout.endUpdate();
44316 this.state = state;
44318 this.layout = layout;
44319 layout.on("regionresized", this.onRegionResized, this);
44320 layout.on("regioncollapsed", this.onRegionCollapsed, this);
44321 layout.on("regionexpanded", this.onRegionExpanded, this);
44324 storeState : function(){
44325 this.provider.set(this.layout.id+"-layout-state", this.state);
44328 onRegionResized : function(region, newSize){
44329 this.state[region.getPosition()].size = newSize;
44333 onRegionCollapsed : function(region){
44334 this.state[region.getPosition()].collapsed = true;
44338 onRegionExpanded : function(region){
44339 this.state[region.getPosition()].collapsed = false;
44344 * Ext JS Library 1.1.1
44345 * Copyright(c) 2006-2007, Ext JS, LLC.
44347 * Originally Released Under LGPL - original licence link has changed is not relivant.
44350 * <script type="text/javascript">
44353 * @class Roo.ContentPanel
44354 * @extends Roo.util.Observable
44355 * A basic ContentPanel element.
44356 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
44357 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
44358 * @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
44359 * @cfg {Boolean} closable True if the panel can be closed/removed
44360 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
44361 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
44362 * @cfg {Toolbar} toolbar A toolbar for this panel
44363 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
44364 * @cfg {String} title The title for this panel
44365 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
44366 * @cfg {String} url Calls {@link #setUrl} with this value
44367 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
44368 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
44370 * Create a new ContentPanel.
44371 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
44372 * @param {String/Object} config A string to set only the title or a config object
44373 * @param {String} content (optional) Set the HTML content for this panel
44374 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
44376 Roo.ContentPanel = function(el, config, content){
44380 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
44384 if (config && config.parentLayout) {
44385 el = config.parentLayout.el.createChild();
44388 if(el.autoCreate){ // xtype is available if this is called from factory
44392 this.el = Roo.get(el);
44393 if(!this.el && config && config.autoCreate){
44394 if(typeof config.autoCreate == "object"){
44395 if(!config.autoCreate.id){
44396 config.autoCreate.id = config.id||el;
44398 this.el = Roo.DomHelper.append(document.body,
44399 config.autoCreate, true);
44401 this.el = Roo.DomHelper.append(document.body,
44402 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
44405 this.closable = false;
44406 this.loaded = false;
44407 this.active = false;
44408 if(typeof config == "string"){
44409 this.title = config;
44411 Roo.apply(this, config);
44414 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
44415 this.wrapEl = this.el.wrap();
44416 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
44423 this.resizeEl = Roo.get(this.resizeEl, true);
44425 this.resizeEl = this.el;
44430 * Fires when this panel is activated.
44431 * @param {Roo.ContentPanel} this
44435 * @event deactivate
44436 * Fires when this panel is activated.
44437 * @param {Roo.ContentPanel} this
44439 "deactivate" : true,
44443 * Fires when this panel is resized if fitToFrame is true.
44444 * @param {Roo.ContentPanel} this
44445 * @param {Number} width The width after any component adjustments
44446 * @param {Number} height The height after any component adjustments
44450 if(this.autoScroll){
44451 this.resizeEl.setStyle("overflow", "auto");
44453 content = content || this.content;
44455 this.setContent(content);
44457 if(config && config.url){
44458 this.setUrl(this.url, this.params, this.loadOnce);
44463 Roo.ContentPanel.superclass.constructor.call(this);
44466 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
44468 setRegion : function(region){
44469 this.region = region;
44471 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
44473 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
44478 * Returns the toolbar for this Panel if one was configured.
44479 * @return {Roo.Toolbar}
44481 getToolbar : function(){
44482 return this.toolbar;
44485 setActiveState : function(active){
44486 this.active = active;
44488 this.fireEvent("deactivate", this);
44490 this.fireEvent("activate", this);
44494 * Updates this panel's element
44495 * @param {String} content The new content
44496 * @param {Boolean} loadScripts (optional) true to look for and process scripts
44498 setContent : function(content, loadScripts){
44499 this.el.update(content, loadScripts);
44502 ignoreResize : function(w, h){
44503 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
44506 this.lastSize = {width: w, height: h};
44511 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
44512 * @return {Roo.UpdateManager} The UpdateManager
44514 getUpdateManager : function(){
44515 return this.el.getUpdateManager();
44518 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
44519 * @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:
44522 url: "your-url.php",
44523 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
44524 callback: yourFunction,
44525 scope: yourObject, //(optional scope)
44528 text: "Loading...",
44533 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
44534 * 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.
44535 * @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}
44536 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
44537 * @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.
44538 * @return {Roo.ContentPanel} this
44541 var um = this.el.getUpdateManager();
44542 um.update.apply(um, arguments);
44548 * 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.
44549 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
44550 * @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)
44551 * @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)
44552 * @return {Roo.UpdateManager} The UpdateManager
44554 setUrl : function(url, params, loadOnce){
44555 if(this.refreshDelegate){
44556 this.removeListener("activate", this.refreshDelegate);
44558 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
44559 this.on("activate", this.refreshDelegate);
44560 return this.el.getUpdateManager();
44563 _handleRefresh : function(url, params, loadOnce){
44564 if(!loadOnce || !this.loaded){
44565 var updater = this.el.getUpdateManager();
44566 updater.update(url, params, this._setLoaded.createDelegate(this));
44570 _setLoaded : function(){
44571 this.loaded = true;
44575 * Returns this panel's id
44578 getId : function(){
44583 * Returns this panel's element - used by regiosn to add.
44584 * @return {Roo.Element}
44586 getEl : function(){
44587 return this.wrapEl || this.el;
44590 adjustForComponents : function(width, height){
44591 if(this.resizeEl != this.el){
44592 width -= this.el.getFrameWidth('lr');
44593 height -= this.el.getFrameWidth('tb');
44596 var te = this.toolbar.getEl();
44597 height -= te.getHeight();
44598 te.setWidth(width);
44600 if(this.adjustments){
44601 width += this.adjustments[0];
44602 height += this.adjustments[1];
44604 return {"width": width, "height": height};
44607 setSize : function(width, height){
44608 if(this.fitToFrame && !this.ignoreResize(width, height)){
44609 if(this.fitContainer && this.resizeEl != this.el){
44610 this.el.setSize(width, height);
44612 var size = this.adjustForComponents(width, height);
44613 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
44614 this.fireEvent('resize', this, size.width, size.height);
44619 * Returns this panel's title
44622 getTitle : function(){
44627 * Set this panel's title
44628 * @param {String} title
44630 setTitle : function(title){
44631 this.title = title;
44633 this.region.updatePanelTitle(this, title);
44638 * Returns true is this panel was configured to be closable
44639 * @return {Boolean}
44641 isClosable : function(){
44642 return this.closable;
44645 beforeSlide : function(){
44647 this.resizeEl.clip();
44650 afterSlide : function(){
44652 this.resizeEl.unclip();
44656 * Force a content refresh from the URL specified in the {@link #setUrl} method.
44657 * Will fail silently if the {@link #setUrl} method has not been called.
44658 * This does not activate the panel, just updates its content.
44660 refresh : function(){
44661 if(this.refreshDelegate){
44662 this.loaded = false;
44663 this.refreshDelegate();
44668 * Destroys this panel
44670 destroy : function(){
44671 this.el.removeAllListeners();
44672 var tempEl = document.createElement("span");
44673 tempEl.appendChild(this.el.dom);
44674 tempEl.innerHTML = "";
44680 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
44690 * @param {Object} cfg Xtype definition of item to add.
44693 addxtype : function(cfg) {
44695 if (cfg.xtype.match(/^Form$/)) {
44696 var el = this.el.createChild();
44698 this.form = new Roo.form.Form(cfg);
44701 if ( this.form.allItems.length) this.form.render(el.dom);
44704 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
44708 return new Roo[cfg.xtype](cfg);
44717 * @class Roo.GridPanel
44718 * @extends Roo.ContentPanel
44720 * Create a new GridPanel.
44721 * @param {Roo.grid.Grid} grid The grid for this panel
44722 * @param {String/Object} config A string to set only the panel's title, or a config object
44724 Roo.GridPanel = function(grid, config){
44727 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
44728 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
44730 this.wrapper.dom.appendChild(grid.getGridEl().dom);
44732 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
44735 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
44737 // xtype created footer. - not sure if will work as we normally have to render first..
44738 if (this.footer && !this.footer.el && this.footer.xtype) {
44740 this.footer.container = this.grid.getView().getFooterPanel(true);
44741 this.footer.dataSource = this.grid.dataSource;
44742 this.footer = Roo.factory(this.footer, Roo);
44746 grid.monitorWindowResize = false; // turn off autosizing
44747 grid.autoHeight = false;
44748 grid.autoWidth = false;
44750 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
44753 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
44754 getId : function(){
44755 return this.grid.id;
44759 * Returns the grid for this panel
44760 * @return {Roo.grid.Grid}
44762 getGrid : function(){
44766 setSize : function(width, height){
44767 if(!this.ignoreResize(width, height)){
44768 var grid = this.grid;
44769 var size = this.adjustForComponents(width, height);
44770 grid.getGridEl().setSize(size.width, size.height);
44775 beforeSlide : function(){
44776 this.grid.getView().scroller.clip();
44779 afterSlide : function(){
44780 this.grid.getView().scroller.unclip();
44783 destroy : function(){
44784 this.grid.destroy();
44786 Roo.GridPanel.superclass.destroy.call(this);
44792 * @class Roo.NestedLayoutPanel
44793 * @extends Roo.ContentPanel
44795 * Create a new NestedLayoutPanel.
44798 * @param {Roo.BorderLayout} layout The layout for this panel
44799 * @param {String/Object} config A string to set only the title or a config object
44801 Roo.NestedLayoutPanel = function(layout, config)
44803 // construct with only one argument..
44804 /* FIXME - implement nicer consturctors
44805 if (layout.layout) {
44807 layout = config.layout;
44808 delete config.layout;
44810 if (layout.xtype && !layout.getEl) {
44811 // then layout needs constructing..
44812 layout = Roo.factory(layout, Roo);
44816 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
44818 layout.monitorWindowResize = false; // turn off autosizing
44819 this.layout = layout;
44820 this.layout.getEl().addClass("x-layout-nested-layout");
44826 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
44828 setSize : function(width, height){
44829 if(!this.ignoreResize(width, height)){
44830 var size = this.adjustForComponents(width, height);
44831 var el = this.layout.getEl();
44832 el.setSize(size.width, size.height);
44833 var touch = el.dom.offsetWidth;
44834 this.layout.layout();
44835 // ie requires a double layout on the first pass
44836 if(Roo.isIE && !this.initialized){
44837 this.initialized = true;
44838 this.layout.layout();
44843 // activate all subpanels if not currently active..
44845 setActiveState : function(active){
44846 this.active = active;
44848 this.fireEvent("deactivate", this);
44852 this.fireEvent("activate", this);
44853 // not sure if this should happen before or after..
44854 if (!this.layout) {
44855 return; // should not happen..
44858 for (var r in this.layout.regions) {
44859 reg = this.layout.getRegion(r);
44860 if (reg.getActivePanel()) {
44861 //reg.showPanel(reg.getActivePanel()); // force it to activate..
44862 reg.setActivePanel(reg.getActivePanel());
44865 if (!reg.panels.length) {
44868 reg.showPanel(reg.getPanel(0));
44877 * Returns the nested BorderLayout for this panel
44878 * @return {Roo.BorderLayout}
44880 getLayout : function(){
44881 return this.layout;
44885 * Adds a xtype elements to the layout of the nested panel
44889 xtype : 'ContentPanel',
44896 xtype : 'NestedLayoutPanel',
44902 items : [ ... list of content panels or nested layout panels.. ]
44906 * @param {Object} cfg Xtype definition of item to add.
44908 addxtype : function(cfg) {
44909 return this.layout.addxtype(cfg);
44914 Roo.ScrollPanel = function(el, config, content){
44915 config = config || {};
44916 config.fitToFrame = true;
44917 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
44919 this.el.dom.style.overflow = "hidden";
44920 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
44921 this.el.removeClass("x-layout-inactive-content");
44922 this.el.on("mousewheel", this.onWheel, this);
44924 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
44925 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
44926 up.unselectable(); down.unselectable();
44927 up.on("click", this.scrollUp, this);
44928 down.on("click", this.scrollDown, this);
44929 up.addClassOnOver("x-scroller-btn-over");
44930 down.addClassOnOver("x-scroller-btn-over");
44931 up.addClassOnClick("x-scroller-btn-click");
44932 down.addClassOnClick("x-scroller-btn-click");
44933 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
44935 this.resizeEl = this.el;
44936 this.el = wrap; this.up = up; this.down = down;
44939 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
44941 wheelIncrement : 5,
44942 scrollUp : function(){
44943 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
44946 scrollDown : function(){
44947 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
44950 afterScroll : function(){
44951 var el = this.resizeEl;
44952 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
44953 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44954 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44957 setSize : function(){
44958 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
44959 this.afterScroll();
44962 onWheel : function(e){
44963 var d = e.getWheelDelta();
44964 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
44965 this.afterScroll();
44969 setContent : function(content, loadScripts){
44970 this.resizeEl.update(content, loadScripts);
44984 * @class Roo.TreePanel
44985 * @extends Roo.ContentPanel
44987 * Create a new TreePanel.
44988 * @param {String/Object} config A string to set only the panel's title, or a config object
44989 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
44991 Roo.TreePanel = function(config){
44992 var el = config.el;
44993 var tree = config.tree;
44994 delete config.tree;
44995 delete config.el; // hopefull!
44996 Roo.TreePanel.superclass.constructor.call(this, el, config);
44997 var treeEl = el.createChild();
44998 this.tree = new Roo.tree.TreePanel(treeEl , tree);
44999 //console.log(tree);
45000 this.on('activate', function()
45002 if (this.tree.rendered) {
45005 //console.log('render tree');
45006 this.tree.render();
45009 this.on('resize', function (cp, w, h) {
45010 this.tree.innerCt.setWidth(w);
45011 this.tree.innerCt.setHeight(h);
45012 this.tree.innerCt.setStyle('overflow-y', 'auto');
45019 Roo.extend(Roo.TreePanel, Roo.ContentPanel);
45033 * Ext JS Library 1.1.1
45034 * Copyright(c) 2006-2007, Ext JS, LLC.
45036 * Originally Released Under LGPL - original licence link has changed is not relivant.
45039 * <script type="text/javascript">
45044 * @class Roo.ReaderLayout
45045 * @extends Roo.BorderLayout
45046 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
45047 * center region containing two nested regions (a top one for a list view and one for item preview below),
45048 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
45049 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
45050 * expedites the setup of the overall layout and regions for this common application style.
45053 var reader = new Roo.ReaderLayout();
45054 var CP = Roo.ContentPanel; // shortcut for adding
45056 reader.beginUpdate();
45057 reader.add("north", new CP("north", "North"));
45058 reader.add("west", new CP("west", {title: "West"}));
45059 reader.add("east", new CP("east", {title: "East"}));
45061 reader.regions.listView.add(new CP("listView", "List"));
45062 reader.regions.preview.add(new CP("preview", "Preview"));
45063 reader.endUpdate();
45066 * Create a new ReaderLayout
45067 * @param {Object} config Configuration options
45068 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
45069 * document.body if omitted)
45071 Roo.ReaderLayout = function(config, renderTo){
45072 var c = config || {size:{}};
45073 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
45074 north: c.north !== false ? Roo.apply({
45078 }, c.north) : false,
45079 west: c.west !== false ? Roo.apply({
45087 margins:{left:5,right:0,bottom:5,top:5},
45088 cmargins:{left:5,right:5,bottom:5,top:5}
45089 }, c.west) : false,
45090 east: c.east !== false ? Roo.apply({
45098 margins:{left:0,right:5,bottom:5,top:5},
45099 cmargins:{left:5,right:5,bottom:5,top:5}
45100 }, c.east) : false,
45101 center: Roo.apply({
45102 tabPosition: 'top',
45106 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
45110 this.el.addClass('x-reader');
45112 this.beginUpdate();
45114 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
45115 south: c.preview !== false ? Roo.apply({
45122 cmargins:{top:5,left:0, right:0, bottom:0}
45123 }, c.preview) : false,
45124 center: Roo.apply({
45130 this.add('center', new Roo.NestedLayoutPanel(inner,
45131 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
45135 this.regions.preview = inner.getRegion('south');
45136 this.regions.listView = inner.getRegion('center');
45139 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
45141 * Ext JS Library 1.1.1
45142 * Copyright(c) 2006-2007, Ext JS, LLC.
45144 * Originally Released Under LGPL - original licence link has changed is not relivant.
45147 * <script type="text/javascript">
45151 * @class Roo.grid.Grid
45152 * @extends Roo.util.Observable
45153 * This class represents the primary interface of a component based grid control.
45154 * <br><br>Usage:<pre><code>
45155 var grid = new Roo.grid.Grid("my-container-id", {
45158 selModel: mySelectionModel,
45159 autoSizeColumns: true,
45160 monitorWindowResize: false,
45161 trackMouseOver: true
45166 * <b>Common Problems:</b><br/>
45167 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
45168 * element will correct this<br/>
45169 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
45170 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
45171 * are unpredictable.<br/>
45172 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
45173 * grid to calculate dimensions/offsets.<br/>
45175 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
45176 * The container MUST have some type of size defined for the grid to fill. The container will be
45177 * automatically set to position relative if it isn't already.
45178 * @param {Object} config A config object that sets properties on this grid.
45180 Roo.grid.Grid = function(container, config){
45181 // initialize the container
45182 this.container = Roo.get(container);
45183 this.container.update("");
45184 this.container.setStyle("overflow", "hidden");
45185 this.container.addClass('x-grid-container');
45187 this.id = this.container.id;
45189 Roo.apply(this, config);
45190 // check and correct shorthanded configs
45192 this.dataSource = this.ds;
45196 this.colModel = this.cm;
45200 this.selModel = this.sm;
45204 if (this.selModel) {
45205 this.selModel = Roo.factory(this.selModel, Roo.grid);
45206 this.sm = this.selModel;
45207 this.sm.xmodule = this.xmodule || false;
45209 if (typeof(this.colModel.config) == 'undefined') {
45210 this.colModel = new Roo.grid.ColumnModel(this.colModel);
45211 this.cm = this.colModel;
45212 this.cm.xmodule = this.xmodule || false;
45214 if (this.dataSource) {
45215 this.dataSource= Roo.factory(this.dataSource, Roo.data);
45216 this.ds = this.dataSource;
45217 this.ds.xmodule = this.xmodule || false;
45224 this.container.setWidth(this.width);
45228 this.container.setHeight(this.height);
45235 * The raw click event for the entire grid.
45236 * @param {Roo.EventObject} e
45241 * The raw dblclick event for the entire grid.
45242 * @param {Roo.EventObject} e
45246 * @event contextmenu
45247 * The raw contextmenu event for the entire grid.
45248 * @param {Roo.EventObject} e
45250 "contextmenu" : true,
45253 * The raw mousedown event for the entire grid.
45254 * @param {Roo.EventObject} e
45256 "mousedown" : true,
45259 * The raw mouseup event for the entire grid.
45260 * @param {Roo.EventObject} e
45265 * The raw mouseover event for the entire grid.
45266 * @param {Roo.EventObject} e
45268 "mouseover" : true,
45271 * The raw mouseout event for the entire grid.
45272 * @param {Roo.EventObject} e
45277 * The raw keypress event for the entire grid.
45278 * @param {Roo.EventObject} e
45283 * The raw keydown event for the entire grid.
45284 * @param {Roo.EventObject} e
45292 * Fires when a cell is clicked
45293 * @param {Grid} this
45294 * @param {Number} rowIndex
45295 * @param {Number} columnIndex
45296 * @param {Roo.EventObject} e
45298 "cellclick" : true,
45300 * @event celldblclick
45301 * Fires when a cell is double clicked
45302 * @param {Grid} this
45303 * @param {Number} rowIndex
45304 * @param {Number} columnIndex
45305 * @param {Roo.EventObject} e
45307 "celldblclick" : true,
45310 * Fires when a row is clicked
45311 * @param {Grid} this
45312 * @param {Number} rowIndex
45313 * @param {Roo.EventObject} e
45317 * @event rowdblclick
45318 * Fires when a row is double clicked
45319 * @param {Grid} this
45320 * @param {Number} rowIndex
45321 * @param {Roo.EventObject} e
45323 "rowdblclick" : true,
45325 * @event headerclick
45326 * Fires when a header is clicked
45327 * @param {Grid} this
45328 * @param {Number} columnIndex
45329 * @param {Roo.EventObject} e
45331 "headerclick" : true,
45333 * @event headerdblclick
45334 * Fires when a header cell is double clicked
45335 * @param {Grid} this
45336 * @param {Number} columnIndex
45337 * @param {Roo.EventObject} e
45339 "headerdblclick" : true,
45341 * @event rowcontextmenu
45342 * Fires when a row is right clicked
45343 * @param {Grid} this
45344 * @param {Number} rowIndex
45345 * @param {Roo.EventObject} e
45347 "rowcontextmenu" : true,
45349 * @event cellcontextmenu
45350 * Fires when a cell is right clicked
45351 * @param {Grid} this
45352 * @param {Number} rowIndex
45353 * @param {Number} cellIndex
45354 * @param {Roo.EventObject} e
45356 "cellcontextmenu" : true,
45358 * @event headercontextmenu
45359 * Fires when a header is right clicked
45360 * @param {Grid} this
45361 * @param {Number} columnIndex
45362 * @param {Roo.EventObject} e
45364 "headercontextmenu" : true,
45366 * @event bodyscroll
45367 * Fires when the body element is scrolled
45368 * @param {Number} scrollLeft
45369 * @param {Number} scrollTop
45371 "bodyscroll" : true,
45373 * @event columnresize
45374 * Fires when the user resizes a column
45375 * @param {Number} columnIndex
45376 * @param {Number} newSize
45378 "columnresize" : true,
45380 * @event columnmove
45381 * Fires when the user moves a column
45382 * @param {Number} oldIndex
45383 * @param {Number} newIndex
45385 "columnmove" : true,
45388 * Fires when row(s) start being dragged
45389 * @param {Grid} this
45390 * @param {Roo.GridDD} dd The drag drop object
45391 * @param {event} e The raw browser event
45393 "startdrag" : true,
45396 * Fires when a drag operation is complete
45397 * @param {Grid} this
45398 * @param {Roo.GridDD} dd The drag drop object
45399 * @param {event} e The raw browser event
45404 * Fires when dragged row(s) are dropped on a valid DD target
45405 * @param {Grid} this
45406 * @param {Roo.GridDD} dd The drag drop object
45407 * @param {String} targetId The target drag drop object
45408 * @param {event} e The raw browser event
45413 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
45414 * @param {Grid} this
45415 * @param {Roo.GridDD} dd The drag drop object
45416 * @param {String} targetId The target drag drop object
45417 * @param {event} e The raw browser event
45422 * Fires when the dragged row(s) first cross another DD target while being dragged
45423 * @param {Grid} this
45424 * @param {Roo.GridDD} dd The drag drop object
45425 * @param {String} targetId The target drag drop object
45426 * @param {event} e The raw browser event
45428 "dragenter" : true,
45431 * Fires when the dragged row(s) leave another DD target while being dragged
45432 * @param {Grid} this
45433 * @param {Roo.GridDD} dd The drag drop object
45434 * @param {String} targetId The target drag drop object
45435 * @param {event} e The raw browser event
45440 * Fires when the grid is rendered
45441 * @param {Grid} grid
45446 Roo.grid.Grid.superclass.constructor.call(this);
45448 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
45450 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
45452 minColumnWidth : 25,
45455 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
45456 * <b>on initial render.</b> It is more efficient to explicitly size the columns
45457 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
45459 autoSizeColumns : false,
45462 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
45464 autoSizeHeaders : true,
45467 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
45469 monitorWindowResize : true,
45472 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
45473 * rows measured to get a columns size. Default is 0 (all rows).
45475 maxRowsToMeasure : 0,
45478 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
45480 trackMouseOver : true,
45483 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
45485 enableDragDrop : false,
45488 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
45490 enableColumnMove : true,
45493 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
45495 enableColumnHide : true,
45498 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
45500 enableRowHeightSync : false,
45503 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
45508 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
45510 autoHeight : false,
45513 * @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.
45515 autoExpandColumn : false,
45518 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
45521 autoExpandMin : 50,
45524 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
45526 autoExpandMax : 1000,
45529 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
45534 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
45542 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
45543 * of a fixed width. Default is false.
45546 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
45549 * Called once after all setup has been completed and the grid is ready to be rendered.
45550 * @return {Roo.grid.Grid} this
45552 render : function(){
45553 var c = this.container;
45554 // try to detect autoHeight/width mode
45555 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
45556 this.autoHeight = true;
45558 var view = this.getView();
45561 c.on("click", this.onClick, this);
45562 c.on("dblclick", this.onDblClick, this);
45563 c.on("contextmenu", this.onContextMenu, this);
45564 c.on("keydown", this.onKeyDown, this);
45566 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
45568 this.getSelectionModel().init(this);
45573 this.loadMask = new Roo.LoadMask(this.container,
45574 Roo.apply({store:this.dataSource}, this.loadMask));
45578 if (this.toolbar && this.toolbar.xtype) {
45579 this.toolbar.container = this.getView().getHeaderPanel(true);
45580 this.toolbar = new Ext.Toolbar(this.toolbar);
45582 if (this.footer && this.footer.xtype) {
45583 this.footer.dataSource = this.getDataSource();
45584 this.footer.container = this.getView().getFooterPanel(true);
45585 this.footer = Roo.factory(this.footer, Roo);
45587 this.rendered = true;
45588 this.fireEvent('render', this);
45593 * Reconfigures the grid to use a different Store and Column Model.
45594 * The View will be bound to the new objects and refreshed.
45595 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
45596 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
45598 reconfigure : function(dataSource, colModel){
45600 this.loadMask.destroy();
45601 this.loadMask = new Roo.LoadMask(this.container,
45602 Roo.apply({store:dataSource}, this.loadMask));
45604 this.view.bind(dataSource, colModel);
45605 this.dataSource = dataSource;
45606 this.colModel = colModel;
45607 this.view.refresh(true);
45611 onKeyDown : function(e){
45612 this.fireEvent("keydown", e);
45616 * Destroy this grid.
45617 * @param {Boolean} removeEl True to remove the element
45619 destroy : function(removeEl, keepListeners){
45621 this.loadMask.destroy();
45623 var c = this.container;
45624 c.removeAllListeners();
45625 this.view.destroy();
45626 this.colModel.purgeListeners();
45627 if(!keepListeners){
45628 this.purgeListeners();
45631 if(removeEl === true){
45637 processEvent : function(name, e){
45638 this.fireEvent(name, e);
45639 var t = e.getTarget();
45641 var header = v.findHeaderIndex(t);
45642 if(header !== false){
45643 this.fireEvent("header" + name, this, header, e);
45645 var row = v.findRowIndex(t);
45646 var cell = v.findCellIndex(t);
45648 this.fireEvent("row" + name, this, row, e);
45649 if(cell !== false){
45650 this.fireEvent("cell" + name, this, row, cell, e);
45657 onClick : function(e){
45658 this.processEvent("click", e);
45662 onContextMenu : function(e, t){
45663 this.processEvent("contextmenu", e);
45667 onDblClick : function(e){
45668 this.processEvent("dblclick", e);
45672 walkCells : function(row, col, step, fn, scope){
45673 var cm = this.colModel, clen = cm.getColumnCount();
45674 var ds = this.dataSource, rlen = ds.getCount(), first = true;
45686 if(fn.call(scope || this, row, col, cm) === true){
45704 if(fn.call(scope || this, row, col, cm) === true){
45716 getSelections : function(){
45717 return this.selModel.getSelections();
45721 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
45722 * but if manual update is required this method will initiate it.
45724 autoSize : function(){
45726 this.view.layout();
45727 if(this.view.adjustForScroll){
45728 this.view.adjustForScroll();
45734 * Returns the grid's underlying element.
45735 * @return {Element} The element
45737 getGridEl : function(){
45738 return this.container;
45741 // private for compatibility, overridden by editor grid
45742 stopEditing : function(){},
45745 * Returns the grid's SelectionModel.
45746 * @return {SelectionModel}
45748 getSelectionModel : function(){
45749 if(!this.selModel){
45750 this.selModel = new Roo.grid.RowSelectionModel();
45752 return this.selModel;
45756 * Returns the grid's DataSource.
45757 * @return {DataSource}
45759 getDataSource : function(){
45760 return this.dataSource;
45764 * Returns the grid's ColumnModel.
45765 * @return {ColumnModel}
45767 getColumnModel : function(){
45768 return this.colModel;
45772 * Returns the grid's GridView object.
45773 * @return {GridView}
45775 getView : function(){
45777 this.view = new Roo.grid.GridView(this.viewConfig);
45782 * Called to get grid's drag proxy text, by default returns this.ddText.
45785 getDragDropText : function(){
45786 var count = this.selModel.getCount();
45787 return String.format(this.ddText, count, count == 1 ? '' : 's');
45791 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
45792 * %0 is replaced with the number of selected rows.
45795 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
45797 * Ext JS Library 1.1.1
45798 * Copyright(c) 2006-2007, Ext JS, LLC.
45800 * Originally Released Under LGPL - original licence link has changed is not relivant.
45803 * <script type="text/javascript">
45806 Roo.grid.AbstractGridView = function(){
45810 "beforerowremoved" : true,
45811 "beforerowsinserted" : true,
45812 "beforerefresh" : true,
45813 "rowremoved" : true,
45814 "rowsinserted" : true,
45815 "rowupdated" : true,
45818 Roo.grid.AbstractGridView.superclass.constructor.call(this);
45821 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
45822 rowClass : "x-grid-row",
45823 cellClass : "x-grid-cell",
45824 tdClass : "x-grid-td",
45825 hdClass : "x-grid-hd",
45826 splitClass : "x-grid-hd-split",
45828 init: function(grid){
45830 var cid = this.grid.getGridEl().id;
45831 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
45832 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
45833 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
45834 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
45837 getColumnRenderers : function(){
45838 var renderers = [];
45839 var cm = this.grid.colModel;
45840 var colCount = cm.getColumnCount();
45841 for(var i = 0; i < colCount; i++){
45842 renderers[i] = cm.getRenderer(i);
45847 getColumnIds : function(){
45849 var cm = this.grid.colModel;
45850 var colCount = cm.getColumnCount();
45851 for(var i = 0; i < colCount; i++){
45852 ids[i] = cm.getColumnId(i);
45857 getDataIndexes : function(){
45858 if(!this.indexMap){
45859 this.indexMap = this.buildIndexMap();
45861 return this.indexMap.colToData;
45864 getColumnIndexByDataIndex : function(dataIndex){
45865 if(!this.indexMap){
45866 this.indexMap = this.buildIndexMap();
45868 return this.indexMap.dataToCol[dataIndex];
45872 * Set a css style for a column dynamically.
45873 * @param {Number} colIndex The index of the column
45874 * @param {String} name The css property name
45875 * @param {String} value The css value
45877 setCSSStyle : function(colIndex, name, value){
45878 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
45879 Roo.util.CSS.updateRule(selector, name, value);
45882 generateRules : function(cm){
45883 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
45884 Roo.util.CSS.removeStyleSheet(rulesId);
45885 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
45886 var cid = cm.getColumnId(i);
45887 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
45888 this.tdSelector, cid, " {\n}\n",
45889 this.hdSelector, cid, " {\n}\n",
45890 this.splitSelector, cid, " {\n}\n");
45892 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
45896 * Ext JS Library 1.1.1
45897 * Copyright(c) 2006-2007, Ext JS, LLC.
45899 * Originally Released Under LGPL - original licence link has changed is not relivant.
45902 * <script type="text/javascript">
45906 // This is a support class used internally by the Grid components
45907 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
45909 this.view = grid.getView();
45910 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45911 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
45913 this.setHandleElId(Roo.id(hd));
45914 this.setOuterHandleElId(Roo.id(hd2));
45916 this.scroll = false;
45918 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
45920 getDragData : function(e){
45921 var t = Roo.lib.Event.getTarget(e);
45922 var h = this.view.findHeaderCell(t);
45924 return {ddel: h.firstChild, header:h};
45929 onInitDrag : function(e){
45930 this.view.headersDisabled = true;
45931 var clone = this.dragData.ddel.cloneNode(true);
45932 clone.id = Roo.id();
45933 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
45934 this.proxy.update(clone);
45938 afterValidDrop : function(){
45940 setTimeout(function(){
45941 v.headersDisabled = false;
45945 afterInvalidDrop : function(){
45947 setTimeout(function(){
45948 v.headersDisabled = false;
45954 * Ext JS Library 1.1.1
45955 * Copyright(c) 2006-2007, Ext JS, LLC.
45957 * Originally Released Under LGPL - original licence link has changed is not relivant.
45960 * <script type="text/javascript">
45963 // This is a support class used internally by the Grid components
45964 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
45966 this.view = grid.getView();
45967 // split the proxies so they don't interfere with mouse events
45968 this.proxyTop = Roo.DomHelper.append(document.body, {
45969 cls:"col-move-top", html:" "
45971 this.proxyBottom = Roo.DomHelper.append(document.body, {
45972 cls:"col-move-bottom", html:" "
45974 this.proxyTop.hide = this.proxyBottom.hide = function(){
45975 this.setLeftTop(-100,-100);
45976 this.setStyle("visibility", "hidden");
45978 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45979 // temporarily disabled
45980 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
45981 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
45983 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
45984 proxyOffsets : [-4, -9],
45985 fly: Roo.Element.fly,
45987 getTargetFromEvent : function(e){
45988 var t = Roo.lib.Event.getTarget(e);
45989 var cindex = this.view.findCellIndex(t);
45990 if(cindex !== false){
45991 return this.view.getHeaderCell(cindex);
45995 nextVisible : function(h){
45996 var v = this.view, cm = this.grid.colModel;
45999 if(!cm.isHidden(v.getCellIndex(h))){
46007 prevVisible : function(h){
46008 var v = this.view, cm = this.grid.colModel;
46011 if(!cm.isHidden(v.getCellIndex(h))){
46019 positionIndicator : function(h, n, e){
46020 var x = Roo.lib.Event.getPageX(e);
46021 var r = Roo.lib.Dom.getRegion(n.firstChild);
46022 var px, pt, py = r.top + this.proxyOffsets[1];
46023 if((r.right - x) <= (r.right-r.left)/2){
46024 px = r.right+this.view.borderWidth;
46030 var oldIndex = this.view.getCellIndex(h);
46031 var newIndex = this.view.getCellIndex(n);
46033 if(this.grid.colModel.isFixed(newIndex)){
46037 var locked = this.grid.colModel.isLocked(newIndex);
46042 if(oldIndex < newIndex){
46045 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
46048 px += this.proxyOffsets[0];
46049 this.proxyTop.setLeftTop(px, py);
46050 this.proxyTop.show();
46051 if(!this.bottomOffset){
46052 this.bottomOffset = this.view.mainHd.getHeight();
46054 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
46055 this.proxyBottom.show();
46059 onNodeEnter : function(n, dd, e, data){
46060 if(data.header != n){
46061 this.positionIndicator(data.header, n, e);
46065 onNodeOver : function(n, dd, e, data){
46066 var result = false;
46067 if(data.header != n){
46068 result = this.positionIndicator(data.header, n, e);
46071 this.proxyTop.hide();
46072 this.proxyBottom.hide();
46074 return result ? this.dropAllowed : this.dropNotAllowed;
46077 onNodeOut : function(n, dd, e, data){
46078 this.proxyTop.hide();
46079 this.proxyBottom.hide();
46082 onNodeDrop : function(n, dd, e, data){
46083 var h = data.header;
46085 var cm = this.grid.colModel;
46086 var x = Roo.lib.Event.getPageX(e);
46087 var r = Roo.lib.Dom.getRegion(n.firstChild);
46088 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
46089 var oldIndex = this.view.getCellIndex(h);
46090 var newIndex = this.view.getCellIndex(n);
46091 var locked = cm.isLocked(newIndex);
46095 if(oldIndex < newIndex){
46098 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
46101 cm.setLocked(oldIndex, locked, true);
46102 cm.moveColumn(oldIndex, newIndex);
46103 this.grid.fireEvent("columnmove", oldIndex, newIndex);
46111 * Ext JS Library 1.1.1
46112 * Copyright(c) 2006-2007, Ext JS, LLC.
46114 * Originally Released Under LGPL - original licence link has changed is not relivant.
46117 * <script type="text/javascript">
46121 * @class Roo.grid.GridView
46122 * @extends Roo.util.Observable
46125 * @param {Object} config
46127 Roo.grid.GridView = function(config){
46128 Roo.grid.GridView.superclass.constructor.call(this);
46131 Roo.apply(this, config);
46134 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
46137 * Override this function to apply custom css classes to rows during rendering
46138 * @param {Record} record The record
46139 * @param {Number} index
46140 * @method getRowClass
46142 rowClass : "x-grid-row",
46144 cellClass : "x-grid-col",
46146 tdClass : "x-grid-td",
46148 hdClass : "x-grid-hd",
46150 splitClass : "x-grid-split",
46152 sortClasses : ["sort-asc", "sort-desc"],
46154 enableMoveAnim : false,
46158 dh : Roo.DomHelper,
46160 fly : Roo.Element.fly,
46162 css : Roo.util.CSS,
46168 scrollIncrement : 22,
46170 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
46172 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
46174 bind : function(ds, cm){
46176 this.ds.un("load", this.onLoad, this);
46177 this.ds.un("datachanged", this.onDataChange, this);
46178 this.ds.un("add", this.onAdd, this);
46179 this.ds.un("remove", this.onRemove, this);
46180 this.ds.un("update", this.onUpdate, this);
46181 this.ds.un("clear", this.onClear, this);
46184 ds.on("load", this.onLoad, this);
46185 ds.on("datachanged", this.onDataChange, this);
46186 ds.on("add", this.onAdd, this);
46187 ds.on("remove", this.onRemove, this);
46188 ds.on("update", this.onUpdate, this);
46189 ds.on("clear", this.onClear, this);
46194 this.cm.un("widthchange", this.onColWidthChange, this);
46195 this.cm.un("headerchange", this.onHeaderChange, this);
46196 this.cm.un("hiddenchange", this.onHiddenChange, this);
46197 this.cm.un("columnmoved", this.onColumnMove, this);
46198 this.cm.un("columnlockchange", this.onColumnLock, this);
46201 this.generateRules(cm);
46202 cm.on("widthchange", this.onColWidthChange, this);
46203 cm.on("headerchange", this.onHeaderChange, this);
46204 cm.on("hiddenchange", this.onHiddenChange, this);
46205 cm.on("columnmoved", this.onColumnMove, this);
46206 cm.on("columnlockchange", this.onColumnLock, this);
46211 init: function(grid){
46212 Roo.grid.GridView.superclass.init.call(this, grid);
46214 this.bind(grid.dataSource, grid.colModel);
46216 grid.on("headerclick", this.handleHeaderClick, this);
46218 if(grid.trackMouseOver){
46219 grid.on("mouseover", this.onRowOver, this);
46220 grid.on("mouseout", this.onRowOut, this);
46222 grid.cancelTextSelection = function(){};
46223 this.gridId = grid.id;
46225 var tpls = this.templates || {};
46228 tpls.master = new Roo.Template(
46229 '<div class="x-grid" hidefocus="true">',
46230 '<div class="x-grid-topbar"></div>',
46231 '<div class="x-grid-scroller"><div></div></div>',
46232 '<div class="x-grid-locked">',
46233 '<div class="x-grid-header">{lockedHeader}</div>',
46234 '<div class="x-grid-body">{lockedBody}</div>',
46236 '<div class="x-grid-viewport">',
46237 '<div class="x-grid-header">{header}</div>',
46238 '<div class="x-grid-body">{body}</div>',
46240 '<div class="x-grid-bottombar"></div>',
46241 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
46242 '<div class="x-grid-resize-proxy"> </div>',
46245 tpls.master.disableformats = true;
46249 tpls.header = new Roo.Template(
46250 '<table border="0" cellspacing="0" cellpadding="0">',
46251 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
46254 tpls.header.disableformats = true;
46256 tpls.header.compile();
46259 tpls.hcell = new Roo.Template(
46260 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
46261 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
46264 tpls.hcell.disableFormats = true;
46266 tpls.hcell.compile();
46269 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
46270 tpls.hsplit.disableFormats = true;
46272 tpls.hsplit.compile();
46275 tpls.body = new Roo.Template(
46276 '<table border="0" cellspacing="0" cellpadding="0">',
46277 "<tbody>{rows}</tbody>",
46280 tpls.body.disableFormats = true;
46282 tpls.body.compile();
46285 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
46286 tpls.row.disableFormats = true;
46288 tpls.row.compile();
46291 tpls.cell = new Roo.Template(
46292 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
46293 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
46296 tpls.cell.disableFormats = true;
46298 tpls.cell.compile();
46300 this.templates = tpls;
46303 // remap these for backwards compat
46304 onColWidthChange : function(){
46305 this.updateColumns.apply(this, arguments);
46307 onHeaderChange : function(){
46308 this.updateHeaders.apply(this, arguments);
46310 onHiddenChange : function(){
46311 this.handleHiddenChange.apply(this, arguments);
46313 onColumnMove : function(){
46314 this.handleColumnMove.apply(this, arguments);
46316 onColumnLock : function(){
46317 this.handleLockChange.apply(this, arguments);
46320 onDataChange : function(){
46322 this.updateHeaderSortState();
46325 onClear : function(){
46329 onUpdate : function(ds, record){
46330 this.refreshRow(record);
46333 refreshRow : function(record){
46334 var ds = this.ds, index;
46335 if(typeof record == 'number'){
46337 record = ds.getAt(index);
46339 index = ds.indexOf(record);
46341 this.insertRows(ds, index, index, true);
46342 this.onRemove(ds, record, index+1, true);
46343 this.syncRowHeights(index, index);
46345 this.fireEvent("rowupdated", this, index, record);
46348 onAdd : function(ds, records, index){
46349 this.insertRows(ds, index, index + (records.length-1));
46352 onRemove : function(ds, record, index, isUpdate){
46353 if(isUpdate !== true){
46354 this.fireEvent("beforerowremoved", this, index, record);
46356 var bt = this.getBodyTable(), lt = this.getLockedTable();
46357 if(bt.rows[index]){
46358 bt.firstChild.removeChild(bt.rows[index]);
46360 if(lt.rows[index]){
46361 lt.firstChild.removeChild(lt.rows[index]);
46363 if(isUpdate !== true){
46364 this.stripeRows(index);
46365 this.syncRowHeights(index, index);
46367 this.fireEvent("rowremoved", this, index, record);
46371 onLoad : function(){
46372 this.scrollToTop();
46376 * Scrolls the grid to the top
46378 scrollToTop : function(){
46380 this.scroller.dom.scrollTop = 0;
46386 * Gets a panel in the header of the grid that can be used for toolbars etc.
46387 * After modifying the contents of this panel a call to grid.autoSize() may be
46388 * required to register any changes in size.
46389 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
46390 * @return Roo.Element
46392 getHeaderPanel : function(doShow){
46394 this.headerPanel.show();
46396 return this.headerPanel;
46400 * Gets a panel in the footer of the grid that can be used for toolbars etc.
46401 * After modifying the contents of this panel a call to grid.autoSize() may be
46402 * required to register any changes in size.
46403 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
46404 * @return Roo.Element
46406 getFooterPanel : function(doShow){
46408 this.footerPanel.show();
46410 return this.footerPanel;
46413 initElements : function(){
46414 var E = Roo.Element;
46415 var el = this.grid.getGridEl().dom.firstChild;
46416 var cs = el.childNodes;
46418 this.el = new E(el);
46419 this.headerPanel = new E(el.firstChild);
46420 this.headerPanel.enableDisplayMode("block");
46422 this.scroller = new E(cs[1]);
46423 this.scrollSizer = new E(this.scroller.dom.firstChild);
46425 this.lockedWrap = new E(cs[2]);
46426 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
46427 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
46429 this.mainWrap = new E(cs[3]);
46430 this.mainHd = new E(this.mainWrap.dom.firstChild);
46431 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
46433 this.footerPanel = new E(cs[4]);
46434 this.footerPanel.enableDisplayMode("block");
46436 this.focusEl = new E(cs[5]);
46437 this.focusEl.swallowEvent("click", true);
46438 this.resizeProxy = new E(cs[6]);
46440 this.headerSelector = String.format(
46441 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
46442 this.lockedHd.id, this.mainHd.id
46445 this.splitterSelector = String.format(
46446 '#{0} div.x-grid-split, #{1} div.x-grid-split',
46447 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
46450 idToCssName : function(s)
46452 return s.replace(/[^a-z0-9]+/ig, '-');
46455 getHeaderCell : function(index){
46456 return Roo.DomQuery.select(this.headerSelector)[index];
46459 getHeaderCellMeasure : function(index){
46460 return this.getHeaderCell(index).firstChild;
46463 getHeaderCellText : function(index){
46464 return this.getHeaderCell(index).firstChild.firstChild;
46467 getLockedTable : function(){
46468 return this.lockedBody.dom.firstChild;
46471 getBodyTable : function(){
46472 return this.mainBody.dom.firstChild;
46475 getLockedRow : function(index){
46476 return this.getLockedTable().rows[index];
46479 getRow : function(index){
46480 return this.getBodyTable().rows[index];
46483 getRowComposite : function(index){
46485 this.rowEl = new Roo.CompositeElementLite();
46487 var els = [], lrow, mrow;
46488 if(lrow = this.getLockedRow(index)){
46491 if(mrow = this.getRow(index)){
46494 this.rowEl.elements = els;
46498 getCell : function(rowIndex, colIndex){
46499 var locked = this.cm.getLockedCount();
46501 if(colIndex < locked){
46502 source = this.lockedBody.dom.firstChild;
46504 source = this.mainBody.dom.firstChild;
46505 colIndex -= locked;
46507 return source.rows[rowIndex].childNodes[colIndex];
46510 getCellText : function(rowIndex, colIndex){
46511 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
46514 getCellBox : function(cell){
46515 var b = this.fly(cell).getBox();
46516 if(Roo.isOpera){ // opera fails to report the Y
46517 b.y = cell.offsetTop + this.mainBody.getY();
46522 getCellIndex : function(cell){
46523 var id = String(cell.className).match(this.cellRE);
46525 return parseInt(id[1], 10);
46530 findHeaderIndex : function(n){
46531 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46532 return r ? this.getCellIndex(r) : false;
46535 findHeaderCell : function(n){
46536 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46537 return r ? r : false;
46540 findRowIndex : function(n){
46544 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
46545 return r ? r.rowIndex : false;
46548 findCellIndex : function(node){
46549 var stop = this.el.dom;
46550 while(node && node != stop){
46551 if(this.findRE.test(node.className)){
46552 return this.getCellIndex(node);
46554 node = node.parentNode;
46559 getColumnId : function(index){
46560 return this.cm.getColumnId(index);
46563 getSplitters : function(){
46564 if(this.splitterSelector){
46565 return Roo.DomQuery.select(this.splitterSelector);
46571 getSplitter : function(index){
46572 return this.getSplitters()[index];
46575 onRowOver : function(e, t){
46577 if((row = this.findRowIndex(t)) !== false){
46578 this.getRowComposite(row).addClass("x-grid-row-over");
46582 onRowOut : function(e, t){
46584 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
46585 this.getRowComposite(row).removeClass("x-grid-row-over");
46589 renderHeaders : function(){
46591 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
46592 var cb = [], lb = [], sb = [], lsb = [], p = {};
46593 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46594 p.cellId = "x-grid-hd-0-" + i;
46595 p.splitId = "x-grid-csplit-0-" + i;
46596 p.id = cm.getColumnId(i);
46597 p.title = cm.getColumnTooltip(i) || "";
46598 p.value = cm.getColumnHeader(i) || "";
46599 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
46600 if(!cm.isLocked(i)){
46601 cb[cb.length] = ct.apply(p);
46602 sb[sb.length] = st.apply(p);
46604 lb[lb.length] = ct.apply(p);
46605 lsb[lsb.length] = st.apply(p);
46608 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
46609 ht.apply({cells: cb.join(""), splits:sb.join("")})];
46612 updateHeaders : function(){
46613 var html = this.renderHeaders();
46614 this.lockedHd.update(html[0]);
46615 this.mainHd.update(html[1]);
46619 * Focuses the specified row.
46620 * @param {Number} row The row index
46622 focusRow : function(row){
46623 var x = this.scroller.dom.scrollLeft;
46624 this.focusCell(row, 0, false);
46625 this.scroller.dom.scrollLeft = x;
46629 * Focuses the specified cell.
46630 * @param {Number} row The row index
46631 * @param {Number} col The column index
46632 * @param {Boolean} hscroll false to disable horizontal scrolling
46634 focusCell : function(row, col, hscroll){
46635 var el = this.ensureVisible(row, col, hscroll);
46636 this.focusEl.alignTo(el, "tl-tl");
46638 this.focusEl.focus();
46640 this.focusEl.focus.defer(1, this.focusEl);
46645 * Scrolls the specified cell into view
46646 * @param {Number} row The row index
46647 * @param {Number} col The column index
46648 * @param {Boolean} hscroll false to disable horizontal scrolling
46650 ensureVisible : function(row, col, hscroll){
46651 if(typeof row != "number"){
46652 row = row.rowIndex;
46654 if(row < 0 && row >= this.ds.getCount()){
46657 col = (col !== undefined ? col : 0);
46658 var cm = this.grid.colModel;
46659 while(cm.isHidden(col)){
46663 var el = this.getCell(row, col);
46667 var c = this.scroller.dom;
46669 var ctop = parseInt(el.offsetTop, 10);
46670 var cleft = parseInt(el.offsetLeft, 10);
46671 var cbot = ctop + el.offsetHeight;
46672 var cright = cleft + el.offsetWidth;
46674 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
46675 var stop = parseInt(c.scrollTop, 10);
46676 var sleft = parseInt(c.scrollLeft, 10);
46677 var sbot = stop + ch;
46678 var sright = sleft + c.clientWidth;
46681 c.scrollTop = ctop;
46682 }else if(cbot > sbot){
46683 c.scrollTop = cbot-ch;
46686 if(hscroll !== false){
46688 c.scrollLeft = cleft;
46689 }else if(cright > sright){
46690 c.scrollLeft = cright-c.clientWidth;
46696 updateColumns : function(){
46697 this.grid.stopEditing();
46698 var cm = this.grid.colModel, colIds = this.getColumnIds();
46699 //var totalWidth = cm.getTotalWidth();
46701 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46702 //if(cm.isHidden(i)) continue;
46703 var w = cm.getColumnWidth(i);
46704 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46705 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46707 this.updateSplitters();
46710 generateRules : function(cm){
46711 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
46712 Roo.util.CSS.removeStyleSheet(rulesId);
46713 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46714 var cid = cm.getColumnId(i);
46716 if(cm.config[i].align){
46717 align = 'text-align:'+cm.config[i].align+';';
46720 if(cm.isHidden(i)){
46721 hidden = 'display:none;';
46723 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
46725 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
46726 this.hdSelector, cid, " {\n", align, width, "}\n",
46727 this.tdSelector, cid, " {\n",hidden,"\n}\n",
46728 this.splitSelector, cid, " {\n", hidden , "\n}\n");
46730 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46733 updateSplitters : function(){
46734 var cm = this.cm, s = this.getSplitters();
46735 if(s){ // splitters not created yet
46736 var pos = 0, locked = true;
46737 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46738 if(cm.isHidden(i)) continue;
46739 var w = cm.getColumnWidth(i);
46740 if(!cm.isLocked(i) && locked){
46745 s[i].style.left = (pos-this.splitOffset) + "px";
46750 handleHiddenChange : function(colModel, colIndex, hidden){
46752 this.hideColumn(colIndex);
46754 this.unhideColumn(colIndex);
46758 hideColumn : function(colIndex){
46759 var cid = this.getColumnId(colIndex);
46760 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
46761 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
46763 this.updateHeaders();
46765 this.updateSplitters();
46769 unhideColumn : function(colIndex){
46770 var cid = this.getColumnId(colIndex);
46771 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
46772 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
46775 this.updateHeaders();
46777 this.updateSplitters();
46781 insertRows : function(dm, firstRow, lastRow, isUpdate){
46782 if(firstRow == 0 && lastRow == dm.getCount()-1){
46786 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
46788 var s = this.getScrollState();
46789 var markup = this.renderRows(firstRow, lastRow);
46790 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
46791 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
46792 this.restoreScroll(s);
46794 this.fireEvent("rowsinserted", this, firstRow, lastRow);
46795 this.syncRowHeights(firstRow, lastRow);
46796 this.stripeRows(firstRow);
46802 bufferRows : function(markup, target, index){
46803 var before = null, trows = target.rows, tbody = target.tBodies[0];
46804 if(index < trows.length){
46805 before = trows[index];
46807 var b = document.createElement("div");
46808 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
46809 var rows = b.firstChild.rows;
46810 for(var i = 0, len = rows.length; i < len; i++){
46812 tbody.insertBefore(rows[0], before);
46814 tbody.appendChild(rows[0]);
46821 deleteRows : function(dm, firstRow, lastRow){
46822 if(dm.getRowCount()<1){
46823 this.fireEvent("beforerefresh", this);
46824 this.mainBody.update("");
46825 this.lockedBody.update("");
46826 this.fireEvent("refresh", this);
46828 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
46829 var bt = this.getBodyTable();
46830 var tbody = bt.firstChild;
46831 var rows = bt.rows;
46832 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
46833 tbody.removeChild(rows[firstRow]);
46835 this.stripeRows(firstRow);
46836 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
46840 updateRows : function(dataSource, firstRow, lastRow){
46841 var s = this.getScrollState();
46843 this.restoreScroll(s);
46846 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
46850 this.updateHeaderSortState();
46853 getScrollState : function(){
46854 var sb = this.scroller.dom;
46855 return {left: sb.scrollLeft, top: sb.scrollTop};
46858 stripeRows : function(startRow){
46859 if(!this.grid.stripeRows || this.ds.getCount() < 1){
46862 startRow = startRow || 0;
46863 var rows = this.getBodyTable().rows;
46864 var lrows = this.getLockedTable().rows;
46865 var cls = ' x-grid-row-alt ';
46866 for(var i = startRow, len = rows.length; i < len; i++){
46867 var row = rows[i], lrow = lrows[i];
46868 var isAlt = ((i+1) % 2 == 0);
46869 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
46870 if(isAlt == hasAlt){
46874 row.className += " x-grid-row-alt";
46876 row.className = row.className.replace("x-grid-row-alt", "");
46879 lrow.className = row.className;
46884 restoreScroll : function(state){
46885 var sb = this.scroller.dom;
46886 sb.scrollLeft = state.left;
46887 sb.scrollTop = state.top;
46891 syncScroll : function(){
46892 var sb = this.scroller.dom;
46893 var sh = this.mainHd.dom;
46894 var bs = this.mainBody.dom;
46895 var lv = this.lockedBody.dom;
46896 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
46897 lv.scrollTop = bs.scrollTop = sb.scrollTop;
46900 handleScroll : function(e){
46902 var sb = this.scroller.dom;
46903 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
46907 handleWheel : function(e){
46908 var d = e.getWheelDelta();
46909 this.scroller.dom.scrollTop -= d*22;
46910 // set this here to prevent jumpy scrolling on large tables
46911 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
46915 renderRows : function(startRow, endRow){
46916 // pull in all the crap needed to render rows
46917 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
46918 var colCount = cm.getColumnCount();
46920 if(ds.getCount() < 1){
46924 // build a map for all the columns
46926 for(var i = 0; i < colCount; i++){
46927 var name = cm.getDataIndex(i);
46929 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
46930 renderer : cm.getRenderer(i),
46931 id : cm.getColumnId(i),
46932 locked : cm.isLocked(i)
46936 startRow = startRow || 0;
46937 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
46939 // records to render
46940 var rs = ds.getRange(startRow, endRow);
46942 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
46945 // As much as I hate to duplicate code, this was branched because FireFox really hates
46946 // [].join("") on strings. The performance difference was substantial enough to
46947 // branch this function
46948 doRender : Roo.isGecko ?
46949 function(cs, rs, ds, startRow, colCount, stripe){
46950 var ts = this.templates, ct = ts.cell, rt = ts.row;
46952 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
46953 for(var j = 0, len = rs.length; j < len; j++){
46954 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
46955 for(var i = 0; i < colCount; i++){
46957 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
46959 p.css = p.attr = "";
46960 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
46961 if(p.value == undefined || p.value === "") p.value = " ";
46962 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
46963 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
46965 var markup = ct.apply(p);
46973 if(stripe && ((rowIndex+1) % 2 == 0)){
46974 alt[0] = "x-grid-row-alt";
46977 alt[1] = " x-grid-dirty-row";
46980 if(this.getRowClass){
46981 alt[2] = this.getRowClass(r, rowIndex);
46983 rp.alt = alt.join(" ");
46984 lbuf+= rt.apply(rp);
46986 buf+= rt.apply(rp);
46988 return [lbuf, buf];
46990 function(cs, rs, ds, startRow, colCount, stripe){
46991 var ts = this.templates, ct = ts.cell, rt = ts.row;
46993 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
46994 for(var j = 0, len = rs.length; j < len; j++){
46995 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
46996 for(var i = 0; i < colCount; i++){
46998 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47000 p.css = p.attr = "";
47001 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47002 if(p.value == undefined || p.value === "") p.value = " ";
47003 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47004 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47006 var markup = ct.apply(p);
47008 cb[cb.length] = markup;
47010 lcb[lcb.length] = markup;
47014 if(stripe && ((rowIndex+1) % 2 == 0)){
47015 alt[0] = "x-grid-row-alt";
47018 alt[1] = " x-grid-dirty-row";
47021 if(this.getRowClass){
47022 alt[2] = this.getRowClass(r, rowIndex);
47024 rp.alt = alt.join(" ");
47025 rp.cells = lcb.join("");
47026 lbuf[lbuf.length] = rt.apply(rp);
47027 rp.cells = cb.join("");
47028 buf[buf.length] = rt.apply(rp);
47030 return [lbuf.join(""), buf.join("")];
47033 renderBody : function(){
47034 var markup = this.renderRows();
47035 var bt = this.templates.body;
47036 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
47040 * Refreshes the grid
47041 * @param {Boolean} headersToo
47043 refresh : function(headersToo){
47044 this.fireEvent("beforerefresh", this);
47045 this.grid.stopEditing();
47046 var result = this.renderBody();
47047 this.lockedBody.update(result[0]);
47048 this.mainBody.update(result[1]);
47049 if(headersToo === true){
47050 this.updateHeaders();
47051 this.updateColumns();
47052 this.updateSplitters();
47053 this.updateHeaderSortState();
47055 this.syncRowHeights();
47057 this.fireEvent("refresh", this);
47060 handleColumnMove : function(cm, oldIndex, newIndex){
47061 this.indexMap = null;
47062 var s = this.getScrollState();
47063 this.refresh(true);
47064 this.restoreScroll(s);
47065 this.afterMove(newIndex);
47068 afterMove : function(colIndex){
47069 if(this.enableMoveAnim && Roo.enableFx){
47070 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
47074 updateCell : function(dm, rowIndex, dataIndex){
47075 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
47076 if(typeof colIndex == "undefined"){ // not present in grid
47079 var cm = this.grid.colModel;
47080 var cell = this.getCell(rowIndex, colIndex);
47081 var cellText = this.getCellText(rowIndex, colIndex);
47084 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
47085 id : cm.getColumnId(colIndex),
47086 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
47088 var renderer = cm.getRenderer(colIndex);
47089 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
47090 if(typeof val == "undefined" || val === "") val = " ";
47091 cellText.innerHTML = val;
47092 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
47093 this.syncRowHeights(rowIndex, rowIndex);
47096 calcColumnWidth : function(colIndex, maxRowsToMeasure){
47098 if(this.grid.autoSizeHeaders){
47099 var h = this.getHeaderCellMeasure(colIndex);
47100 maxWidth = Math.max(maxWidth, h.scrollWidth);
47103 if(this.cm.isLocked(colIndex)){
47104 tb = this.getLockedTable();
47107 tb = this.getBodyTable();
47108 index = colIndex - this.cm.getLockedCount();
47111 var rows = tb.rows;
47112 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
47113 for(var i = 0; i < stopIndex; i++){
47114 var cell = rows[i].childNodes[index].firstChild;
47115 maxWidth = Math.max(maxWidth, cell.scrollWidth);
47118 return maxWidth + /*margin for error in IE*/ 5;
47121 * Autofit a column to its content.
47122 * @param {Number} colIndex
47123 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
47125 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
47126 if(this.cm.isHidden(colIndex)){
47127 return; // can't calc a hidden column
47130 var cid = this.cm.getColumnId(colIndex);
47131 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
47132 if(this.grid.autoSizeHeaders){
47133 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
47136 var newWidth = this.calcColumnWidth(colIndex);
47137 this.cm.setColumnWidth(colIndex,
47138 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
47139 if(!suppressEvent){
47140 this.grid.fireEvent("columnresize", colIndex, newWidth);
47145 * Autofits all columns to their content and then expands to fit any extra space in the grid
47147 autoSizeColumns : function(){
47148 var cm = this.grid.colModel;
47149 var colCount = cm.getColumnCount();
47150 for(var i = 0; i < colCount; i++){
47151 this.autoSizeColumn(i, true, true);
47153 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
47156 this.updateColumns();
47162 * Autofits all columns to the grid's width proportionate with their current size
47163 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
47165 fitColumns : function(reserveScrollSpace){
47166 var cm = this.grid.colModel;
47167 var colCount = cm.getColumnCount();
47171 for (i = 0; i < colCount; i++){
47172 if(!cm.isHidden(i) && !cm.isFixed(i)){
47173 w = cm.getColumnWidth(i);
47179 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
47180 if(reserveScrollSpace){
47183 var frac = (avail - cm.getTotalWidth())/width;
47184 while (cols.length){
47187 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
47189 this.updateColumns();
47193 onRowSelect : function(rowIndex){
47194 var row = this.getRowComposite(rowIndex);
47195 row.addClass("x-grid-row-selected");
47198 onRowDeselect : function(rowIndex){
47199 var row = this.getRowComposite(rowIndex);
47200 row.removeClass("x-grid-row-selected");
47203 onCellSelect : function(row, col){
47204 var cell = this.getCell(row, col);
47206 Roo.fly(cell).addClass("x-grid-cell-selected");
47210 onCellDeselect : function(row, col){
47211 var cell = this.getCell(row, col);
47213 Roo.fly(cell).removeClass("x-grid-cell-selected");
47217 updateHeaderSortState : function(){
47218 var state = this.ds.getSortState();
47222 this.sortState = state;
47223 var sortColumn = this.cm.findColumnIndex(state.field);
47224 if(sortColumn != -1){
47225 var sortDir = state.direction;
47226 var sc = this.sortClasses;
47227 var hds = this.el.select(this.headerSelector).removeClass(sc);
47228 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
47232 handleHeaderClick : function(g, index){
47233 if(this.headersDisabled){
47236 var dm = g.dataSource, cm = g.colModel;
47237 if(!cm.isSortable(index)){
47241 dm.sort(cm.getDataIndex(index));
47245 destroy : function(){
47247 this.colMenu.removeAll();
47248 Roo.menu.MenuMgr.unregister(this.colMenu);
47249 this.colMenu.getEl().remove();
47250 delete this.colMenu;
47253 this.hmenu.removeAll();
47254 Roo.menu.MenuMgr.unregister(this.hmenu);
47255 this.hmenu.getEl().remove();
47258 if(this.grid.enableColumnMove){
47259 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47261 for(var dd in dds){
47262 if(!dds[dd].config.isTarget && dds[dd].dragElId){
47263 var elid = dds[dd].dragElId;
47265 Roo.get(elid).remove();
47266 } else if(dds[dd].config.isTarget){
47267 dds[dd].proxyTop.remove();
47268 dds[dd].proxyBottom.remove();
47271 if(Roo.dd.DDM.locationCache[dd]){
47272 delete Roo.dd.DDM.locationCache[dd];
47275 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47278 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
47279 this.bind(null, null);
47280 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
47283 handleLockChange : function(){
47284 this.refresh(true);
47287 onDenyColumnLock : function(){
47291 onDenyColumnHide : function(){
47295 handleHdMenuClick : function(item){
47296 var index = this.hdCtxIndex;
47297 var cm = this.cm, ds = this.ds;
47300 ds.sort(cm.getDataIndex(index), "ASC");
47303 ds.sort(cm.getDataIndex(index), "DESC");
47306 var lc = cm.getLockedCount();
47307 if(cm.getColumnCount(true) <= lc+1){
47308 this.onDenyColumnLock();
47312 cm.setLocked(index, true, true);
47313 cm.moveColumn(index, lc);
47314 this.grid.fireEvent("columnmove", index, lc);
47316 cm.setLocked(index, true);
47320 var lc = cm.getLockedCount();
47321 if((lc-1) != index){
47322 cm.setLocked(index, false, true);
47323 cm.moveColumn(index, lc-1);
47324 this.grid.fireEvent("columnmove", index, lc-1);
47326 cm.setLocked(index, false);
47330 index = cm.getIndexById(item.id.substr(4));
47332 if(item.checked && cm.getColumnCount(true) <= 1){
47333 this.onDenyColumnHide();
47336 cm.setHidden(index, item.checked);
47342 beforeColMenuShow : function(){
47343 var cm = this.cm, colCount = cm.getColumnCount();
47344 this.colMenu.removeAll();
47345 for(var i = 0; i < colCount; i++){
47346 this.colMenu.add(new Roo.menu.CheckItem({
47347 id: "col-"+cm.getColumnId(i),
47348 text: cm.getColumnHeader(i),
47349 checked: !cm.isHidden(i),
47355 handleHdCtx : function(g, index, e){
47357 var hd = this.getHeaderCell(index);
47358 this.hdCtxIndex = index;
47359 var ms = this.hmenu.items, cm = this.cm;
47360 ms.get("asc").setDisabled(!cm.isSortable(index));
47361 ms.get("desc").setDisabled(!cm.isSortable(index));
47362 if(this.grid.enableColLock !== false){
47363 ms.get("lock").setDisabled(cm.isLocked(index));
47364 ms.get("unlock").setDisabled(!cm.isLocked(index));
47366 this.hmenu.show(hd, "tl-bl");
47369 handleHdOver : function(e){
47370 var hd = this.findHeaderCell(e.getTarget());
47371 if(hd && !this.headersDisabled){
47372 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
47373 this.fly(hd).addClass("x-grid-hd-over");
47378 handleHdOut : function(e){
47379 var hd = this.findHeaderCell(e.getTarget());
47381 this.fly(hd).removeClass("x-grid-hd-over");
47385 handleSplitDblClick : function(e, t){
47386 var i = this.getCellIndex(t);
47387 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
47388 this.autoSizeColumn(i, true);
47393 render : function(){
47396 var colCount = cm.getColumnCount();
47398 if(this.grid.monitorWindowResize === true){
47399 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47401 var header = this.renderHeaders();
47402 var body = this.templates.body.apply({rows:""});
47403 var html = this.templates.master.apply({
47406 lockedHeader: header[0],
47410 //this.updateColumns();
47412 this.grid.getGridEl().dom.innerHTML = html;
47414 this.initElements();
47416 this.scroller.on("scroll", this.handleScroll, this);
47417 this.lockedBody.on("mousewheel", this.handleWheel, this);
47418 this.mainBody.on("mousewheel", this.handleWheel, this);
47420 this.mainHd.on("mouseover", this.handleHdOver, this);
47421 this.mainHd.on("mouseout", this.handleHdOut, this);
47422 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
47423 {delegate: "."+this.splitClass});
47425 this.lockedHd.on("mouseover", this.handleHdOver, this);
47426 this.lockedHd.on("mouseout", this.handleHdOut, this);
47427 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
47428 {delegate: "."+this.splitClass});
47430 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
47431 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47434 this.updateSplitters();
47436 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
47437 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47438 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47441 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
47442 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
47444 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
47445 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
47447 if(this.grid.enableColLock !== false){
47448 this.hmenu.add('-',
47449 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
47450 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
47453 if(this.grid.enableColumnHide !== false){
47455 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
47456 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
47457 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
47459 this.hmenu.add('-',
47460 {id:"columns", text: this.columnsText, menu: this.colMenu}
47463 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
47465 this.grid.on("headercontextmenu", this.handleHdCtx, this);
47468 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
47469 this.dd = new Roo.grid.GridDragZone(this.grid, {
47470 ddGroup : this.grid.ddGroup || 'GridDD'
47475 for(var i = 0; i < colCount; i++){
47476 if(cm.isHidden(i)){
47477 this.hideColumn(i);
47479 if(cm.config[i].align){
47480 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
47481 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
47485 this.updateHeaderSortState();
47487 this.beforeInitialResize();
47490 // two part rendering gives faster view to the user
47491 this.renderPhase2.defer(1, this);
47494 renderPhase2 : function(){
47495 // render the rows now
47497 if(this.grid.autoSizeColumns){
47498 this.autoSizeColumns();
47502 beforeInitialResize : function(){
47506 onColumnSplitterMoved : function(i, w){
47507 this.userResized = true;
47508 var cm = this.grid.colModel;
47509 cm.setColumnWidth(i, w, true);
47510 var cid = cm.getColumnId(i);
47511 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47512 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47513 this.updateSplitters();
47515 this.grid.fireEvent("columnresize", i, w);
47518 syncRowHeights : function(startIndex, endIndex){
47519 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
47520 startIndex = startIndex || 0;
47521 var mrows = this.getBodyTable().rows;
47522 var lrows = this.getLockedTable().rows;
47523 var len = mrows.length-1;
47524 endIndex = Math.min(endIndex || len, len);
47525 for(var i = startIndex; i <= endIndex; i++){
47526 var m = mrows[i], l = lrows[i];
47527 var h = Math.max(m.offsetHeight, l.offsetHeight);
47528 m.style.height = l.style.height = h + "px";
47533 layout : function(initialRender, is2ndPass){
47535 var auto = g.autoHeight;
47536 var scrollOffset = 16;
47537 var c = g.getGridEl(), cm = this.cm,
47538 expandCol = g.autoExpandColumn,
47540 //c.beginMeasure();
47542 if(!c.dom.offsetWidth){ // display:none?
47544 this.lockedWrap.show();
47545 this.mainWrap.show();
47550 var hasLock = this.cm.isLocked(0);
47552 var tbh = this.headerPanel.getHeight();
47553 var bbh = this.footerPanel.getHeight();
47556 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
47557 var newHeight = ch + c.getBorderWidth("tb");
47559 newHeight = Math.min(g.maxHeight, newHeight);
47561 c.setHeight(newHeight);
47565 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
47568 var s = this.scroller;
47570 var csize = c.getSize(true);
47572 this.el.setSize(csize.width, csize.height);
47574 this.headerPanel.setWidth(csize.width);
47575 this.footerPanel.setWidth(csize.width);
47577 var hdHeight = this.mainHd.getHeight();
47578 var vw = csize.width;
47579 var vh = csize.height - (tbh + bbh);
47583 var bt = this.getBodyTable();
47584 var ltWidth = hasLock ?
47585 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
47587 var scrollHeight = bt.offsetHeight;
47588 var scrollWidth = ltWidth + bt.offsetWidth;
47589 var vscroll = false, hscroll = false;
47591 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
47593 var lw = this.lockedWrap, mw = this.mainWrap;
47594 var lb = this.lockedBody, mb = this.mainBody;
47596 setTimeout(function(){
47597 var t = s.dom.offsetTop;
47598 var w = s.dom.clientWidth,
47599 h = s.dom.clientHeight;
47602 lw.setSize(ltWidth, h);
47604 mw.setLeftTop(ltWidth, t);
47605 mw.setSize(w-ltWidth, h);
47607 lb.setHeight(h-hdHeight);
47608 mb.setHeight(h-hdHeight);
47610 if(is2ndPass !== true && !gv.userResized && expandCol){
47611 // high speed resize without full column calculation
47613 var ci = cm.getIndexById(expandCol);
47615 ci = cm.findColumnIndex(expandCol);
47617 ci = Math.max(0, ci); // make sure it's got at least the first col.
47618 var expandId = cm.getColumnId(ci);
47619 var tw = cm.getTotalWidth(false);
47620 var currentWidth = cm.getColumnWidth(ci);
47621 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
47622 if(currentWidth != cw){
47623 cm.setColumnWidth(ci, cw, true);
47624 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47625 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47626 gv.updateSplitters();
47627 gv.layout(false, true);
47639 onWindowResize : function(){
47640 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
47646 appendFooter : function(parentEl){
47650 sortAscText : "Sort Ascending",
47651 sortDescText : "Sort Descending",
47652 lockText : "Lock Column",
47653 unlockText : "Unlock Column",
47654 columnsText : "Columns"
47658 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
47659 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
47660 this.proxy.el.addClass('x-grid3-col-dd');
47663 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
47664 handleMouseDown : function(e){
47668 callHandleMouseDown : function(e){
47669 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
47674 * Ext JS Library 1.1.1
47675 * Copyright(c) 2006-2007, Ext JS, LLC.
47677 * Originally Released Under LGPL - original licence link has changed is not relivant.
47680 * <script type="text/javascript">
47684 // This is a support class used internally by the Grid components
47685 Roo.grid.SplitDragZone = function(grid, hd, hd2){
47687 this.view = grid.getView();
47688 this.proxy = this.view.resizeProxy;
47689 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
47690 "gridSplitters" + this.grid.getGridEl().id, {
47691 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
47693 this.setHandleElId(Roo.id(hd));
47694 this.setOuterHandleElId(Roo.id(hd2));
47695 this.scroll = false;
47697 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
47698 fly: Roo.Element.fly,
47700 b4StartDrag : function(x, y){
47701 this.view.headersDisabled = true;
47702 this.proxy.setHeight(this.view.mainWrap.getHeight());
47703 var w = this.cm.getColumnWidth(this.cellIndex);
47704 var minw = Math.max(w-this.grid.minColumnWidth, 0);
47705 this.resetConstraints();
47706 this.setXConstraint(minw, 1000);
47707 this.setYConstraint(0, 0);
47708 this.minX = x - minw;
47709 this.maxX = x + 1000;
47711 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
47715 handleMouseDown : function(e){
47716 ev = Roo.EventObject.setEvent(e);
47717 var t = this.fly(ev.getTarget());
47718 if(t.hasClass("x-grid-split")){
47719 this.cellIndex = this.view.getCellIndex(t.dom);
47720 this.split = t.dom;
47721 this.cm = this.grid.colModel;
47722 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
47723 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
47728 endDrag : function(e){
47729 this.view.headersDisabled = false;
47730 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
47731 var diff = endX - this.startPos;
47732 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
47735 autoOffset : function(){
47736 this.setDelta(0,0);
47740 * Ext JS Library 1.1.1
47741 * Copyright(c) 2006-2007, Ext JS, LLC.
47743 * Originally Released Under LGPL - original licence link has changed is not relivant.
47746 * <script type="text/javascript">
47750 // This is a support class used internally by the Grid components
47751 Roo.grid.GridDragZone = function(grid, config){
47752 this.view = grid.getView();
47753 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
47754 if(this.view.lockedBody){
47755 this.setHandleElId(Roo.id(this.view.mainBody.dom));
47756 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
47758 this.scroll = false;
47760 this.ddel = document.createElement('div');
47761 this.ddel.className = 'x-grid-dd-wrap';
47764 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
47765 ddGroup : "GridDD",
47767 getDragData : function(e){
47768 var t = Roo.lib.Event.getTarget(e);
47769 var rowIndex = this.view.findRowIndex(t);
47770 if(rowIndex !== false){
47771 var sm = this.grid.selModel;
47772 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
47773 // sm.mouseDown(e, t);
47775 if (e.hasModifier()){
47776 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
47778 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
47783 onInitDrag : function(e){
47784 var data = this.dragData;
47785 this.ddel.innerHTML = this.grid.getDragDropText();
47786 this.proxy.update(this.ddel);
47787 // fire start drag?
47790 afterRepair : function(){
47791 this.dragging = false;
47794 getRepairXY : function(e, data){
47798 onEndDrag : function(data, e){
47802 onValidDrop : function(dd, e, id){
47807 beforeInvalidDrop : function(e, id){
47812 * Ext JS Library 1.1.1
47813 * Copyright(c) 2006-2007, Ext JS, LLC.
47815 * Originally Released Under LGPL - original licence link has changed is not relivant.
47818 * <script type="text/javascript">
47823 * @class Roo.grid.ColumnModel
47824 * @extends Roo.util.Observable
47825 * This is the default implementation of a ColumnModel used by the Grid. It defines
47826 * the columns in the grid.
47829 var colModel = new Roo.grid.ColumnModel([
47830 {header: "Ticker", width: 60, sortable: true, locked: true},
47831 {header: "Company Name", width: 150, sortable: true},
47832 {header: "Market Cap.", width: 100, sortable: true},
47833 {header: "$ Sales", width: 100, sortable: true, renderer: money},
47834 {header: "Employees", width: 100, sortable: true, resizable: false}
47839 * The config options listed for this class are options which may appear in each
47840 * individual column definition.
47841 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
47843 * @param {Object} config An Array of column config objects. See this class's
47844 * config objects for details.
47846 Roo.grid.ColumnModel = function(config){
47848 * The config passed into the constructor
47850 this.config = config;
47853 // if no id, create one
47854 // if the column does not have a dataIndex mapping,
47855 // map it to the order it is in the config
47856 for(var i = 0, len = config.length; i < len; i++){
47858 if(typeof c.dataIndex == "undefined"){
47861 if(typeof c.renderer == "string"){
47862 c.renderer = Roo.util.Format[c.renderer];
47864 if(typeof c.id == "undefined"){
47867 if(c.editor && c.editor.xtype){
47868 c.editor = Roo.factory(c.editor, Roo.grid);
47870 if(c.editor && c.editor.isFormField){
47871 c.editor = new Roo.grid.GridEditor(c.editor);
47873 this.lookup[c.id] = c;
47877 * The width of columns which have no width specified (defaults to 100)
47880 this.defaultWidth = 100;
47883 * Default sortable of columns which have no sortable specified (defaults to false)
47886 this.defaultSortable = false;
47890 * @event widthchange
47891 * Fires when the width of a column changes.
47892 * @param {ColumnModel} this
47893 * @param {Number} columnIndex The column index
47894 * @param {Number} newWidth The new width
47896 "widthchange": true,
47898 * @event headerchange
47899 * Fires when the text of a header changes.
47900 * @param {ColumnModel} this
47901 * @param {Number} columnIndex The column index
47902 * @param {Number} newText The new header text
47904 "headerchange": true,
47906 * @event hiddenchange
47907 * Fires when a column is hidden or "unhidden".
47908 * @param {ColumnModel} this
47909 * @param {Number} columnIndex The column index
47910 * @param {Boolean} hidden true if hidden, false otherwise
47912 "hiddenchange": true,
47914 * @event columnmoved
47915 * Fires when a column is moved.
47916 * @param {ColumnModel} this
47917 * @param {Number} oldIndex
47918 * @param {Number} newIndex
47920 "columnmoved" : true,
47922 * @event columlockchange
47923 * Fires when a column's locked state is changed
47924 * @param {ColumnModel} this
47925 * @param {Number} colIndex
47926 * @param {Boolean} locked true if locked
47928 "columnlockchange" : true
47930 Roo.grid.ColumnModel.superclass.constructor.call(this);
47932 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
47934 * @cfg {String} header The header text to display in the Grid view.
47937 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
47938 * {@link Roo.data.Record} definition from which to draw the column's value. If not
47939 * specified, the column's index is used as an index into the Record's data Array.
47942 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
47943 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
47946 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
47947 * Defaults to the value of the {@link #defaultSortable} property.
47948 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
47951 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
47954 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
47957 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
47960 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
47963 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
47964 * given the cell's data value. See {@link #setRenderer}. If not specified, the
47965 * default renderer uses the raw data value.
47968 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
47971 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
47975 * Returns the id of the column at the specified index.
47976 * @param {Number} index The column index
47977 * @return {String} the id
47979 getColumnId : function(index){
47980 return this.config[index].id;
47984 * Returns the column for a specified id.
47985 * @param {String} id The column id
47986 * @return {Object} the column
47988 getColumnById : function(id){
47989 return this.lookup[id];
47993 * Returns the index for a specified column id.
47994 * @param {String} id The column id
47995 * @return {Number} the index, or -1 if not found
47997 getIndexById : function(id){
47998 for(var i = 0, len = this.config.length; i < len; i++){
47999 if(this.config[i].id == id){
48006 * Returns the index for a specified column dataIndex.
48007 * @param {String} dataIndex The column dataIndex
48008 * @return {Number} the index, or -1 if not found
48011 findColumnIndex : function(dataIndex){
48012 for(var i = 0, len = this.config.length; i < len; i++){
48013 if(this.config[i].dataIndex == dataIndex){
48021 moveColumn : function(oldIndex, newIndex){
48022 var c = this.config[oldIndex];
48023 this.config.splice(oldIndex, 1);
48024 this.config.splice(newIndex, 0, c);
48025 this.dataMap = null;
48026 this.fireEvent("columnmoved", this, oldIndex, newIndex);
48029 isLocked : function(colIndex){
48030 return this.config[colIndex].locked === true;
48033 setLocked : function(colIndex, value, suppressEvent){
48034 if(this.isLocked(colIndex) == value){
48037 this.config[colIndex].locked = value;
48038 if(!suppressEvent){
48039 this.fireEvent("columnlockchange", this, colIndex, value);
48043 getTotalLockedWidth : function(){
48044 var totalWidth = 0;
48045 for(var i = 0; i < this.config.length; i++){
48046 if(this.isLocked(i) && !this.isHidden(i)){
48047 this.totalWidth += this.getColumnWidth(i);
48053 getLockedCount : function(){
48054 for(var i = 0, len = this.config.length; i < len; i++){
48055 if(!this.isLocked(i)){
48062 * Returns the number of columns.
48065 getColumnCount : function(visibleOnly){
48066 if(visibleOnly === true){
48068 for(var i = 0, len = this.config.length; i < len; i++){
48069 if(!this.isHidden(i)){
48075 return this.config.length;
48079 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
48080 * @param {Function} fn
48081 * @param {Object} scope (optional)
48082 * @return {Array} result
48084 getColumnsBy : function(fn, scope){
48086 for(var i = 0, len = this.config.length; i < len; i++){
48087 var c = this.config[i];
48088 if(fn.call(scope||this, c, i) === true){
48096 * Returns true if the specified column is sortable.
48097 * @param {Number} col The column index
48098 * @return {Boolean}
48100 isSortable : function(col){
48101 if(typeof this.config[col].sortable == "undefined"){
48102 return this.defaultSortable;
48104 return this.config[col].sortable;
48108 * Returns the rendering (formatting) function defined for the column.
48109 * @param {Number} col The column index.
48110 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
48112 getRenderer : function(col){
48113 if(!this.config[col].renderer){
48114 return Roo.grid.ColumnModel.defaultRenderer;
48116 return this.config[col].renderer;
48120 * Sets the rendering (formatting) function for a column.
48121 * @param {Number} col The column index
48122 * @param {Function} fn The function to use to process the cell's raw data
48123 * to return HTML markup for the grid view. The render function is called with
48124 * the following parameters:<ul>
48125 * <li>Data value.</li>
48126 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
48127 * <li>css A CSS style string to apply to the table cell.</li>
48128 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
48129 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
48130 * <li>Row index</li>
48131 * <li>Column index</li>
48132 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
48134 setRenderer : function(col, fn){
48135 this.config[col].renderer = fn;
48139 * Returns the width for the specified column.
48140 * @param {Number} col The column index
48143 getColumnWidth : function(col){
48144 return this.config[col].width || this.defaultWidth;
48148 * Sets the width for a column.
48149 * @param {Number} col The column index
48150 * @param {Number} width The new width
48152 setColumnWidth : function(col, width, suppressEvent){
48153 this.config[col].width = width;
48154 this.totalWidth = null;
48155 if(!suppressEvent){
48156 this.fireEvent("widthchange", this, col, width);
48161 * Returns the total width of all columns.
48162 * @param {Boolean} includeHidden True to include hidden column widths
48165 getTotalWidth : function(includeHidden){
48166 if(!this.totalWidth){
48167 this.totalWidth = 0;
48168 for(var i = 0, len = this.config.length; i < len; i++){
48169 if(includeHidden || !this.isHidden(i)){
48170 this.totalWidth += this.getColumnWidth(i);
48174 return this.totalWidth;
48178 * Returns the header for the specified column.
48179 * @param {Number} col The column index
48182 getColumnHeader : function(col){
48183 return this.config[col].header;
48187 * Sets the header for a column.
48188 * @param {Number} col The column index
48189 * @param {String} header The new header
48191 setColumnHeader : function(col, header){
48192 this.config[col].header = header;
48193 this.fireEvent("headerchange", this, col, header);
48197 * Returns the tooltip for the specified column.
48198 * @param {Number} col The column index
48201 getColumnTooltip : function(col){
48202 return this.config[col].tooltip;
48205 * Sets the tooltip for a column.
48206 * @param {Number} col The column index
48207 * @param {String} tooltip The new tooltip
48209 setColumnTooltip : function(col, tooltip){
48210 this.config[col].tooltip = tooltip;
48214 * Returns the dataIndex for the specified column.
48215 * @param {Number} col The column index
48218 getDataIndex : function(col){
48219 return this.config[col].dataIndex;
48223 * Sets the dataIndex for a column.
48224 * @param {Number} col The column index
48225 * @param {Number} dataIndex The new dataIndex
48227 setDataIndex : function(col, dataIndex){
48228 this.config[col].dataIndex = dataIndex;
48234 * Returns true if the cell is editable.
48235 * @param {Number} colIndex The column index
48236 * @param {Number} rowIndex The row index
48237 * @return {Boolean}
48239 isCellEditable : function(colIndex, rowIndex){
48240 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
48244 * Returns the editor defined for the cell/column.
48245 * return false or null to disable editing.
48246 * @param {Number} colIndex The column index
48247 * @param {Number} rowIndex The row index
48250 getCellEditor : function(colIndex, rowIndex){
48251 return this.config[colIndex].editor;
48255 * Sets if a column is editable.
48256 * @param {Number} col The column index
48257 * @param {Boolean} editable True if the column is editable
48259 setEditable : function(col, editable){
48260 this.config[col].editable = editable;
48265 * Returns true if the column is hidden.
48266 * @param {Number} colIndex The column index
48267 * @return {Boolean}
48269 isHidden : function(colIndex){
48270 return this.config[colIndex].hidden;
48275 * Returns true if the column width cannot be changed
48277 isFixed : function(colIndex){
48278 return this.config[colIndex].fixed;
48282 * Returns true if the column can be resized
48283 * @return {Boolean}
48285 isResizable : function(colIndex){
48286 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
48289 * Sets if a column is hidden.
48290 * @param {Number} colIndex The column index
48291 * @param {Boolean} hidden True if the column is hidden
48293 setHidden : function(colIndex, hidden){
48294 this.config[colIndex].hidden = hidden;
48295 this.totalWidth = null;
48296 this.fireEvent("hiddenchange", this, colIndex, hidden);
48300 * Sets the editor for a column.
48301 * @param {Number} col The column index
48302 * @param {Object} editor The editor object
48304 setEditor : function(col, editor){
48305 this.config[col].editor = editor;
48309 Roo.grid.ColumnModel.defaultRenderer = function(value){
48310 if(typeof value == "string" && value.length < 1){
48316 // Alias for backwards compatibility
48317 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
48320 * Ext JS Library 1.1.1
48321 * Copyright(c) 2006-2007, Ext JS, LLC.
48323 * Originally Released Under LGPL - original licence link has changed is not relivant.
48326 * <script type="text/javascript">
48330 * @class Roo.grid.AbstractSelectionModel
48331 * @extends Roo.util.Observable
48332 * Abstract base class for grid SelectionModels. It provides the interface that should be
48333 * implemented by descendant classes. This class should not be directly instantiated.
48336 Roo.grid.AbstractSelectionModel = function(){
48337 this.locked = false;
48338 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
48341 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
48342 /** @ignore Called by the grid automatically. Do not call directly. */
48343 init : function(grid){
48349 * Locks the selections.
48352 this.locked = true;
48356 * Unlocks the selections.
48358 unlock : function(){
48359 this.locked = false;
48363 * Returns true if the selections are locked.
48364 * @return {Boolean}
48366 isLocked : function(){
48367 return this.locked;
48371 * Ext JS Library 1.1.1
48372 * Copyright(c) 2006-2007, Ext JS, LLC.
48374 * Originally Released Under LGPL - original licence link has changed is not relivant.
48377 * <script type="text/javascript">
48380 * @extends Roo.grid.AbstractSelectionModel
48381 * @class Roo.grid.RowSelectionModel
48382 * The default SelectionModel used by {@link Roo.grid.Grid}.
48383 * It supports multiple selections and keyboard selection/navigation.
48385 * @param {Object} config
48387 Roo.grid.RowSelectionModel = function(config){
48388 Roo.apply(this, config);
48389 this.selections = new Roo.util.MixedCollection(false, function(o){
48394 this.lastActive = false;
48398 * @event selectionchange
48399 * Fires when the selection changes
48400 * @param {SelectionModel} this
48402 "selectionchange" : true,
48404 * @event afterselectionchange
48405 * Fires after the selection changes (eg. by key press or clicking)
48406 * @param {SelectionModel} this
48408 "afterselectionchange" : true,
48410 * @event beforerowselect
48411 * Fires when a row is selected being selected, return false to cancel.
48412 * @param {SelectionModel} this
48413 * @param {Number} rowIndex The selected index
48414 * @param {Boolean} keepExisting False if other selections will be cleared
48416 "beforerowselect" : true,
48419 * Fires when a row is selected.
48420 * @param {SelectionModel} this
48421 * @param {Number} rowIndex The selected index
48422 * @param {Roo.data.Record} r The record
48424 "rowselect" : true,
48426 * @event rowdeselect
48427 * Fires when a row is deselected.
48428 * @param {SelectionModel} this
48429 * @param {Number} rowIndex The selected index
48431 "rowdeselect" : true
48433 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
48434 this.locked = false;
48437 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
48439 * @cfg {Boolean} singleSelect
48440 * True to allow selection of only one row at a time (defaults to false)
48442 singleSelect : false,
48445 initEvents : function(){
48447 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
48448 this.grid.on("mousedown", this.handleMouseDown, this);
48449 }else{ // allow click to work like normal
48450 this.grid.on("rowclick", this.handleDragableRowClick, this);
48453 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
48454 "up" : function(e){
48456 this.selectPrevious(e.shiftKey);
48457 }else if(this.last !== false && this.lastActive !== false){
48458 var last = this.last;
48459 this.selectRange(this.last, this.lastActive-1);
48460 this.grid.getView().focusRow(this.lastActive);
48461 if(last !== false){
48465 this.selectFirstRow();
48467 this.fireEvent("afterselectionchange", this);
48469 "down" : function(e){
48471 this.selectNext(e.shiftKey);
48472 }else if(this.last !== false && this.lastActive !== false){
48473 var last = this.last;
48474 this.selectRange(this.last, this.lastActive+1);
48475 this.grid.getView().focusRow(this.lastActive);
48476 if(last !== false){
48480 this.selectFirstRow();
48482 this.fireEvent("afterselectionchange", this);
48487 var view = this.grid.view;
48488 view.on("refresh", this.onRefresh, this);
48489 view.on("rowupdated", this.onRowUpdated, this);
48490 view.on("rowremoved", this.onRemove, this);
48494 onRefresh : function(){
48495 var ds = this.grid.dataSource, i, v = this.grid.view;
48496 var s = this.selections;
48497 s.each(function(r){
48498 if((i = ds.indexOfId(r.id)) != -1){
48507 onRemove : function(v, index, r){
48508 this.selections.remove(r);
48512 onRowUpdated : function(v, index, r){
48513 if(this.isSelected(r)){
48514 v.onRowSelect(index);
48520 * @param {Array} records The records to select
48521 * @param {Boolean} keepExisting (optional) True to keep existing selections
48523 selectRecords : function(records, keepExisting){
48525 this.clearSelections();
48527 var ds = this.grid.dataSource;
48528 for(var i = 0, len = records.length; i < len; i++){
48529 this.selectRow(ds.indexOf(records[i]), true);
48534 * Gets the number of selected rows.
48537 getCount : function(){
48538 return this.selections.length;
48542 * Selects the first row in the grid.
48544 selectFirstRow : function(){
48549 * Select the last row.
48550 * @param {Boolean} keepExisting (optional) True to keep existing selections
48552 selectLastRow : function(keepExisting){
48553 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
48557 * Selects the row immediately following the last selected row.
48558 * @param {Boolean} keepExisting (optional) True to keep existing selections
48560 selectNext : function(keepExisting){
48561 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
48562 this.selectRow(this.last+1, keepExisting);
48563 this.grid.getView().focusRow(this.last);
48568 * Selects the row that precedes the last selected row.
48569 * @param {Boolean} keepExisting (optional) True to keep existing selections
48571 selectPrevious : function(keepExisting){
48573 this.selectRow(this.last-1, keepExisting);
48574 this.grid.getView().focusRow(this.last);
48579 * Returns the selected records
48580 * @return {Array} Array of selected records
48582 getSelections : function(){
48583 return [].concat(this.selections.items);
48587 * Returns the first selected record.
48590 getSelected : function(){
48591 return this.selections.itemAt(0);
48596 * Clears all selections.
48598 clearSelections : function(fast){
48599 if(this.locked) return;
48601 var ds = this.grid.dataSource;
48602 var s = this.selections;
48603 s.each(function(r){
48604 this.deselectRow(ds.indexOfId(r.id));
48608 this.selections.clear();
48615 * Selects all rows.
48617 selectAll : function(){
48618 if(this.locked) return;
48619 this.selections.clear();
48620 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
48621 this.selectRow(i, true);
48626 * Returns True if there is a selection.
48627 * @return {Boolean}
48629 hasSelection : function(){
48630 return this.selections.length > 0;
48634 * Returns True if the specified row is selected.
48635 * @param {Number/Record} record The record or index of the record to check
48636 * @return {Boolean}
48638 isSelected : function(index){
48639 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
48640 return (r && this.selections.key(r.id) ? true : false);
48644 * Returns True if the specified record id is selected.
48645 * @param {String} id The id of record to check
48646 * @return {Boolean}
48648 isIdSelected : function(id){
48649 return (this.selections.key(id) ? true : false);
48653 handleMouseDown : function(e, t){
48654 var view = this.grid.getView(), rowIndex;
48655 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
48658 if(e.shiftKey && this.last !== false){
48659 var last = this.last;
48660 this.selectRange(last, rowIndex, e.ctrlKey);
48661 this.last = last; // reset the last
48662 view.focusRow(rowIndex);
48664 var isSelected = this.isSelected(rowIndex);
48665 if(e.button !== 0 && isSelected){
48666 view.focusRow(rowIndex);
48667 }else if(e.ctrlKey && isSelected){
48668 this.deselectRow(rowIndex);
48669 }else if(!isSelected){
48670 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
48671 view.focusRow(rowIndex);
48674 this.fireEvent("afterselectionchange", this);
48677 handleDragableRowClick : function(grid, rowIndex, e)
48679 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
48680 this.selectRow(rowIndex, false);
48681 grid.view.focusRow(rowIndex);
48682 this.fireEvent("afterselectionchange", this);
48687 * Selects multiple rows.
48688 * @param {Array} rows Array of the indexes of the row to select
48689 * @param {Boolean} keepExisting (optional) True to keep existing selections
48691 selectRows : function(rows, keepExisting){
48693 this.clearSelections();
48695 for(var i = 0, len = rows.length; i < len; i++){
48696 this.selectRow(rows[i], true);
48701 * Selects a range of rows. All rows in between startRow and endRow are also selected.
48702 * @param {Number} startRow The index of the first row in the range
48703 * @param {Number} endRow The index of the last row in the range
48704 * @param {Boolean} keepExisting (optional) True to retain existing selections
48706 selectRange : function(startRow, endRow, keepExisting){
48707 if(this.locked) return;
48709 this.clearSelections();
48711 if(startRow <= endRow){
48712 for(var i = startRow; i <= endRow; i++){
48713 this.selectRow(i, true);
48716 for(var i = startRow; i >= endRow; i--){
48717 this.selectRow(i, true);
48723 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
48724 * @param {Number} startRow The index of the first row in the range
48725 * @param {Number} endRow The index of the last row in the range
48727 deselectRange : function(startRow, endRow, preventViewNotify){
48728 if(this.locked) return;
48729 for(var i = startRow; i <= endRow; i++){
48730 this.deselectRow(i, preventViewNotify);
48736 * @param {Number} row The index of the row to select
48737 * @param {Boolean} keepExisting (optional) True to keep existing selections
48739 selectRow : function(index, keepExisting, preventViewNotify){
48740 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
48741 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
48742 if(!keepExisting || this.singleSelect){
48743 this.clearSelections();
48745 var r = this.grid.dataSource.getAt(index);
48746 this.selections.add(r);
48747 this.last = this.lastActive = index;
48748 if(!preventViewNotify){
48749 this.grid.getView().onRowSelect(index);
48751 this.fireEvent("rowselect", this, index, r);
48752 this.fireEvent("selectionchange", this);
48758 * @param {Number} row The index of the row to deselect
48760 deselectRow : function(index, preventViewNotify){
48761 if(this.locked) return;
48762 if(this.last == index){
48765 if(this.lastActive == index){
48766 this.lastActive = false;
48768 var r = this.grid.dataSource.getAt(index);
48769 this.selections.remove(r);
48770 if(!preventViewNotify){
48771 this.grid.getView().onRowDeselect(index);
48773 this.fireEvent("rowdeselect", this, index);
48774 this.fireEvent("selectionchange", this);
48778 restoreLast : function(){
48780 this.last = this._last;
48785 acceptsNav : function(row, col, cm){
48786 return !cm.isHidden(col) && cm.isCellEditable(col, row);
48790 onEditorKey : function(field, e){
48791 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
48796 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
48798 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
48800 }else if(k == e.ENTER && !e.ctrlKey){
48804 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
48806 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
48808 }else if(k == e.ESC){
48812 g.startEditing(newCell[0], newCell[1]);
48817 * Ext JS Library 1.1.1
48818 * Copyright(c) 2006-2007, Ext JS, LLC.
48820 * Originally Released Under LGPL - original licence link has changed is not relivant.
48823 * <script type="text/javascript">
48826 * @class Roo.grid.CellSelectionModel
48827 * @extends Roo.grid.AbstractSelectionModel
48828 * This class provides the basic implementation for cell selection in a grid.
48830 * @param {Object} config The object containing the configuration of this model.
48832 Roo.grid.CellSelectionModel = function(config){
48833 Roo.apply(this, config);
48835 this.selection = null;
48839 * @event beforerowselect
48840 * Fires before a cell is selected.
48841 * @param {SelectionModel} this
48842 * @param {Number} rowIndex The selected row index
48843 * @param {Number} colIndex The selected cell index
48845 "beforecellselect" : true,
48847 * @event cellselect
48848 * Fires when a cell is selected.
48849 * @param {SelectionModel} this
48850 * @param {Number} rowIndex The selected row index
48851 * @param {Number} colIndex The selected cell index
48853 "cellselect" : true,
48855 * @event selectionchange
48856 * Fires when the active selection changes.
48857 * @param {SelectionModel} this
48858 * @param {Object} selection null for no selection or an object (o) with two properties
48860 <li>o.record: the record object for the row the selection is in</li>
48861 <li>o.cell: An array of [rowIndex, columnIndex]</li>
48864 "selectionchange" : true
48866 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
48869 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
48872 initEvents : function(){
48873 this.grid.on("mousedown", this.handleMouseDown, this);
48874 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
48875 var view = this.grid.view;
48876 view.on("refresh", this.onViewChange, this);
48877 view.on("rowupdated", this.onRowUpdated, this);
48878 view.on("beforerowremoved", this.clearSelections, this);
48879 view.on("beforerowsinserted", this.clearSelections, this);
48880 if(this.grid.isEditor){
48881 this.grid.on("beforeedit", this.beforeEdit, this);
48886 beforeEdit : function(e){
48887 this.select(e.row, e.column, false, true, e.record);
48891 onRowUpdated : function(v, index, r){
48892 if(this.selection && this.selection.record == r){
48893 v.onCellSelect(index, this.selection.cell[1]);
48898 onViewChange : function(){
48899 this.clearSelections(true);
48903 * Returns the currently selected cell,.
48904 * @return {Array} The selected cell (row, column) or null if none selected.
48906 getSelectedCell : function(){
48907 return this.selection ? this.selection.cell : null;
48911 * Clears all selections.
48912 * @param {Boolean} true to prevent the gridview from being notified about the change.
48914 clearSelections : function(preventNotify){
48915 var s = this.selection;
48917 if(preventNotify !== true){
48918 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
48920 this.selection = null;
48921 this.fireEvent("selectionchange", this, null);
48926 * Returns true if there is a selection.
48927 * @return {Boolean}
48929 hasSelection : function(){
48930 return this.selection ? true : false;
48934 handleMouseDown : function(e, t){
48935 var v = this.grid.getView();
48936 if(this.isLocked()){
48939 var row = v.findRowIndex(t);
48940 var cell = v.findCellIndex(t);
48941 if(row !== false && cell !== false){
48942 this.select(row, cell);
48948 * @param {Number} rowIndex
48949 * @param {Number} collIndex
48951 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
48952 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
48953 this.clearSelections();
48954 r = r || this.grid.dataSource.getAt(rowIndex);
48957 cell : [rowIndex, colIndex]
48959 if(!preventViewNotify){
48960 var v = this.grid.getView();
48961 v.onCellSelect(rowIndex, colIndex);
48962 if(preventFocus !== true){
48963 v.focusCell(rowIndex, colIndex);
48966 this.fireEvent("cellselect", this, rowIndex, colIndex);
48967 this.fireEvent("selectionchange", this, this.selection);
48972 isSelectable : function(rowIndex, colIndex, cm){
48973 return !cm.isHidden(colIndex);
48977 handleKeyDown : function(e){
48978 if(!e.isNavKeyPress()){
48981 var g = this.grid, s = this.selection;
48984 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
48986 this.select(cell[0], cell[1]);
48991 var walk = function(row, col, step){
48992 return g.walkCells(row, col, step, sm.isSelectable, sm);
48994 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
49000 newCell = walk(r, c-1, -1);
49002 newCell = walk(r, c+1, 1);
49006 newCell = walk(r+1, c, 1);
49009 newCell = walk(r-1, c, -1);
49012 newCell = walk(r, c+1, 1);
49015 newCell = walk(r, c-1, -1);
49018 if(g.isEditor && !g.editing){
49019 g.startEditing(r, c);
49026 this.select(newCell[0], newCell[1]);
49031 acceptsNav : function(row, col, cm){
49032 return !cm.isHidden(col) && cm.isCellEditable(col, row);
49035 onEditorKey : function(field, e){
49036 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
49039 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49041 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49044 }else if(k == e.ENTER && !e.ctrlKey){
49047 }else if(k == e.ESC){
49051 g.startEditing(newCell[0], newCell[1]);
49056 * Ext JS Library 1.1.1
49057 * Copyright(c) 2006-2007, Ext JS, LLC.
49059 * Originally Released Under LGPL - original licence link has changed is not relivant.
49062 * <script type="text/javascript">
49066 * @class Roo.grid.EditorGrid
49067 * @extends Roo.grid.Grid
49068 * Class for creating and editable grid.
49069 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49070 * The container MUST have some type of size defined for the grid to fill. The container will be
49071 * automatically set to position relative if it isn't already.
49072 * @param {Object} dataSource The data model to bind to
49073 * @param {Object} colModel The column model with info about this grid's columns
49075 Roo.grid.EditorGrid = function(container, config){
49076 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
49077 this.getGridEl().addClass("xedit-grid");
49079 if(!this.selModel){
49080 this.selModel = new Roo.grid.CellSelectionModel();
49083 this.activeEditor = null;
49087 * @event beforeedit
49088 * Fires before cell editing is triggered. The edit event object has the following properties <br />
49089 * <ul style="padding:5px;padding-left:16px;">
49090 * <li>grid - This grid</li>
49091 * <li>record - The record being edited</li>
49092 * <li>field - The field name being edited</li>
49093 * <li>value - The value for the field being edited.</li>
49094 * <li>row - The grid row index</li>
49095 * <li>column - The grid column index</li>
49096 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
49098 * @param {Object} e An edit event (see above for description)
49100 "beforeedit" : true,
49103 * Fires after a cell is edited. <br />
49104 * <ul style="padding:5px;padding-left:16px;">
49105 * <li>grid - This grid</li>
49106 * <li>record - The record being edited</li>
49107 * <li>field - The field name being edited</li>
49108 * <li>value - The value being set</li>
49109 * <li>originalValue - The original value for the field, before the edit.</li>
49110 * <li>row - The grid row index</li>
49111 * <li>column - The grid column index</li>
49113 * @param {Object} e An edit event (see above for description)
49115 "afteredit" : true,
49117 * @event validateedit
49118 * Fires after a cell is edited, but before the value is set in the record.
49119 * You can use this to modify the value being set in the field, Return false
49120 * to cancel the change. The edit event object has the following properties <br />
49121 * <ul style="padding:5px;padding-left:16px;">
49122 * <li>editor - This editor</li>
49123 * <li>grid - This grid</li>
49124 * <li>record - The record being edited</li>
49125 * <li>field - The field name being edited</li>
49126 * <li>value - The value being set</li>
49127 * <li>originalValue - The original value for the field, before the edit.</li>
49128 * <li>row - The grid row index</li>
49129 * <li>column - The grid column index</li>
49130 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
49132 * @param {Object} e An edit event (see above for description)
49134 "validateedit" : true
49136 this.on("bodyscroll", this.stopEditing, this);
49137 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
49140 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
49142 * @cfg {Number} clicksToEdit
49143 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
49150 trackMouseOver: false, // causes very odd FF errors
49152 onCellDblClick : function(g, row, col){
49153 this.startEditing(row, col);
49156 onEditComplete : function(ed, value, startValue){
49157 this.editing = false;
49158 this.activeEditor = null;
49159 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
49161 var field = this.colModel.getDataIndex(ed.col);
49166 originalValue: startValue,
49173 if(String(value) !== String(startValue)){
49175 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
49176 r.set(field, e.value);
49177 delete e.cancel; //?? why!!!
49178 this.fireEvent("afteredit", e);
49181 this.fireEvent("afteredit", e); // always fir it!
49183 this.view.focusCell(ed.row, ed.col);
49187 * Starts editing the specified for the specified row/column
49188 * @param {Number} rowIndex
49189 * @param {Number} colIndex
49191 startEditing : function(row, col){
49192 this.stopEditing();
49193 if(this.colModel.isCellEditable(col, row)){
49194 this.view.ensureVisible(row, col, true);
49195 var r = this.dataSource.getAt(row);
49196 var field = this.colModel.getDataIndex(col);
49201 value: r.data[field],
49206 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
49207 this.editing = true;
49208 var ed = this.colModel.getCellEditor(col, row);
49214 ed.render(ed.parentEl || document.body);
49217 (function(){ // complex but required for focus issues in safari, ie and opera
49221 ed.on("complete", this.onEditComplete, this, {single: true});
49222 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
49223 this.activeEditor = ed;
49224 var v = r.data[field];
49225 ed.startEdit(this.view.getCell(row, col), v);
49226 }).defer(50, this);
49232 * Stops any active editing
49234 stopEditing : function(){
49235 if(this.activeEditor){
49236 this.activeEditor.completeEdit();
49238 this.activeEditor = null;
49242 * Ext JS Library 1.1.1
49243 * Copyright(c) 2006-2007, Ext JS, LLC.
49245 * Originally Released Under LGPL - original licence link has changed is not relivant.
49248 * <script type="text/javascript">
49251 // private - not really -- you end up using it !
49252 // This is a support class used internally by the Grid components
49255 * @class Roo.grid.GridEditor
49256 * @extends Roo.Editor
49257 * Class for creating and editable grid elements.
49258 * @param {Object} config any settings (must include field)
49260 Roo.grid.GridEditor = function(field, config){
49261 if (!config && field.field) {
49263 field = Roo.factory(config.field, Roo.form);
49265 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
49266 field.monitorTab = false;
49269 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
49272 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
49275 alignment: "tl-tl",
49278 cls: "x-small-editor x-grid-editor",
49283 * Ext JS Library 1.1.1
49284 * Copyright(c) 2006-2007, Ext JS, LLC.
49286 * Originally Released Under LGPL - original licence link has changed is not relivant.
49289 * <script type="text/javascript">
49294 Roo.grid.PropertyRecord = Roo.data.Record.create([
49295 {name:'name',type:'string'}, 'value'
49299 Roo.grid.PropertyStore = function(grid, source){
49301 this.store = new Roo.data.Store({
49302 recordType : Roo.grid.PropertyRecord
49304 this.store.on('update', this.onUpdate, this);
49306 this.setSource(source);
49308 Roo.grid.PropertyStore.superclass.constructor.call(this);
49313 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
49314 setSource : function(o){
49316 this.store.removeAll();
49319 if(this.isEditableValue(o[k])){
49320 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
49323 this.store.loadRecords({records: data}, {}, true);
49326 onUpdate : function(ds, record, type){
49327 if(type == Roo.data.Record.EDIT){
49328 var v = record.data['value'];
49329 var oldValue = record.modified['value'];
49330 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
49331 this.source[record.id] = v;
49333 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
49340 getProperty : function(row){
49341 return this.store.getAt(row);
49344 isEditableValue: function(val){
49345 if(val && val instanceof Date){
49347 }else if(typeof val == 'object' || typeof val == 'function'){
49353 setValue : function(prop, value){
49354 this.source[prop] = value;
49355 this.store.getById(prop).set('value', value);
49358 getSource : function(){
49359 return this.source;
49363 Roo.grid.PropertyColumnModel = function(grid, store){
49366 g.PropertyColumnModel.superclass.constructor.call(this, [
49367 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
49368 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
49370 this.store = store;
49371 this.bselect = Roo.DomHelper.append(document.body, {
49372 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
49373 {tag: 'option', value: 'true', html: 'true'},
49374 {tag: 'option', value: 'false', html: 'false'}
49377 Roo.id(this.bselect);
49380 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
49381 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
49382 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
49383 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
49384 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
49386 this.renderCellDelegate = this.renderCell.createDelegate(this);
49387 this.renderPropDelegate = this.renderProp.createDelegate(this);
49390 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
49394 valueText : 'Value',
49396 dateFormat : 'm/j/Y',
49399 renderDate : function(dateVal){
49400 return dateVal.dateFormat(this.dateFormat);
49403 renderBool : function(bVal){
49404 return bVal ? 'true' : 'false';
49407 isCellEditable : function(colIndex, rowIndex){
49408 return colIndex == 1;
49411 getRenderer : function(col){
49413 this.renderCellDelegate : this.renderPropDelegate;
49416 renderProp : function(v){
49417 return this.getPropertyName(v);
49420 renderCell : function(val){
49422 if(val instanceof Date){
49423 rv = this.renderDate(val);
49424 }else if(typeof val == 'boolean'){
49425 rv = this.renderBool(val);
49427 return Roo.util.Format.htmlEncode(rv);
49430 getPropertyName : function(name){
49431 var pn = this.grid.propertyNames;
49432 return pn && pn[name] ? pn[name] : name;
49435 getCellEditor : function(colIndex, rowIndex){
49436 var p = this.store.getProperty(rowIndex);
49437 var n = p.data['name'], val = p.data['value'];
49439 if(typeof(this.grid.customEditors[n]) == 'string'){
49440 return this.editors[this.grid.customEditors[n]];
49442 if(typeof(this.grid.customEditors[n]) != 'undefined'){
49443 return this.grid.customEditors[n];
49445 if(val instanceof Date){
49446 return this.editors['date'];
49447 }else if(typeof val == 'number'){
49448 return this.editors['number'];
49449 }else if(typeof val == 'boolean'){
49450 return this.editors['boolean'];
49452 return this.editors['string'];
49458 * @class Roo.grid.PropertyGrid
49459 * @extends Roo.grid.EditorGrid
49460 * This class represents the interface of a component based property grid control.
49461 * <br><br>Usage:<pre><code>
49462 var grid = new Roo.grid.PropertyGrid("my-container-id", {
49470 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49471 * The container MUST have some type of size defined for the grid to fill. The container will be
49472 * automatically set to position relative if it isn't already.
49473 * @param {Object} config A config object that sets properties on this grid.
49475 Roo.grid.PropertyGrid = function(container, config){
49476 config = config || {};
49477 var store = new Roo.grid.PropertyStore(this);
49478 this.store = store;
49479 var cm = new Roo.grid.PropertyColumnModel(this, store);
49480 store.store.sort('name', 'ASC');
49481 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
49484 enableColLock:false,
49485 enableColumnMove:false,
49487 trackMouseOver: false,
49490 this.getGridEl().addClass('x-props-grid');
49491 this.lastEditRow = null;
49492 this.on('columnresize', this.onColumnResize, this);
49495 * @event beforepropertychange
49496 * Fires before a property changes (return false to stop?)
49497 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
49498 * @param {String} id Record Id
49499 * @param {String} newval New Value
49500 * @param {String} oldval Old Value
49502 "beforepropertychange": true,
49504 * @event propertychange
49505 * Fires after a property changes
49506 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
49507 * @param {String} id Record Id
49508 * @param {String} newval New Value
49509 * @param {String} oldval Old Value
49511 "propertychange": true
49513 this.customEditors = this.customEditors || {};
49515 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
49518 * @cfg {Object} customEditors map of colnames=> custom editors.
49519 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
49520 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
49521 * false disables editing of the field.
49525 * @cfg {Object} propertyNames map of property Names to their displayed value
49528 render : function(){
49529 Roo.grid.PropertyGrid.superclass.render.call(this);
49530 this.autoSize.defer(100, this);
49533 autoSize : function(){
49534 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
49536 this.view.fitColumns();
49540 onColumnResize : function(){
49541 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
49545 * Sets the data for the Grid
49546 * accepts a Key => Value object of all the elements avaiable.
49547 * @param {Object} data to appear in grid.
49549 setSource : function(source){
49550 this.store.setSource(source);
49554 * Gets all the data from the grid.
49555 * @return {Object} data data stored in grid
49557 getSource : function(){
49558 return this.store.getSource();
49562 * Ext JS Library 1.1.1
49563 * Copyright(c) 2006-2007, Ext JS, LLC.
49565 * Originally Released Under LGPL - original licence link has changed is not relivant.
49568 * <script type="text/javascript">
49572 * @class Roo.LoadMask
49573 * A simple utility class for generically masking elements while loading data. If the element being masked has
49574 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
49575 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
49576 * element's UpdateManager load indicator and will be destroyed after the initial load.
49578 * Create a new LoadMask
49579 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
49580 * @param {Object} config The config object
49582 Roo.LoadMask = function(el, config){
49583 this.el = Roo.get(el);
49584 Roo.apply(this, config);
49586 this.store.on('beforeload', this.onBeforeLoad, this);
49587 this.store.on('load', this.onLoad, this);
49588 this.store.on('loadexception', this.onLoad, this);
49589 this.removeMask = false;
49591 var um = this.el.getUpdateManager();
49592 um.showLoadIndicator = false; // disable the default indicator
49593 um.on('beforeupdate', this.onBeforeLoad, this);
49594 um.on('update', this.onLoad, this);
49595 um.on('failure', this.onLoad, this);
49596 this.removeMask = true;
49600 Roo.LoadMask.prototype = {
49602 * @cfg {Boolean} removeMask
49603 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
49604 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
49607 * @cfg {String} msg
49608 * The text to display in a centered loading message box (defaults to 'Loading...')
49610 msg : 'Loading...',
49612 * @cfg {String} msgCls
49613 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
49615 msgCls : 'x-mask-loading',
49618 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
49624 * Disables the mask to prevent it from being displayed
49626 disable : function(){
49627 this.disabled = true;
49631 * Enables the mask so that it can be displayed
49633 enable : function(){
49634 this.disabled = false;
49638 onLoad : function(){
49639 this.el.unmask(this.removeMask);
49643 onBeforeLoad : function(){
49644 if(!this.disabled){
49645 this.el.mask(this.msg, this.msgCls);
49650 destroy : function(){
49652 this.store.un('beforeload', this.onBeforeLoad, this);
49653 this.store.un('load', this.onLoad, this);
49654 this.store.un('loadexception', this.onLoad, this);
49656 var um = this.el.getUpdateManager();
49657 um.un('beforeupdate', this.onBeforeLoad, this);
49658 um.un('update', this.onLoad, this);
49659 um.un('failure', this.onLoad, this);
49664 * Ext JS Library 1.1.1
49665 * Copyright(c) 2006-2007, Ext JS, LLC.
49667 * Originally Released Under LGPL - original licence link has changed is not relivant.
49670 * <script type="text/javascript">
49672 Roo.XTemplate = function(){
49673 Roo.XTemplate.superclass.constructor.apply(this, arguments);
49676 s = ['<tpl>', s, '</tpl>'].join('');
49678 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
49680 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
49681 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
49682 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
49686 while(m = s.match(re)){
49687 var m2 = m[0].match(nameRe);
49688 var m3 = m[0].match(ifRe);
49689 var m4 = m[0].match(execRe);
49690 var exp = null, fn = null, exec = null;
49691 var name = m2 && m2[1] ? m2[1] : '';
49693 exp = m3 && m3[1] ? m3[1] : null;
49695 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
49699 exp = m4 && m4[1] ? m4[1] : null;
49701 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
49706 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
49707 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
49708 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
49718 s = s.replace(m[0], '{xtpl'+ id + '}');
49721 for(var i = tpls.length-1; i >= 0; --i){
49722 this.compileTpl(tpls[i]);
49724 this.master = tpls[tpls.length-1];
49727 Roo.extend(Roo.XTemplate, Roo.Template, {
49729 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
49731 applySubTemplate : function(id, values, parent){
49732 var t = this.tpls[id];
49733 if(t.test && !t.test.call(this, values, parent)){
49736 if(t.exec && t.exec.call(this, values, parent)){
49739 var vs = t.target ? t.target.call(this, values, parent) : values;
49740 parent = t.target ? values : parent;
49741 if(t.target && vs instanceof Array){
49743 for(var i = 0, len = vs.length; i < len; i++){
49744 buf[buf.length] = t.compiled.call(this, vs[i], parent);
49746 return buf.join('');
49748 return t.compiled.call(this, vs, parent);
49751 compileTpl : function(tpl){
49752 var fm = Roo.util.Format;
49753 var useF = this.disableFormats !== true;
49754 var sep = Roo.isGecko ? "+" : ",";
49755 var fn = function(m, name, format, args){
49756 if(name.substr(0, 4) == 'xtpl'){
49757 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
49760 if(name.indexOf('.') != -1){
49763 v = "values['" + name + "']";
49765 if(format && useF){
49766 args = args ? ',' + args : "";
49767 if(format.substr(0, 5) != "this."){
49768 format = "fm." + format + '(';
49770 format = 'this.call("'+ format.substr(5) + '", ';
49774 args= ''; format = "("+v+" === undefined ? '' : ";
49776 return "'"+ sep + format + v + args + ")"+sep+"'";
49779 // branched to use + in gecko and [].join() in others
49781 body = "tpl.compiled = function(values, parent){ return '" +
49782 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
49785 body = ["tpl.compiled = function(values, parent){ return ['"];
49786 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
49787 body.push("'].join('');};");
49788 body = body.join('');
49790 /** eval:var:zzzzzzz */
49795 applyTemplate : function(values){
49796 return this.master.compiled.call(this, values, {});
49800 apply : function(){
49801 return this.applyTemplate.apply(this, arguments);
49804 compile : function(){return this;}
49807 Roo.XTemplate.from = function(el){
49808 el = Roo.getDom(el);
49809 return new Roo.XTemplate(el.value || el.innerHTML);
49811 * Original code for Roojs - LGPL
49812 * <script type="text/javascript">
49816 * @class Roo.XComponent
49817 * A delayed Element creator...
49819 * Mypart.xyx = new Roo.XComponent({
49821 parent : 'Mypart.xyz', // empty == document.element.!!
49825 disabled : function() {}
49827 tree : function() { // return an tree of xtype declared components
49831 xtype : 'NestedLayoutPanel',
49836 * @extends Roo.util.Observable
49838 * @param cfg {Object} configuration of component
49841 Roo.XComponent = function(cfg) {
49842 Roo.apply(this, cfg);
49846 * Fires when this the componnt is built
49847 * @param {Roo.XComponent} c the component
49851 * @event buildcomplete
49852 * Fires on the top level element when all elements have been built
49853 * @param {Roo.XComponent} c the top level component.
49855 'buildcomplete' : true,
49859 Roo.XComponent.register(this);
49860 this.modules = false;
49861 this.el = false; // where the layout goes..
49865 Roo.extend(Roo.XComponent, Roo.util.Observable, {
49868 * The created element (with Roo.factory())
49869 * @type {Roo.Layout}
49875 * for BC - use el in new code
49876 * @type {Roo.Layout}
49882 * for BC - use el in new code
49883 * @type {Roo.Layout}
49888 * @cfg {Function|boolean} disabled
49889 * If this module is disabled by some rule, return true from the funtion
49894 * @cfg {String} parent
49895 * Name of parent element which it get xtype added to..
49900 * @cfg {String} order
49901 * Used to set the order in which elements are created (usefull for multiple tabs)
49906 * @cfg {String} name
49907 * String to display while loading.
49911 * @cfg {Array} items
49912 * A single item array - the first element is the root of the tree..
49913 * It's done this way to stay compatible with the Xtype system...
49921 Roo.apply(Roo.XComponent, {
49924 * @property buildCompleted
49925 * True when the builder has completed building the interface.
49928 buildCompleted : false,
49931 * @property topModule
49932 * the upper most module - uses document.element as it's constructor.
49939 * @property modules
49940 * array of modules to be created by registration system.
49941 * @type Roo.XComponent
49948 * Register components to be built later.
49950 * This solves the following issues
49951 * - Building is not done on page load, but after an authentication process has occured.
49952 * - Interface elements are registered on page load
49953 * - Parent Interface elements may not be loaded before child, so this handles that..
49960 module : 'Pman.Tab.projectMgr',
49962 parent : 'Pman.layout',
49963 disabled : false, // or use a function..
49966 * * @param {Object} details about module
49968 register : function(obj) {
49969 this.modules.push(obj);
49973 * convert a string to an object..
49977 toObject : function(str)
49979 if (!str || typeof(str) == 'object') {
49982 var ar = str.split('.');
49986 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
49988 throw "Module not found : " + str;
49990 Roo.each(ar, function(e) {
49991 if (typeof(o[e]) == 'undefined') {
49992 throw "Module not found : " + str;
50002 * move modules into their correct place in the tree..
50005 preBuild : function ()
50008 Roo.each(this.modules , function (obj)
50010 obj.parent = this.toObject(obj.parent);
50013 this.topModule = obj;
50017 if (!obj.parent.modules) {
50018 obj.parent.modules = new Roo.util.MixedCollection(false,
50019 function(o) { return o.order + '' }
50023 obj.parent.modules.add(obj);
50028 * make a list of modules to build.
50029 * @return {Array} list of modules.
50032 buildOrder : function()
50035 var cmp = function(a,b) {
50036 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
50039 if (!this.topModule || !this.topModule.modules) {
50040 throw "No top level modules to build";
50043 // make a flat list in order of modules to build.
50044 var mods = [ this.topModule ];
50047 // add modules to their parents..
50048 var addMod = function(m) {
50049 // console.log(m.modKey);
50053 m.modules.keySort('ASC', cmp );
50054 m.modules.each(addMod);
50056 // not sure if this is used any more..
50058 m.finalize.name = m.name + " (clean up) ";
50059 mods.push(m.finalize);
50063 this.topModule.modules.keySort('ASC', cmp );
50064 this.topModule.modules.each(addMod);
50069 * Build the registered modules.
50070 * @param {Object} parent element.
50071 * @param {Function} optional method to call after module has been added.
50079 var mods = this.buildOrder();
50081 //this.allmods = mods;
50082 //console.log(mods);
50084 if (!mods.length) { // should not happen
50085 throw "NO modules!!!";
50090 // flash it up as modal - so we store the mask!?
50091 Roo.MessageBox.show({ title: 'loading' });
50092 Roo.MessageBox.show({
50093 title: "Please wait...",
50094 msg: "Building Interface...",
50101 var total = mods.length;
50104 var progressRun = function() {
50105 if (!mods.length) {
50106 console.log('hide?');
50107 Roo.MessageBox.hide();
50108 _this.topModule.fireEvent('buildcomplete', _this.topModule);
50112 var m = mods.shift();
50114 if (typeof(m) == 'function') { // not sure if this is supported any more..
50116 return progressRun.defer(10, _this);
50119 Roo.MessageBox.updateProgress(
50120 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
50122 (m.name ? (' - ' + m.name) : '')
50127 var disabled = (typeof(m.disabled) == 'function') ?
50128 m.disabled.call(m.module.disabled) : m.disabled;
50132 return progressRun(); // we do not update the display!
50136 // it's a top level one..
50137 var layoutbase = new Ext.BorderLayout(document.body, {
50143 tabPosition: 'top',
50144 //resizeTabs: true,
50145 alwaysShowTabs: true,
50149 var tree = m.tree();
50150 tree.region = 'center';
50151 m.el = layoutbase.addxtype(tree);
50153 m.layout = m.panel.layout;
50154 return progressRun.defer(10, _this);
50157 var tree = m.tree();
50158 tree.region = tree.region || m.region;
50159 m.el = m.parent.el.addxtype(tree);
50160 m.fireEvent('built', m);
50162 m.layout = m.panel.layout;
50163 progressRun.defer(10, _this);
50166 progressRun.defer(1, _this);
50176 //<script type="text/javascript">
50181 * @extends Roo.LayoutDialog
50182 * A generic Login Dialog..... - only one needed in theory!?!?
50184 * Fires XComponent builder on success...
50187 * username,password, lang = for login actions.
50188 * check = 1 for periodic checking that sesion is valid.
50189 * passwordRequest = email request password
50190 * logout = 1 = to logout
50192 * Affects: (this id="????" elements)
50193 * loading (removed) (used to indicate application is loading)
50194 * loading-mask (hides) (used to hide application when it's building loading)
50200 * Myapp.login = Roo.Login({
50216 Roo.Login = function(cfg)
50219 'refreshed' : true,
50222 Roo.apply(this,cfg);
50224 Roo.onReady(function() {
50230 Roo.Login.superclass.constructor.call(this, this);
50231 //this.addxtype(this.items[0]);
50237 Roo.extend(Roo.Login, Roo.LayoutDialog, {
50240 * @cfg {String} method
50241 * Method used to query for login details.
50246 * @cfg {String} url
50247 * URL to query login data. - eg. baseURL + '/Login.php'
50253 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
50258 * @property checkFails
50259 * Number of times we have attempted to get authentication check, and failed.
50264 * @property intervalID
50265 * The window interval that does the constant login checking.
50271 onLoad : function() // called on page load...
50275 if (Roo.get('loading')) { // clear any loading indicator..
50276 Roo.get('loading').remove();
50279 //this.switchLang('en'); // set the language to english..
50282 success: function(response, opts) { // check successfull...
50284 var res = this.processResponse(response);
50285 this.checkFails =0;
50286 if (!res.success) { // error!
50287 this.checkFails = 5;
50288 //console.log('call failure');
50289 return this.failure(response,opts);
50292 if (!res.data.id) { // id=0 == login failure.
50293 return this.show();
50297 //console.log(success);
50298 this.fillAuth(res.data);
50299 this.checkFails =0;
50300 Roo.XComponent.build();
50302 failure : this.show
50308 check: function(cfg) // called every so often to refresh cookie etc..
50310 if (cfg.again) { // could be undefined..
50313 this.checkFails = 0;
50316 if (this.sending) {
50317 if ( this.checkFails > 4) {
50318 Roo.MessageBox.alert("Error",
50319 "Error getting authentication status. - try reloading, or wait a while", function() {
50320 _this.sending = false;
50325 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
50328 this.sending = true;
50335 method: this.method,
50336 success: cfg.success || this.success,
50337 failure : cfg.failure || this.failure,
50347 window.onbeforeunload = function() { }; // false does not work for IE..
50357 failure : function() {
50358 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
50359 document.location = document.location.toString() + '?ts=' + Math.random();
50363 success : function() {
50364 _this.user = false;
50365 this.checkFails =0;
50367 document.location = document.location.toString() + '?ts=' + Math.random();
50374 processResponse : function (response)
50378 res = Roo.decode(response.responseText);
50380 if (typeof(res) != 'object') {
50381 res = { success : false, errorMsg : res, errors : true };
50383 if (typeof(res.success) == 'undefined') {
50384 res.success = false;
50388 res = { success : false, errorMsg : response.responseText, errors : true };
50393 success : function(response, opts) // check successfull...
50395 this.sending = false;
50396 var res = this.processResponse(response);
50397 if (!res.success) {
50398 return this.failure(response, opts);
50400 if (!res.data || !res.data.id) {
50401 return this.failure(response,opts);
50403 //console.log(res);
50404 this.fillAuth(res.data);
50406 this.checkFails =0;
50411 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
50413 this.authUser = -1;
50414 this.sending = false;
50415 var res = this.processResponse(response);
50416 //console.log(res);
50417 if ( this.checkFails > 2) {
50419 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
50420 "Error getting authentication status. - try reloading");
50423 opts.callCfg.again = true;
50424 this.check.defer(1000, this, [ opts.callCfg ]);
50430 fillAuth: function(au) {
50431 this.startAuthCheck();
50432 this.authUserId = au.id;
50433 this.authUser = au;
50434 this.lastChecked = new Date();
50435 this.fireEvent('refreshed', au);
50436 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
50437 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
50438 au.lang = au.lang || 'en';
50439 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
50440 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
50441 this.switchLang(au.lang );
50444 // open system... - -on setyp..
50445 if (this.authUserId < 0) {
50446 Roo.MessageBox.alert("Warning",
50447 "This is an open system - please set up a admin user with a password.");
50450 //Pman.onload(); // which should do nothing if it's a re-auth result...
50455 startAuthCheck : function() // starter for timeout checking..
50457 if (this.intervalID) { // timer already in place...
50461 this.intervalID = window.setInterval(function() {
50462 _this.check(false);
50463 }, 120000); // every 120 secs = 2mins..
50469 switchLang : function (lang)
50471 _T = typeof(_T) == 'undefined' ? false : _T;
50472 if (!_T || !lang.length) {
50476 if (!_T && lang != 'en') {
50477 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
50481 if (typeof(_T.en) == 'undefined') {
50483 Roo.apply(_T.en, _T);
50486 if (typeof(_T[lang]) == 'undefined') {
50487 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
50492 Roo.apply(_T, _T[lang]);
50493 // just need to set the text values for everything...
50495 /* this will not work ...
50499 function formLabel(name, val) {
50500 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
50503 formLabel('password', "Password"+':');
50504 formLabel('username', "Email Address"+':');
50505 formLabel('lang', "Language"+':');
50506 this.dialog.setTitle("Login");
50507 this.dialog.buttons[0].setText("Forgot Password");
50508 this.dialog.buttons[1].setText("Login");
50527 collapsible: false,
50529 center: { // needed??
50532 // tabPosition: 'top',
50535 alwaysShowTabs: false
50539 show : function(dlg)
50541 //console.log(this);
50542 this.form = this.layout.getRegion('center').activePanel.form;
50543 this.form.dialog = dlg;
50544 this.buttons[0].form = this.form;
50545 this.buttons[0].dialog = dlg
50546 this.buttons[1].form = this.form;
50547 this.buttons[1].dialog = dlg;
50549 //this.resizeToLogo.defer(1000,this);
50550 // this is all related to resizing for logos..
50551 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
50553 // this.resizeToLogo.defer(1000,this);
50556 //var w = Ext.lib.Dom.getViewWidth() - 100;
50557 //var h = Ext.lib.Dom.getViewHeight() - 100;
50558 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
50560 if (this.disabled) {
50565 if (this.user.id < 0) { // used for inital setup situations.
50569 if (this.intervalID) {
50570 // remove the timer
50571 window.clearInterval(this.intervalID);
50572 this.intervalID = false;
50576 if (Roo.get('loading')) {
50577 Roo.get('loading').remove();
50579 if (Roo.get('loading-mask')) {
50580 Roo.get('loading-mask').hide();
50583 //incomming._node = tnode;
50585 //this.dialog.modal = !modal;
50586 //this.dialog.show();
50590 this.form.setValues({
50591 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
50592 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
50595 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
50596 if (this.form.findField('username').getValue().length > 0 ){
50597 this.form.findField('password').focus();
50599 this.form.findField('username').focus();
50607 xtype : 'ContentPanel',
50619 style : 'margin: 10px;',
50622 actionfailed : function(f, act) {
50623 // form can return { errors: .... }
50625 //act.result.errors // invalid form element list...
50626 //act.result.errorMsg// invalid form element list...
50628 this.dialog.el.unmask();
50629 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
50630 "Login failed - communication error - try again.");
50633 actioncomplete: function(re, act) {
50635 Roo.state.Manager.set(
50636 this.dialog.realm + '.username',
50637 this.findField('username').getValue()
50639 Roo.state.Manager.set(
50640 this.dialog.realm + '.lang',
50641 this.findField('lang').getValue()
50644 this.dialog.fillAuth(act.result.data);
50646 this.dialog.hide();
50648 if (Roo.get('loading-mask')) {
50649 Roo.get('loading-mask').show();
50651 Roo.XComponent.build();
50659 xtype : 'TextField',
50661 fieldLabel: "Email Address",
50664 autoCreate : {tag: "input", type: "text", size: "20"}
50667 xtype : 'TextField',
50669 fieldLabel: "Password",
50670 inputType: 'password',
50673 autoCreate : {tag: "input", type: "text", size: "20"},
50675 specialkey : function(e,ev) {
50676 if (ev.keyCode == 13) {
50677 this.form.dialog.el.mask("Logging in");
50678 this.form.doAction('submit', {
50679 url: this.form.dialog.url,
50680 method: this.form.dialog.method,
50687 xtype : 'ComboBox',
50689 fieldLabel: "Language",
50692 xtype : 'SimpleStore',
50693 fields: ['lang', 'ldisp'],
50695 [ 'en', 'English' ],
50696 [ 'zh_HK' , '\u7E41\u4E2D' ],
50697 [ 'zh_CN', '\u7C21\u4E2D' ]
50701 valueField : 'lang',
50702 hiddenName: 'lang',
50704 displayField:'ldisp',
50708 triggerAction: 'all',
50709 emptyText:'Select a Language...',
50710 selectOnFocus:true,
50712 select : function(cb, rec, ix) {
50713 this.form.switchLang(rec.data.lang);
50729 text : "Forgot Password",
50731 click : function() {
50732 //console.log(this);
50733 var n = this.form.findField('username').getValue();
50735 Roo.MessageBox.alert("Error", "Fill in your email address");
50739 url: this.dialog.url,
50743 method: this.dialog.method,
50744 success: function(response, opts) { // check successfull...
50746 var res = this.dialog.processResponse(response);
50747 if (!res.success) { // error!
50748 Roo.MessageBox.alert("Error" ,
50749 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
50752 Roo.MessageBox.alert("Notice" ,
50753 "Please check you email for the Password Reset message");
50755 failure : function() {
50756 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
50769 click : function () {
50771 this.dialog.el.mask("Logging in");
50772 this.form.doAction('submit', {
50773 url: this.dialog.url,
50774 method: this.dialog.method