4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
90 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
93 enableGarbageCollector : true,
96 * True to automatically purge event listeners after uncaching an element (defaults to false).
97 * Note: this only happens if enableGarbageCollector is true.
100 enableListenerCollection:false,
103 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
104 * the IE insecure content warning (defaults to javascript:false).
107 SSL_SECURE_URL : "javascript:false",
110 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
111 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
114 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
116 emptyFn : function(){},
119 * Copies all the properties of config to obj if they don't already exist.
120 * @param {Object} obj The receiver of the properties
121 * @param {Object} config The source of the properties
122 * @return {Object} returns obj
124 applyIf : function(o, c){
127 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134 * Applies event listeners to elements by selectors when the document is ready.
135 * The event name is specified with an @ suffix.
138 // add a listener for click on all anchors in element with id foo
139 '#foo a@click' : function(e, t){
143 // add the same listener to multiple selectors (separated by comma BEFORE the @)
144 '#foo a, #bar span.some-class@mouseover' : function(){
149 * @param {Object} obj The list of behaviors to apply
151 addBehaviors : function(o){
153 Roo.onReady(function(){
158 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
160 var parts = b.split('@');
161 if(parts[1]){ // for Object prototype breakers
164 cache[s] = Roo.select(s);
166 cache[s].on(parts[1], o[b]);
173 * Generates unique ids. If the element already has an id, it is unchanged
174 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
175 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
176 * @return {String} The generated Id.
178 id : function(el, prefix){
179 prefix = prefix || "roo-gen";
181 var id = prefix + (++idSeed);
182 return el ? (el.id ? el.id : (el.id = id)) : id;
187 * Extends one class with another class and optionally overrides members with the passed literal. This class
188 * also adds the function "override()" to the class that can be used to override
189 * members on an instance.
190 * @param {Object} subclass The class inheriting the functionality
191 * @param {Object} superclass The class being extended
192 * @param {Object} overrides (optional) A literal with members
197 var io = function(o){
202 return function(sb, sp, overrides){
203 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
206 sb = function(){sp.apply(this, arguments);};
208 var F = function(){}, sbp, spp = sp.prototype;
210 sbp = sb.prototype = new F();
214 if(spp.constructor == Object.prototype.constructor){
219 sb.override = function(o){
223 Roo.override(sb, overrides);
229 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
231 Roo.override(MyClass, {
232 newMethod1: function(){
235 newMethod2: function(foo){
240 * @param {Object} origclass The class to override
241 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
242 * containing one or more methods.
245 override : function(origclass, overrides){
247 var p = origclass.prototype;
248 for(var method in overrides){
249 p[method] = overrides[method];
254 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
256 Roo.namespace('Company', 'Company.data');
257 Company.Widget = function() { ... }
258 Company.data.CustomStore = function(config) { ... }
260 * @param {String} namespace1
261 * @param {String} namespace2
262 * @param {String} etc
265 namespace : function(){
266 var a=arguments, o=null, i, j, d, rt;
267 for (i=0; i<a.length; ++i) {
271 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
272 for (j=1; j<d.length; ++j) {
273 o[d[j]]=o[d[j]] || {};
279 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
281 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
282 Roo.factory(conf, Roo.data);
284 * @param {String} classname
285 * @param {String} namespace (optional)
289 factory : function(c, ns)
291 // no xtype, no ns or c.xns - or forced off by c.xns
292 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
295 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
296 if (c.constructor == ns[c.xtype]) {// already created...
300 console.log("Roo.Factory(" + c.xtype + ")");
301 var ret = new ns[c.xtype](c);
305 c.xns = false; // prevent recursion..
310 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
314 urlEncode : function(o){
320 var ov = o[key], k = encodeURIComponent(key);
321 var type = typeof ov;
322 if(type == 'undefined'){
324 }else if(type != "function" && type != "object"){
325 buf.push(k, "=", encodeURIComponent(ov), "&");
326 }else if(ov instanceof Array){
328 for(var i = 0, len = ov.length; i < len; i++) {
329 buf.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
341 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
342 * @param {String} string
343 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
344 * @return {Object} A literal with members
346 urlDecode : function(string, overwrite){
347 if(!string || !string.length){
351 var pairs = string.split('&');
352 var pair, name, value;
353 for(var i = 0, len = pairs.length; i < len; i++){
354 pair = pairs[i].split('=');
355 name = decodeURIComponent(pair[0]);
356 value = decodeURIComponent(pair[1]);
357 if(overwrite !== true){
358 if(typeof obj[name] == "undefined"){
360 }else if(typeof obj[name] == "string"){
361 obj[name] = [obj[name]];
362 obj[name].push(value);
364 obj[name].push(value);
374 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
375 * passed array is not really an array, your function is called once with it.
376 * The supplied function is called with (Object item, Number index, Array allItems).
377 * @param {Array/NodeList/Mixed} array
378 * @param {Function} fn
379 * @param {Object} scope
381 each : function(array, fn, scope){
382 if(typeof array.length == "undefined" || typeof array == "string"){
385 for(var i = 0, len = array.length; i < len; i++){
386 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
391 combine : function(){
392 var as = arguments, l = as.length, r = [];
393 for(var i = 0; i < l; i++){
395 if(a instanceof Array){
397 }else if(a.length !== undefined && !a.substr){
398 r = r.concat(Array.prototype.slice.call(a, 0));
407 * Escapes the passed string for use in a regular expression
408 * @param {String} str
411 escapeRe : function(s) {
412 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
416 callback : function(cb, scope, args, delay){
417 if(typeof cb == "function"){
419 cb.defer(delay, scope, args || []);
421 cb.apply(scope, args || []);
427 * Return the dom node for the passed string (id), dom node, or Roo.Element
428 * @param {String/HTMLElement/Roo.Element} el
429 * @return HTMLElement
431 getDom : function(el){
435 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
439 * Shorthand for {@link Roo.ComponentMgr#get}
441 * @return Roo.Component
443 getCmp : function(id){
444 return Roo.ComponentMgr.get(id);
447 num : function(v, defaultValue){
448 if(typeof v != 'number'){
454 destroy : function(){
455 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
459 as.removeAllListeners();
463 if(typeof as.purgeListeners == 'function'){
466 if(typeof as.destroy == 'function'){
473 // inpired by a similar function in mootools library
475 * Returns the type of object that is passed in. If the object passed in is null or undefined it
476 * return false otherwise it returns one of the following values:<ul>
477 * <li><b>string</b>: If the object passed is a string</li>
478 * <li><b>number</b>: If the object passed is a number</li>
479 * <li><b>boolean</b>: If the object passed is a boolean value</li>
480 * <li><b>function</b>: If the object passed is a function reference</li>
481 * <li><b>object</b>: If the object passed is an object</li>
482 * <li><b>array</b>: If the object passed is an array</li>
483 * <li><b>regexp</b>: If the object passed is a regular expression</li>
484 * <li><b>element</b>: If the object passed is a DOM Element</li>
485 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
486 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
487 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
488 * @param {Mixed} object
492 if(o === undefined || o === null){
499 if(t == 'object' && o.nodeName) {
501 case 1: return 'element';
502 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
505 if(t == 'object' || t == 'function') {
506 switch(o.constructor) {
507 case Array: return 'array';
508 case RegExp: return 'regexp';
510 if(typeof o.length == 'number' && typeof o.item == 'function') {
518 * Returns true if the passed value is null, undefined or an empty string (optional).
519 * @param {Mixed} value The value to test
520 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
523 isEmpty : function(v, allowBlank){
524 return v === null || v === undefined || (!allowBlank ? v === '' : false);
538 isBorderBox : isBorderBox,
540 isWindows : isWindows,
547 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
548 * you may want to set this to true.
551 useShims : ((isIE && !isIE7) || (isGecko && isMac))
557 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
558 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
561 * Ext JS Library 1.1.1
562 * Copyright(c) 2006-2007, Ext JS, LLC.
564 * Originally Released Under LGPL - original licence link has changed is not relivant.
567 * <script type="text/javascript">
571 // wrappedn so fnCleanup is not in global scope...
573 function fnCleanUp() {
574 var p = Function.prototype;
575 delete p.createSequence;
577 delete p.createDelegate;
578 delete p.createCallback;
579 delete p.createInterceptor;
581 window.detachEvent("onunload", fnCleanUp);
583 window.attachEvent("onunload", fnCleanUp);
590 * These functions are available on every Function object (any JavaScript function).
592 Roo.apply(Function.prototype, {
594 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
595 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
596 * Will create a function that is bound to those 2 args.
597 * @return {Function} The new function
599 createCallback : function(/*args...*/){
600 // make args available, in function below
601 var args = arguments;
604 return method.apply(window, args);
609 * Creates a delegate (callback) that sets the scope to obj.
610 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
611 * Will create a function that is automatically scoped to this.
612 * @param {Object} obj (optional) The object for which the scope is set
613 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
614 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
615 * if a number the args are inserted at the specified position
616 * @return {Function} The new function
618 createDelegate : function(obj, args, appendArgs){
621 var callArgs = args || arguments;
622 if(appendArgs === true){
623 callArgs = Array.prototype.slice.call(arguments, 0);
624 callArgs = callArgs.concat(args);
625 }else if(typeof appendArgs == "number"){
626 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
627 var applyArgs = [appendArgs, 0].concat(args); // create method call params
628 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
630 return method.apply(obj || window, callArgs);
635 * Calls this function after the number of millseconds specified.
636 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
637 * @param {Object} obj (optional) The object for which the scope is set
638 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
639 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
640 * if a number the args are inserted at the specified position
641 * @return {Number} The timeout id that can be used with clearTimeout
643 defer : function(millis, obj, args, appendArgs){
644 var fn = this.createDelegate(obj, args, appendArgs);
646 return setTimeout(fn, millis);
652 * Create a combined function call sequence of the original function + the passed function.
653 * The resulting function returns the results of the original function.
654 * The passed fcn is called with the parameters of the original function
655 * @param {Function} fcn The function to sequence
656 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
657 * @return {Function} The new function
659 createSequence : function(fcn, scope){
660 if(typeof fcn != "function"){
665 var retval = method.apply(this || window, arguments);
666 fcn.apply(scope || this || window, arguments);
672 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
673 * The resulting function returns the results of the original function.
674 * The passed fcn is called with the parameters of the original function.
676 * @param {Function} fcn The function to call before the original
677 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
678 * @return {Function} The new function
680 createInterceptor : function(fcn, scope){
681 if(typeof fcn != "function"){
688 if(fcn.apply(scope || this || window, arguments) === false){
691 return method.apply(this || window, arguments);
697 * Ext JS Library 1.1.1
698 * Copyright(c) 2006-2007, Ext JS, LLC.
700 * Originally Released Under LGPL - original licence link has changed is not relivant.
703 * <script type="text/javascript">
706 Roo.applyIf(String, {
711 * Escapes the passed string for ' and \
712 * @param {String} string The string to escape
713 * @return {String} The escaped string
716 escape : function(string) {
717 return string.replace(/('|\\)/g, "\\$1");
721 * Pads the left side of a string with a specified character. This is especially useful
722 * for normalizing number and date strings. Example usage:
724 var s = String.leftPad('123', 5, '0');
725 // s now contains the string: '00123'
727 * @param {String} string The original string
728 * @param {Number} size The total length of the output string
729 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
730 * @return {String} The padded string
733 leftPad : function (val, size, ch) {
734 var result = new String(val);
735 if(ch === null || ch === undefined || ch === '') {
738 while (result.length < size) {
739 result = ch + result;
745 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
746 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
748 var cls = 'my-class', text = 'Some text';
749 var s = String.format('<div class="{0}">{1}</div>', cls, text);
750 // s now contains the string: '<div class="my-class">Some text</div>'
752 * @param {String} string The tokenized string to be formatted
753 * @param {String} value1 The value to replace token {0}
754 * @param {String} value2 Etc...
755 * @return {String} The formatted string
758 format : function(format){
759 var args = Array.prototype.slice.call(arguments, 1);
760 return format.replace(/\{(\d+)\}/g, function(m, i){
761 return Roo.util.Format.htmlEncode(args[i]);
767 * Utility function that allows you to easily switch a string between two alternating values. The passed value
768 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
769 * they are already different, the first value passed in is returned. Note that this method returns the new value
770 * but does not change the current string.
772 // alternate sort directions
773 sort = sort.toggle('ASC', 'DESC');
775 // instead of conditional logic:
776 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
778 * @param {String} value The value to compare to the current string
779 * @param {String} other The new value to use if the string already equals the first value passed in
780 * @return {String} The new value
783 String.prototype.toggle = function(value, other){
784 return this == value ? other : value;
787 * Ext JS Library 1.1.1
788 * Copyright(c) 2006-2007, Ext JS, LLC.
790 * Originally Released Under LGPL - original licence link has changed is not relivant.
793 * <script type="text/javascript">
799 Roo.applyIf(Number.prototype, {
801 * Checks whether or not the current number is within a desired range. If the number is already within the
802 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
803 * exceeded. Note that this method returns the constrained value but does not change the current number.
804 * @param {Number} min The minimum number in the range
805 * @param {Number} max The maximum number in the range
806 * @return {Number} The constrained value if outside the range, otherwise the current value
808 constrain : function(min, max){
809 return Math.min(Math.max(this, min), max);
813 * Ext JS Library 1.1.1
814 * Copyright(c) 2006-2007, Ext JS, LLC.
816 * Originally Released Under LGPL - original licence link has changed is not relivant.
819 * <script type="text/javascript">
824 Roo.applyIf(Array.prototype, {
826 * Checks whether or not the specified object exists in the array.
827 * @param {Object} o The object to check for
828 * @return {Number} The index of o in the array (or -1 if it is not found)
830 indexOf : function(o){
831 for (var i = 0, len = this.length; i < len; i++){
832 if(this[i] == o) return i;
838 * Removes the specified object from the array. If the object is not found nothing happens.
839 * @param {Object} o The object to remove
841 remove : function(o){
842 var index = this.indexOf(o);
844 this.splice(index, 1);
849 * Ext JS Library 1.1.1
850 * Copyright(c) 2006-2007, Ext JS, LLC.
852 * Originally Released Under LGPL - original licence link has changed is not relivant.
855 * <script type="text/javascript">
861 * The date parsing and format syntax is a subset of
862 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
863 * supported will provide results equivalent to their PHP versions.
865 * Following is the list of all currently supported formats:
868 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
870 Format Output Description
871 ------ ---------- --------------------------------------------------------------
872 d 10 Day of the month, 2 digits with leading zeros
873 D Wed A textual representation of a day, three letters
874 j 10 Day of the month without leading zeros
875 l Wednesday A full textual representation of the day of the week
876 S th English ordinal day of month suffix, 2 chars (use with j)
877 w 3 Numeric representation of the day of the week
878 z 9 The julian date, or day of the year (0-365)
879 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
880 F January A full textual representation of the month
881 m 01 Numeric representation of a month, with leading zeros
882 M Jan Month name abbreviation, three letters
883 n 1 Numeric representation of a month, without leading zeros
884 t 31 Number of days in the given month
885 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
886 Y 2007 A full numeric representation of a year, 4 digits
887 y 07 A two digit representation of a year
888 a pm Lowercase Ante meridiem and Post meridiem
889 A PM Uppercase Ante meridiem and Post meridiem
890 g 3 12-hour format of an hour without leading zeros
891 G 15 24-hour format of an hour without leading zeros
892 h 03 12-hour format of an hour with leading zeros
893 H 15 24-hour format of an hour with leading zeros
894 i 05 Minutes with leading zeros
895 s 01 Seconds, with leading zeros
896 O -0600 Difference to Greenwich time (GMT) in hours
897 T CST Timezone setting of the machine running the code
898 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
901 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
903 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
904 document.write(dt.format('Y-m-d')); //2007-01-10
905 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
906 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
909 * Here are some standard date/time patterns that you might find helpful. They
910 * are not part of the source of Date.js, but to use them you can simply copy this
911 * block of code into any script that is included after Date.js and they will also become
912 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
915 ISO8601Long:"Y-m-d H:i:s",
916 ISO8601Short:"Y-m-d",
918 LongDate: "l, F d, Y",
919 FullDateTime: "l, F d, Y g:i:s A",
923 SortableDateTime: "Y-m-d\\TH:i:s",
924 UniversalSortableDateTime: "Y-m-d H:i:sO",
932 document.write(dt.format(Date.patterns.ShortDate));
937 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
938 * They generate precompiled functions from date formats instead of parsing and
939 * processing the pattern every time you format a date. These functions are available
940 * on every Date object (any javascript function).
942 * The original article and download are here:
943 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
950 Returns the number of milliseconds between this date and date
951 @param {Date} date (optional) Defaults to now
952 @return {Number} The diff in milliseconds
953 @member Date getElapsed
955 Date.prototype.getElapsed = function(date) {
956 return Math.abs((date || new Date()).getTime()-this.getTime());
958 // was in date file..
962 Date.parseFunctions = {count:0};
964 Date.parseRegexes = [];
966 Date.formatFunctions = {count:0};
969 Date.prototype.dateFormat = function(format) {
970 if (Date.formatFunctions[format] == null) {
971 Date.createNewFormat(format);
973 var func = Date.formatFunctions[format];
979 * Formats a date given the supplied format string
980 * @param {String} format The format string
981 * @return {String} The formatted date
984 Date.prototype.format = Date.prototype.dateFormat;
987 Date.createNewFormat = function(format) {
988 var funcName = "format" + Date.formatFunctions.count++;
989 Date.formatFunctions[format] = funcName;
990 var code = "Date.prototype." + funcName + " = function(){return ";
993 for (var i = 0; i < format.length; ++i) {
994 ch = format.charAt(i);
995 if (!special && ch == "\\") {
1000 code += "'" + String.escape(ch) + "' + ";
1003 code += Date.getFormatCode(ch);
1006 /** eval:var:zzzzzzzzzzzzz */
1007 eval(code.substring(0, code.length - 3) + ";}");
1011 Date.getFormatCode = function(character) {
1012 switch (character) {
1014 return "String.leftPad(this.getDate(), 2, '0') + ";
1016 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1018 return "this.getDate() + ";
1020 return "Date.dayNames[this.getDay()] + ";
1022 return "this.getSuffix() + ";
1024 return "this.getDay() + ";
1026 return "this.getDayOfYear() + ";
1028 return "this.getWeekOfYear() + ";
1030 return "Date.monthNames[this.getMonth()] + ";
1032 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1034 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1036 return "(this.getMonth() + 1) + ";
1038 return "this.getDaysInMonth() + ";
1040 return "(this.isLeapYear() ? 1 : 0) + ";
1042 return "this.getFullYear() + ";
1044 return "('' + this.getFullYear()).substring(2, 4) + ";
1046 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1048 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1050 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1052 return "this.getHours() + ";
1054 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1056 return "String.leftPad(this.getHours(), 2, '0') + ";
1058 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1060 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1062 return "this.getGMTOffset() + ";
1064 return "this.getTimezone() + ";
1066 return "(this.getTimezoneOffset() * -60) + ";
1068 return "'" + String.escape(character) + "' + ";
1073 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1074 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1075 * the date format that is not specified will default to the current date value for that part. Time parts can also
1076 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1077 * string or the parse operation will fail.
1080 //dt = Fri May 25 2007 (current date)
1081 var dt = new Date();
1083 //dt = Thu May 25 2006 (today's month/day in 2006)
1084 dt = Date.parseDate("2006", "Y");
1086 //dt = Sun Jan 15 2006 (all date parts specified)
1087 dt = Date.parseDate("2006-1-15", "Y-m-d");
1089 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1090 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1092 * @param {String} input The unparsed date as a string
1093 * @param {String} format The format the date is in
1094 * @return {Date} The parsed date
1097 Date.parseDate = function(input, format) {
1098 if (Date.parseFunctions[format] == null) {
1099 Date.createParser(format);
1101 var func = Date.parseFunctions[format];
1102 return Date[func](input);
1107 Date.createParser = function(format) {
1108 var funcName = "parse" + Date.parseFunctions.count++;
1109 var regexNum = Date.parseRegexes.length;
1110 var currentGroup = 1;
1111 Date.parseFunctions[format] = funcName;
1113 var code = "Date." + funcName + " = function(input){\n"
1114 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1115 + "var d = new Date();\n"
1116 + "y = d.getFullYear();\n"
1117 + "m = d.getMonth();\n"
1118 + "d = d.getDate();\n"
1119 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1120 + "if (results && results.length > 0) {";
1123 var special = false;
1125 for (var i = 0; i < format.length; ++i) {
1126 ch = format.charAt(i);
1127 if (!special && ch == "\\") {
1132 regex += String.escape(ch);
1135 var obj = Date.formatCodeToRegex(ch, currentGroup);
1136 currentGroup += obj.g;
1138 if (obj.g && obj.c) {
1144 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1145 + "{v = new Date(y, m, d, h, i, s);}\n"
1146 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1147 + "{v = new Date(y, m, d, h, i);}\n"
1148 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1149 + "{v = new Date(y, m, d, h);}\n"
1150 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1151 + "{v = new Date(y, m, d);}\n"
1152 + "else if (y >= 0 && m >= 0)\n"
1153 + "{v = new Date(y, m);}\n"
1154 + "else if (y >= 0)\n"
1155 + "{v = new Date(y);}\n"
1156 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1157 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1158 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1161 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1162 /** eval:var:zzzzzzzzzzzzz */
1167 Date.formatCodeToRegex = function(character, currentGroup) {
1168 switch (character) {
1172 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1175 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1176 s:"(\\d{1,2})"}; // day of month without leading zeroes
1179 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1180 s:"(\\d{2})"}; // day of month with leading zeroes
1184 s:"(?:" + Date.dayNames.join("|") + ")"};
1188 s:"(?:st|nd|rd|th)"};
1203 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1204 s:"(" + Date.monthNames.join("|") + ")"};
1207 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1208 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1211 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1212 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1215 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1216 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1227 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1231 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1232 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1236 c:"if (results[" + currentGroup + "] == 'am') {\n"
1237 + "if (h == 12) { h = 0; }\n"
1238 + "} else { if (h < 12) { h += 12; }}",
1242 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1243 + "if (h == 12) { h = 0; }\n"
1244 + "} else { if (h < 12) { h += 12; }}",
1249 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1250 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1254 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1255 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1258 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1262 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1267 "o = results[", currentGroup, "];\n",
1268 "var sn = o.substring(0,1);\n", // get + / - sign
1269 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1270 "var mn = o.substring(3,5) % 60;\n", // get minutes
1271 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1272 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1278 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1281 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1282 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1283 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1287 s:String.escape(character)};
1292 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1293 * @return {String} The abbreviated timezone name (e.g. 'CST')
1295 Date.prototype.getTimezone = function() {
1296 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1300 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1301 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1303 Date.prototype.getGMTOffset = function() {
1304 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1305 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1306 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1310 * Get the numeric day number of the year, adjusted for leap year.
1311 * @return {Number} 0 through 364 (365 in leap years)
1313 Date.prototype.getDayOfYear = function() {
1315 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1316 for (var i = 0; i < this.getMonth(); ++i) {
1317 num += Date.daysInMonth[i];
1319 return num + this.getDate() - 1;
1323 * Get the string representation of the numeric week number of the year
1324 * (equivalent to the format specifier 'W').
1325 * @return {String} '00' through '52'
1327 Date.prototype.getWeekOfYear = function() {
1328 // Skip to Thursday of this week
1329 var now = this.getDayOfYear() + (4 - this.getDay());
1330 // Find the first Thursday of the year
1331 var jan1 = new Date(this.getFullYear(), 0, 1);
1332 var then = (7 - jan1.getDay() + 4);
1333 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1337 * Whether or not the current date is in a leap year.
1338 * @return {Boolean} True if the current date is in a leap year, else false
1340 Date.prototype.isLeapYear = function() {
1341 var year = this.getFullYear();
1342 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1346 * Get the first day of the current month, adjusted for leap year. The returned value
1347 * is the numeric day index within the week (0-6) which can be used in conjunction with
1348 * the {@link #monthNames} array to retrieve the textual day name.
1351 var dt = new Date('1/10/2007');
1352 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1354 * @return {Number} The day number (0-6)
1356 Date.prototype.getFirstDayOfMonth = function() {
1357 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1358 return (day < 0) ? (day + 7) : day;
1362 * Get the last day of the current month, adjusted for leap year. The returned value
1363 * is the numeric day index within the week (0-6) which can be used in conjunction with
1364 * the {@link #monthNames} array to retrieve the textual day name.
1367 var dt = new Date('1/10/2007');
1368 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1370 * @return {Number} The day number (0-6)
1372 Date.prototype.getLastDayOfMonth = function() {
1373 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1374 return (day < 0) ? (day + 7) : day;
1379 * Get the first date of this date's month
1382 Date.prototype.getFirstDateOfMonth = function() {
1383 return new Date(this.getFullYear(), this.getMonth(), 1);
1387 * Get the last date of this date's month
1390 Date.prototype.getLastDateOfMonth = function() {
1391 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1394 * Get the number of days in the current month, adjusted for leap year.
1395 * @return {Number} The number of days in the month
1397 Date.prototype.getDaysInMonth = function() {
1398 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1399 return Date.daysInMonth[this.getMonth()];
1403 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1404 * @return {String} 'st, 'nd', 'rd' or 'th'
1406 Date.prototype.getSuffix = function() {
1407 switch (this.getDate()) {
1424 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1427 * An array of textual month names.
1428 * Override these values for international dates, for example...
1429 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1448 * An array of textual day names.
1449 * Override these values for international dates, for example...
1450 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1466 Date.monthNumbers = {
1481 * Creates and returns a new Date instance with the exact same date value as the called instance.
1482 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1483 * variable will also be changed. When the intention is to create a new variable that will not
1484 * modify the original instance, you should create a clone.
1486 * Example of correctly cloning a date:
1489 var orig = new Date('10/1/2006');
1492 document.write(orig); //returns 'Thu Oct 05 2006'!
1495 var orig = new Date('10/1/2006');
1496 var copy = orig.clone();
1498 document.write(orig); //returns 'Thu Oct 01 2006'
1500 * @return {Date} The new Date instance
1502 Date.prototype.clone = function() {
1503 return new Date(this.getTime());
1507 * Clears any time information from this date
1508 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1509 @return {Date} this or the clone
1511 Date.prototype.clearTime = function(clone){
1513 return this.clone().clearTime();
1518 this.setMilliseconds(0);
1523 // safari setMonth is broken
1525 Date.brokenSetMonth = Date.prototype.setMonth;
1526 Date.prototype.setMonth = function(num){
1528 var n = Math.ceil(-num);
1529 var back_year = Math.ceil(n/12);
1530 var month = (n % 12) ? 12 - n % 12 : 0 ;
1531 this.setFullYear(this.getFullYear() - back_year);
1532 return Date.brokenSetMonth.call(this, month);
1534 return Date.brokenSetMonth.apply(this, arguments);
1539 /** Date interval constant
1543 /** Date interval constant
1547 /** Date interval constant
1551 /** Date interval constant
1555 /** Date interval constant
1559 /** Date interval constant
1563 /** Date interval constant
1569 * Provides a convenient method of performing basic date arithmetic. This method
1570 * does not modify the Date instance being called - it creates and returns
1571 * a new Date instance containing the resulting date value.
1576 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1577 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1579 //Negative values will subtract correctly:
1580 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1581 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1583 //You can even chain several calls together in one line!
1584 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1585 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1588 * @param {String} interval A valid date interval enum value
1589 * @param {Number} value The amount to add to the current date
1590 * @return {Date} The new Date instance
1592 Date.prototype.add = function(interval, value){
1593 var d = this.clone();
1594 if (!interval || value === 0) return d;
1595 switch(interval.toLowerCase()){
1597 d.setMilliseconds(this.getMilliseconds() + value);
1600 d.setSeconds(this.getSeconds() + value);
1603 d.setMinutes(this.getMinutes() + value);
1606 d.setHours(this.getHours() + value);
1609 d.setDate(this.getDate() + value);
1612 var day = this.getDate();
1614 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1617 d.setMonth(this.getMonth() + value);
1620 d.setFullYear(this.getFullYear() + value);
1626 * Ext JS Library 1.1.1
1627 * Copyright(c) 2006-2007, Ext JS, LLC.
1629 * Originally Released Under LGPL - original licence link has changed is not relivant.
1632 * <script type="text/javascript">
1636 getViewWidth : function(full) {
1637 return full ? this.getDocumentWidth() : this.getViewportWidth();
1640 getViewHeight : function(full) {
1641 return full ? this.getDocumentHeight() : this.getViewportHeight();
1644 getDocumentHeight: function() {
1645 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1646 return Math.max(scrollHeight, this.getViewportHeight());
1649 getDocumentWidth: function() {
1650 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1651 return Math.max(scrollWidth, this.getViewportWidth());
1654 getViewportHeight: function() {
1655 var height = self.innerHeight;
1656 var mode = document.compatMode;
1658 if ((mode || Roo.isIE) && !Roo.isOpera) {
1659 height = (mode == "CSS1Compat") ?
1660 document.documentElement.clientHeight :
1661 document.body.clientHeight;
1667 getViewportWidth: function() {
1668 var width = self.innerWidth;
1669 var mode = document.compatMode;
1671 if (mode || Roo.isIE) {
1672 width = (mode == "CSS1Compat") ?
1673 document.documentElement.clientWidth :
1674 document.body.clientWidth;
1679 isAncestor : function(p, c) {
1686 if (p.contains && !Roo.isSafari) {
1687 return p.contains(c);
1688 } else if (p.compareDocumentPosition) {
1689 return !!(p.compareDocumentPosition(c) & 16);
1691 var parent = c.parentNode;
1696 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1699 parent = parent.parentNode;
1705 getRegion : function(el) {
1706 return Roo.lib.Region.getRegion(el);
1709 getY : function(el) {
1710 return this.getXY(el)[1];
1713 getX : function(el) {
1714 return this.getXY(el)[0];
1717 getXY : function(el) {
1718 var p, pe, b, scroll, bd = document.body;
1719 el = Roo.getDom(el);
1720 var fly = Roo.lib.AnimBase.fly;
1721 if (el.getBoundingClientRect) {
1722 b = el.getBoundingClientRect();
1723 scroll = fly(document).getScroll();
1724 return [b.left + scroll.left, b.top + scroll.top];
1730 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1737 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1744 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1745 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1752 if (p != el && pe.getStyle('overflow') != 'visible') {
1760 if (Roo.isSafari && hasAbsolute) {
1765 if (Roo.isGecko && !hasAbsolute) {
1767 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1768 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1772 while (p && p != bd) {
1773 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1785 setXY : function(el, xy) {
1786 el = Roo.fly(el, '_setXY');
1788 var pts = el.translatePoints(xy);
1789 if (xy[0] !== false) {
1790 el.dom.style.left = pts.left + "px";
1792 if (xy[1] !== false) {
1793 el.dom.style.top = pts.top + "px";
1797 setX : function(el, x) {
1798 this.setXY(el, [x, false]);
1801 setY : function(el, y) {
1802 this.setXY(el, [false, y]);
1806 * Portions of this file are based on pieces of Yahoo User Interface Library
1807 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1808 * YUI licensed under the BSD License:
1809 * http://developer.yahoo.net/yui/license.txt
1810 * <script type="text/javascript">
1814 Roo.lib.Event = function() {
1815 var loadComplete = false;
1817 var unloadListeners = [];
1819 var onAvailStack = [];
1821 var lastError = null;
1834 startInterval: function() {
1835 if (!this._interval) {
1837 var callback = function() {
1838 self._tryPreloadAttach();
1840 this._interval = setInterval(callback, this.POLL_INTERVAL);
1845 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1846 onAvailStack.push({ id: p_id,
1849 override: p_override,
1850 checkReady: false });
1852 retryCount = this.POLL_RETRYS;
1853 this.startInterval();
1857 addListener: function(el, eventName, fn) {
1858 el = Roo.getDom(el);
1863 if ("unload" == eventName) {
1864 unloadListeners[unloadListeners.length] =
1865 [el, eventName, fn];
1869 var wrappedFn = function(e) {
1870 return fn(Roo.lib.Event.getEvent(e));
1873 var li = [el, eventName, fn, wrappedFn];
1875 var index = listeners.length;
1876 listeners[index] = li;
1878 this.doAdd(el, eventName, wrappedFn, false);
1884 removeListener: function(el, eventName, fn) {
1887 el = Roo.getDom(el);
1890 return this.purgeElement(el, false, eventName);
1894 if ("unload" == eventName) {
1896 for (i = 0,len = unloadListeners.length; i < len; i++) {
1897 var li = unloadListeners[i];
1900 li[1] == eventName &&
1902 unloadListeners.splice(i, 1);
1910 var cacheItem = null;
1913 var index = arguments[3];
1915 if ("undefined" == typeof index) {
1916 index = this._getCacheIndex(el, eventName, fn);
1920 cacheItem = listeners[index];
1923 if (!el || !cacheItem) {
1927 this.doRemove(el, eventName, cacheItem[this.WFN], false);
1929 delete listeners[index][this.WFN];
1930 delete listeners[index][this.FN];
1931 listeners.splice(index, 1);
1938 getTarget: function(ev, resolveTextNode) {
1939 ev = ev.browserEvent || ev;
1940 var t = ev.target || ev.srcElement;
1941 return this.resolveTextNode(t);
1945 resolveTextNode: function(node) {
1946 if (Roo.isSafari && node && 3 == node.nodeType) {
1947 return node.parentNode;
1954 getPageX: function(ev) {
1955 ev = ev.browserEvent || ev;
1957 if (!x && 0 !== x) {
1958 x = ev.clientX || 0;
1961 x += this.getScroll()[1];
1969 getPageY: function(ev) {
1970 ev = ev.browserEvent || ev;
1972 if (!y && 0 !== y) {
1973 y = ev.clientY || 0;
1976 y += this.getScroll()[0];
1985 getXY: function(ev) {
1986 ev = ev.browserEvent || ev;
1987 return [this.getPageX(ev), this.getPageY(ev)];
1991 getRelatedTarget: function(ev) {
1992 ev = ev.browserEvent || ev;
1993 var t = ev.relatedTarget;
1995 if (ev.type == "mouseout") {
1997 } else if (ev.type == "mouseover") {
2002 return this.resolveTextNode(t);
2006 getTime: function(ev) {
2007 ev = ev.browserEvent || ev;
2009 var t = new Date().getTime();
2013 this.lastError = ex;
2022 stopEvent: function(ev) {
2023 this.stopPropagation(ev);
2024 this.preventDefault(ev);
2028 stopPropagation: function(ev) {
2029 ev = ev.browserEvent || ev;
2030 if (ev.stopPropagation) {
2031 ev.stopPropagation();
2033 ev.cancelBubble = true;
2038 preventDefault: function(ev) {
2039 ev = ev.browserEvent || ev;
2040 if(ev.preventDefault) {
2041 ev.preventDefault();
2043 ev.returnValue = false;
2048 getEvent: function(e) {
2049 var ev = e || window.event;
2051 var c = this.getEvent.caller;
2053 ev = c.arguments[0];
2054 if (ev && Event == ev.constructor) {
2064 getCharCode: function(ev) {
2065 ev = ev.browserEvent || ev;
2066 return ev.charCode || ev.keyCode || 0;
2070 _getCacheIndex: function(el, eventName, fn) {
2071 for (var i = 0,len = listeners.length; i < len; ++i) {
2072 var li = listeners[i];
2074 li[this.FN] == fn &&
2075 li[this.EL] == el &&
2076 li[this.TYPE] == eventName) {
2088 getEl: function(id) {
2089 return document.getElementById(id);
2093 clearCache: function() {
2097 _load: function(e) {
2098 loadComplete = true;
2099 var EU = Roo.lib.Event;
2103 EU.doRemove(window, "load", EU._load);
2108 _tryPreloadAttach: function() {
2117 var tryAgain = !loadComplete;
2119 tryAgain = (retryCount > 0);
2124 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2125 var item = onAvailStack[i];
2127 var el = this.getEl(item.id);
2130 if (!item.checkReady ||
2133 (document && document.body)) {
2136 if (item.override) {
2137 if (item.override === true) {
2140 scope = item.override;
2143 item.fn.call(scope, item.obj);
2144 onAvailStack[i] = null;
2147 notAvail.push(item);
2152 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2156 this.startInterval();
2158 clearInterval(this._interval);
2159 this._interval = null;
2162 this.locked = false;
2169 purgeElement: function(el, recurse, eventName) {
2170 var elListeners = this.getListeners(el, eventName);
2172 for (var i = 0,len = elListeners.length; i < len; ++i) {
2173 var l = elListeners[i];
2174 this.removeListener(el, l.type, l.fn);
2178 if (recurse && el && el.childNodes) {
2179 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2180 this.purgeElement(el.childNodes[i], recurse, eventName);
2186 getListeners: function(el, eventName) {
2187 var results = [], searchLists;
2189 searchLists = [listeners, unloadListeners];
2190 } else if (eventName == "unload") {
2191 searchLists = [unloadListeners];
2193 searchLists = [listeners];
2196 for (var j = 0; j < searchLists.length; ++j) {
2197 var searchList = searchLists[j];
2198 if (searchList && searchList.length > 0) {
2199 for (var i = 0,len = searchList.length; i < len; ++i) {
2200 var l = searchList[i];
2201 if (l && l[this.EL] === el &&
2202 (!eventName || eventName === l[this.TYPE])) {
2207 adjust: l[this.ADJ_SCOPE],
2215 return (results.length) ? results : null;
2219 _unload: function(e) {
2221 var EU = Roo.lib.Event, i, j, l, len, index;
2223 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2224 l = unloadListeners[i];
2227 if (l[EU.ADJ_SCOPE]) {
2228 if (l[EU.ADJ_SCOPE] === true) {
2231 scope = l[EU.ADJ_SCOPE];
2234 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2235 unloadListeners[i] = null;
2241 unloadListeners = null;
2243 if (listeners && listeners.length > 0) {
2244 j = listeners.length;
2247 l = listeners[index];
2249 EU.removeListener(l[EU.EL], l[EU.TYPE],
2259 EU.doRemove(window, "unload", EU._unload);
2264 getScroll: function() {
2265 var dd = document.documentElement, db = document.body;
2266 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2267 return [dd.scrollTop, dd.scrollLeft];
2269 return [db.scrollTop, db.scrollLeft];
2276 doAdd: function () {
2277 if (window.addEventListener) {
2278 return function(el, eventName, fn, capture) {
2279 el.addEventListener(eventName, fn, (capture));
2281 } else if (window.attachEvent) {
2282 return function(el, eventName, fn, capture) {
2283 el.attachEvent("on" + eventName, fn);
2292 doRemove: function() {
2293 if (window.removeEventListener) {
2294 return function (el, eventName, fn, capture) {
2295 el.removeEventListener(eventName, fn, (capture));
2297 } else if (window.detachEvent) {
2298 return function (el, eventName, fn) {
2299 el.detachEvent("on" + eventName, fn);
2311 var E = Roo.lib.Event;
2312 E.on = E.addListener;
2313 E.un = E.removeListener;
2315 if (document && document.body) {
2318 E.doAdd(window, "load", E._load);
2320 E.doAdd(window, "unload", E._unload);
2321 E._tryPreloadAttach();
2325 * Portions of this file are based on pieces of Yahoo User Interface Library
2326 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2327 * YUI licensed under the BSD License:
2328 * http://developer.yahoo.net/yui/license.txt
2329 * <script type="text/javascript">
2336 request : function(method, uri, cb, data, options) {
2338 var hs = options.headers;
2341 if(hs.hasOwnProperty(h)){
2342 this.initHeader(h, hs[h], false);
2346 if(options.xmlData){
2347 this.initHeader('Content-Type', 'text/xml', false);
2349 data = options.xmlData;
2353 return this.asyncRequest(method, uri, cb, data);
2356 serializeForm : function(form) {
2357 if(typeof form == 'string') {
2358 form = (document.getElementById(form) || document.forms[form]);
2361 var el, name, val, disabled, data = '', hasSubmit = false;
2362 for (var i = 0; i < form.elements.length; i++) {
2363 el = form.elements[i];
2364 disabled = form.elements[i].disabled;
2365 name = form.elements[i].name;
2366 val = form.elements[i].value;
2368 if (!disabled && name){
2372 case 'select-multiple':
2373 for (var j = 0; j < el.options.length; j++) {
2374 if (el.options[j].selected) {
2376 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2379 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2387 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2400 if(hasSubmit == false) {
2401 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2406 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2411 data = data.substr(0, data.length - 1);
2419 useDefaultHeader:true,
2421 defaultPostHeader:'application/x-www-form-urlencoded',
2423 useDefaultXhrHeader:true,
2425 defaultXhrHeader:'XMLHttpRequest',
2427 hasDefaultHeaders:true,
2439 setProgId:function(id)
2441 this.activeX.unshift(id);
2444 setDefaultPostHeader:function(b)
2446 this.useDefaultHeader = b;
2449 setDefaultXhrHeader:function(b)
2451 this.useDefaultXhrHeader = b;
2454 setPollingInterval:function(i)
2456 if (typeof i == 'number' && isFinite(i)) {
2457 this.pollInterval = i;
2461 createXhrObject:function(transactionId)
2467 http = new XMLHttpRequest();
2469 obj = { conn:http, tId:transactionId };
2473 for (var i = 0; i < this.activeX.length; ++i) {
2477 http = new ActiveXObject(this.activeX[i]);
2479 obj = { conn:http, tId:transactionId };
2492 getConnectionObject:function()
2495 var tId = this.transactionId;
2499 o = this.createXhrObject(tId);
2501 this.transactionId++;
2512 asyncRequest:function(method, uri, callback, postData)
2514 var o = this.getConnectionObject();
2520 o.conn.open(method, uri, true);
2522 if (this.useDefaultXhrHeader) {
2523 if (!this.defaultHeaders['X-Requested-With']) {
2524 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2528 if(postData && this.useDefaultHeader){
2529 this.initHeader('Content-Type', this.defaultPostHeader);
2532 if (this.hasDefaultHeaders || this.hasHeaders) {
2536 this.handleReadyState(o, callback);
2537 o.conn.send(postData || null);
2543 handleReadyState:function(o, callback)
2547 if (callback && callback.timeout) {
2548 this.timeout[o.tId] = window.setTimeout(function() {
2549 oConn.abort(o, callback, true);
2550 }, callback.timeout);
2553 this.poll[o.tId] = window.setInterval(
2555 if (o.conn && o.conn.readyState == 4) {
2556 window.clearInterval(oConn.poll[o.tId]);
2557 delete oConn.poll[o.tId];
2559 if(callback && callback.timeout) {
2560 window.clearTimeout(oConn.timeout[o.tId]);
2561 delete oConn.timeout[o.tId];
2564 oConn.handleTransactionResponse(o, callback);
2567 , this.pollInterval);
2570 handleTransactionResponse:function(o, callback, isAbort)
2574 this.releaseObject(o);
2578 var httpStatus, responseObject;
2582 if (o.conn.status !== undefined && o.conn.status != 0) {
2583 httpStatus = o.conn.status;
2595 if (httpStatus >= 200 && httpStatus < 300) {
2596 responseObject = this.createResponseObject(o, callback.argument);
2597 if (callback.success) {
2598 if (!callback.scope) {
2599 callback.success(responseObject);
2604 callback.success.apply(callback.scope, [responseObject]);
2609 switch (httpStatus) {
2617 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2618 if (callback.failure) {
2619 if (!callback.scope) {
2620 callback.failure(responseObject);
2623 callback.failure.apply(callback.scope, [responseObject]);
2628 responseObject = this.createResponseObject(o, callback.argument);
2629 if (callback.failure) {
2630 if (!callback.scope) {
2631 callback.failure(responseObject);
2634 callback.failure.apply(callback.scope, [responseObject]);
2640 this.releaseObject(o);
2641 responseObject = null;
2644 createResponseObject:function(o, callbackArg)
2651 var headerStr = o.conn.getAllResponseHeaders();
2652 var header = headerStr.split('\n');
2653 for (var i = 0; i < header.length; i++) {
2654 var delimitPos = header[i].indexOf(':');
2655 if (delimitPos != -1) {
2656 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2664 obj.status = o.conn.status;
2665 obj.statusText = o.conn.statusText;
2666 obj.getResponseHeader = headerObj;
2667 obj.getAllResponseHeaders = headerStr;
2668 obj.responseText = o.conn.responseText;
2669 obj.responseXML = o.conn.responseXML;
2671 if (typeof callbackArg !== undefined) {
2672 obj.argument = callbackArg;
2678 createExceptionObject:function(tId, callbackArg, isAbort)
2681 var COMM_ERROR = 'communication failure';
2682 var ABORT_CODE = -1;
2683 var ABORT_ERROR = 'transaction aborted';
2689 obj.status = ABORT_CODE;
2690 obj.statusText = ABORT_ERROR;
2693 obj.status = COMM_CODE;
2694 obj.statusText = COMM_ERROR;
2698 obj.argument = callbackArg;
2704 initHeader:function(label, value, isDefault)
2706 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2708 if (headerObj[label] === undefined) {
2709 headerObj[label] = value;
2714 headerObj[label] = value + "," + headerObj[label];
2718 this.hasDefaultHeaders = true;
2721 this.hasHeaders = true;
2726 setHeader:function(o)
2728 if (this.hasDefaultHeaders) {
2729 for (var prop in this.defaultHeaders) {
2730 if (this.defaultHeaders.hasOwnProperty(prop)) {
2731 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2736 if (this.hasHeaders) {
2737 for (var prop in this.headers) {
2738 if (this.headers.hasOwnProperty(prop)) {
2739 o.conn.setRequestHeader(prop, this.headers[prop]);
2743 this.hasHeaders = false;
2747 resetDefaultHeaders:function() {
2748 delete this.defaultHeaders;
2749 this.defaultHeaders = {};
2750 this.hasDefaultHeaders = false;
2753 abort:function(o, callback, isTimeout)
2755 if(this.isCallInProgress(o)) {
2757 window.clearInterval(this.poll[o.tId]);
2758 delete this.poll[o.tId];
2760 delete this.timeout[o.tId];
2763 this.handleTransactionResponse(o, callback, true);
2773 isCallInProgress:function(o)
2776 return o.conn.readyState != 4 && o.conn.readyState != 0;
2785 releaseObject:function(o)
2794 'MSXML2.XMLHTTP.3.0',
2802 * Portions of this file are based on pieces of Yahoo User Interface Library
2803 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2804 * YUI licensed under the BSD License:
2805 * http://developer.yahoo.net/yui/license.txt
2806 * <script type="text/javascript">
2810 Roo.lib.Region = function(t, r, b, l) {
2820 Roo.lib.Region.prototype = {
2821 contains : function(region) {
2822 return ( region.left >= this.left &&
2823 region.right <= this.right &&
2824 region.top >= this.top &&
2825 region.bottom <= this.bottom );
2829 getArea : function() {
2830 return ( (this.bottom - this.top) * (this.right - this.left) );
2833 intersect : function(region) {
2834 var t = Math.max(this.top, region.top);
2835 var r = Math.min(this.right, region.right);
2836 var b = Math.min(this.bottom, region.bottom);
2837 var l = Math.max(this.left, region.left);
2839 if (b >= t && r >= l) {
2840 return new Roo.lib.Region(t, r, b, l);
2845 union : function(region) {
2846 var t = Math.min(this.top, region.top);
2847 var r = Math.max(this.right, region.right);
2848 var b = Math.max(this.bottom, region.bottom);
2849 var l = Math.min(this.left, region.left);
2851 return new Roo.lib.Region(t, r, b, l);
2854 adjust : function(t, l, b, r) {
2863 Roo.lib.Region.getRegion = function(el) {
2864 var p = Roo.lib.Dom.getXY(el);
2867 var r = p[0] + el.offsetWidth;
2868 var b = p[1] + el.offsetHeight;
2871 return new Roo.lib.Region(t, r, b, l);
2874 * Portions of this file are based on pieces of Yahoo User Interface Library
2875 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2876 * YUI licensed under the BSD License:
2877 * http://developer.yahoo.net/yui/license.txt
2878 * <script type="text/javascript">
2881 //@@dep Roo.lib.Region
2884 Roo.lib.Point = function(x, y) {
2885 if (x instanceof Array) {
2889 this.x = this.right = this.left = this[0] = x;
2890 this.y = this.top = this.bottom = this[1] = y;
2893 Roo.lib.Point.prototype = new Roo.lib.Region();
2895 * Portions of this file are based on pieces of Yahoo User Interface Library
2896 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2897 * YUI licensed under the BSD License:
2898 * http://developer.yahoo.net/yui/license.txt
2899 * <script type="text/javascript">
2906 scroll : function(el, args, duration, easing, cb, scope) {
2907 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2910 motion : function(el, args, duration, easing, cb, scope) {
2911 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2914 color : function(el, args, duration, easing, cb, scope) {
2915 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2918 run : function(el, args, duration, easing, cb, scope, type) {
2919 type = type || Roo.lib.AnimBase;
2920 if (typeof easing == "string") {
2921 easing = Roo.lib.Easing[easing];
2923 var anim = new type(el, args, duration, easing);
2924 anim.animateX(function() {
2925 Roo.callback(cb, scope);
2931 * Portions of this file are based on pieces of Yahoo User Interface Library
2932 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2933 * YUI licensed under the BSD License:
2934 * http://developer.yahoo.net/yui/license.txt
2935 * <script type="text/javascript">
2943 if (!libFlyweight) {
2944 libFlyweight = new Roo.Element.Flyweight();
2946 libFlyweight.dom = el;
2947 return libFlyweight;
2950 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2954 Roo.lib.AnimBase = function(el, attributes, duration, method) {
2956 this.init(el, attributes, duration, method);
2960 Roo.lib.AnimBase.fly = fly;
2964 Roo.lib.AnimBase.prototype = {
2966 toString: function() {
2967 var el = this.getEl();
2968 var id = el.id || el.tagName;
2969 return ("Anim " + id);
2973 noNegatives: /width|height|opacity|padding/i,
2974 offsetAttribute: /^((width|height)|(top|left))$/,
2975 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
2976 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
2980 doMethod: function(attr, start, end) {
2981 return this.method(this.currentFrame, start, end - start, this.totalFrames);
2985 setAttribute: function(attr, val, unit) {
2986 if (this.patterns.noNegatives.test(attr)) {
2987 val = (val > 0) ? val : 0;
2990 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
2994 getAttribute: function(attr) {
2995 var el = this.getEl();
2996 var val = fly(el).getStyle(attr);
2998 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
2999 return parseFloat(val);
3002 var a = this.patterns.offsetAttribute.exec(attr) || [];
3003 var pos = !!( a[3] );
3004 var box = !!( a[2] );
3007 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3008 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3017 getDefaultUnit: function(attr) {
3018 if (this.patterns.defaultUnit.test(attr)) {
3025 animateX : function(callback, scope) {
3026 var f = function() {
3027 this.onComplete.removeListener(f);
3028 if (typeof callback == "function") {
3029 callback.call(scope || this, this);
3032 this.onComplete.addListener(f, this);
3037 setRuntimeAttribute: function(attr) {
3040 var attributes = this.attributes;
3042 this.runtimeAttributes[attr] = {};
3044 var isset = function(prop) {
3045 return (typeof prop !== 'undefined');
3048 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3052 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3055 if (isset(attributes[attr]['to'])) {
3056 end = attributes[attr]['to'];
3057 } else if (isset(attributes[attr]['by'])) {
3058 if (start.constructor == Array) {
3060 for (var i = 0, len = start.length; i < len; ++i) {
3061 end[i] = start[i] + attributes[attr]['by'][i];
3064 end = start + attributes[attr]['by'];
3068 this.runtimeAttributes[attr].start = start;
3069 this.runtimeAttributes[attr].end = end;
3072 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3076 init: function(el, attributes, duration, method) {
3078 var isAnimated = false;
3081 var startTime = null;
3084 var actualFrames = 0;
3087 el = Roo.getDom(el);
3090 this.attributes = attributes || {};
3093 this.duration = duration || 1;
3096 this.method = method || Roo.lib.Easing.easeNone;
3099 this.useSeconds = true;
3102 this.currentFrame = 0;
3105 this.totalFrames = Roo.lib.AnimMgr.fps;
3108 this.getEl = function() {
3113 this.isAnimated = function() {
3118 this.getStartTime = function() {
3122 this.runtimeAttributes = {};
3125 this.animate = function() {
3126 if (this.isAnimated()) {
3130 this.currentFrame = 0;
3132 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3134 Roo.lib.AnimMgr.registerElement(this);
3138 this.stop = function(finish) {
3140 this.currentFrame = this.totalFrames;
3141 this._onTween.fire();
3143 Roo.lib.AnimMgr.stop(this);
3146 var onStart = function() {
3147 this.onStart.fire();
3149 this.runtimeAttributes = {};
3150 for (var attr in this.attributes) {
3151 this.setRuntimeAttribute(attr);
3156 startTime = new Date();
3160 var onTween = function() {
3162 duration: new Date() - this.getStartTime(),
3163 currentFrame: this.currentFrame
3166 data.toString = function() {
3168 'duration: ' + data.duration +
3169 ', currentFrame: ' + data.currentFrame
3173 this.onTween.fire(data);
3175 var runtimeAttributes = this.runtimeAttributes;
3177 for (var attr in runtimeAttributes) {
3178 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3184 var onComplete = function() {
3185 var actual_duration = (new Date() - startTime) / 1000 ;
3188 duration: actual_duration,
3189 frames: actualFrames,
3190 fps: actualFrames / actual_duration
3193 data.toString = function() {
3195 'duration: ' + data.duration +
3196 ', frames: ' + data.frames +
3197 ', fps: ' + data.fps
3203 this.onComplete.fire(data);
3207 this._onStart = new Roo.util.Event(this);
3208 this.onStart = new Roo.util.Event(this);
3209 this.onTween = new Roo.util.Event(this);
3210 this._onTween = new Roo.util.Event(this);
3211 this.onComplete = new Roo.util.Event(this);
3212 this._onComplete = new Roo.util.Event(this);
3213 this._onStart.addListener(onStart);
3214 this._onTween.addListener(onTween);
3215 this._onComplete.addListener(onComplete);
3220 * Portions of this file are based on pieces of Yahoo User Interface Library
3221 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3222 * YUI licensed under the BSD License:
3223 * http://developer.yahoo.net/yui/license.txt
3224 * <script type="text/javascript">
3228 Roo.lib.AnimMgr = new function() {
3245 this.registerElement = function(tween) {
3246 queue[queue.length] = tween;
3248 tween._onStart.fire();
3253 this.unRegister = function(tween, index) {
3254 tween._onComplete.fire();
3255 index = index || getIndex(tween);
3257 queue.splice(index, 1);
3261 if (tweenCount <= 0) {
3267 this.start = function() {
3268 if (thread === null) {
3269 thread = setInterval(this.run, this.delay);
3274 this.stop = function(tween) {
3276 clearInterval(thread);
3278 for (var i = 0, len = queue.length; i < len; ++i) {
3279 if (queue[0].isAnimated()) {
3280 this.unRegister(queue[0], 0);
3289 this.unRegister(tween);
3294 this.run = function() {
3295 for (var i = 0, len = queue.length; i < len; ++i) {
3296 var tween = queue[i];
3297 if (!tween || !tween.isAnimated()) {
3301 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3303 tween.currentFrame += 1;
3305 if (tween.useSeconds) {
3306 correctFrame(tween);
3308 tween._onTween.fire();
3311 Roo.lib.AnimMgr.stop(tween, i);
3316 var getIndex = function(anim) {
3317 for (var i = 0, len = queue.length; i < len; ++i) {
3318 if (queue[i] == anim) {
3326 var correctFrame = function(tween) {
3327 var frames = tween.totalFrames;
3328 var frame = tween.currentFrame;
3329 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3330 var elapsed = (new Date() - tween.getStartTime());
3333 if (elapsed < tween.duration * 1000) {
3334 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3336 tweak = frames - (frame + 1);
3338 if (tweak > 0 && isFinite(tweak)) {
3339 if (tween.currentFrame + tweak >= frames) {
3340 tweak = frames - (frame + 1);
3343 tween.currentFrame += tweak;
3347 * Portions of this file are based on pieces of Yahoo User Interface Library
3348 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3349 * YUI licensed under the BSD License:
3350 * http://developer.yahoo.net/yui/license.txt
3351 * <script type="text/javascript">
3354 Roo.lib.Bezier = new function() {
3356 this.getPosition = function(points, t) {
3357 var n = points.length;
3360 for (var i = 0; i < n; ++i) {
3361 tmp[i] = [points[i][0], points[i][1]];
3364 for (var j = 1; j < n; ++j) {
3365 for (i = 0; i < n - j; ++i) {
3366 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3367 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3371 return [ tmp[0][0], tmp[0][1] ];
3375 * Portions of this file are based on pieces of Yahoo User Interface Library
3376 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3377 * YUI licensed under the BSD License:
3378 * http://developer.yahoo.net/yui/license.txt
3379 * <script type="text/javascript">
3384 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3385 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3388 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3390 var fly = Roo.lib.AnimBase.fly;
3392 var superclass = Y.ColorAnim.superclass;
3393 var proto = Y.ColorAnim.prototype;
3395 proto.toString = function() {
3396 var el = this.getEl();
3397 var id = el.id || el.tagName;
3398 return ("ColorAnim " + id);
3401 proto.patterns.color = /color$/i;
3402 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3403 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3404 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3405 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3408 proto.parseColor = function(s) {
3409 if (s.length == 3) {
3413 var c = this.patterns.hex.exec(s);
3414 if (c && c.length == 4) {
3415 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3418 c = this.patterns.rgb.exec(s);
3419 if (c && c.length == 4) {
3420 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3423 c = this.patterns.hex3.exec(s);
3424 if (c && c.length == 4) {
3425 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3430 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3431 proto.getAttribute = function(attr) {
3432 var el = this.getEl();
3433 if (this.patterns.color.test(attr)) {
3434 var val = fly(el).getStyle(attr);
3436 if (this.patterns.transparent.test(val)) {
3437 var parent = el.parentNode;
3438 val = fly(parent).getStyle(attr);
3440 while (parent && this.patterns.transparent.test(val)) {
3441 parent = parent.parentNode;
3442 val = fly(parent).getStyle(attr);
3443 if (parent.tagName.toUpperCase() == 'HTML') {
3449 val = superclass.getAttribute.call(this, attr);
3454 proto.getAttribute = function(attr) {
3455 var el = this.getEl();
3456 if (this.patterns.color.test(attr)) {
3457 var val = fly(el).getStyle(attr);
3459 if (this.patterns.transparent.test(val)) {
3460 var parent = el.parentNode;
3461 val = fly(parent).getStyle(attr);
3463 while (parent && this.patterns.transparent.test(val)) {
3464 parent = parent.parentNode;
3465 val = fly(parent).getStyle(attr);
3466 if (parent.tagName.toUpperCase() == 'HTML') {
3472 val = superclass.getAttribute.call(this, attr);
3478 proto.doMethod = function(attr, start, end) {
3481 if (this.patterns.color.test(attr)) {
3483 for (var i = 0, len = start.length; i < len; ++i) {
3484 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3487 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3490 val = superclass.doMethod.call(this, attr, start, end);
3496 proto.setRuntimeAttribute = function(attr) {
3497 superclass.setRuntimeAttribute.call(this, attr);
3499 if (this.patterns.color.test(attr)) {
3500 var attributes = this.attributes;
3501 var start = this.parseColor(this.runtimeAttributes[attr].start);
3502 var end = this.parseColor(this.runtimeAttributes[attr].end);
3504 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3505 end = this.parseColor(attributes[attr].by);
3507 for (var i = 0, len = start.length; i < len; ++i) {
3508 end[i] = start[i] + end[i];
3512 this.runtimeAttributes[attr].start = start;
3513 this.runtimeAttributes[attr].end = end;
3519 * Portions of this file are based on pieces of Yahoo User Interface Library
3520 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3521 * YUI licensed under the BSD License:
3522 * http://developer.yahoo.net/yui/license.txt
3523 * <script type="text/javascript">
3529 easeNone: function (t, b, c, d) {
3530 return c * t / d + b;
3534 easeIn: function (t, b, c, d) {
3535 return c * (t /= d) * t + b;
3539 easeOut: function (t, b, c, d) {
3540 return -c * (t /= d) * (t - 2) + b;
3544 easeBoth: function (t, b, c, d) {
3545 if ((t /= d / 2) < 1) {
3546 return c / 2 * t * t + b;
3549 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3553 easeInStrong: function (t, b, c, d) {
3554 return c * (t /= d) * t * t * t + b;
3558 easeOutStrong: function (t, b, c, d) {
3559 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3563 easeBothStrong: function (t, b, c, d) {
3564 if ((t /= d / 2) < 1) {
3565 return c / 2 * t * t * t * t + b;
3568 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3573 elasticIn: function (t, b, c, d, a, p) {
3577 if ((t /= d) == 1) {
3584 if (!a || a < Math.abs(c)) {
3589 var s = p / (2 * Math.PI) * Math.asin(c / a);
3592 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3596 elasticOut: function (t, b, c, d, a, p) {
3600 if ((t /= d) == 1) {
3607 if (!a || a < Math.abs(c)) {
3612 var s = p / (2 * Math.PI) * Math.asin(c / a);
3615 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3619 elasticBoth: function (t, b, c, d, a, p) {
3624 if ((t /= d / 2) == 2) {
3632 if (!a || a < Math.abs(c)) {
3637 var s = p / (2 * Math.PI) * Math.asin(c / a);
3641 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3642 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3644 return a * Math.pow(2, -10 * (t -= 1)) *
3645 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3650 backIn: function (t, b, c, d, s) {
3651 if (typeof s == 'undefined') {
3654 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3658 backOut: function (t, b, c, d, s) {
3659 if (typeof s == 'undefined') {
3662 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3666 backBoth: function (t, b, c, d, s) {
3667 if (typeof s == 'undefined') {
3671 if ((t /= d / 2 ) < 1) {
3672 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3674 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3678 bounceIn: function (t, b, c, d) {
3679 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3683 bounceOut: function (t, b, c, d) {
3684 if ((t /= d) < (1 / 2.75)) {
3685 return c * (7.5625 * t * t) + b;
3686 } else if (t < (2 / 2.75)) {
3687 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3688 } else if (t < (2.5 / 2.75)) {
3689 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3691 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3695 bounceBoth: function (t, b, c, d) {
3697 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3699 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3702 * Portions of this file are based on pieces of Yahoo User Interface Library
3703 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3704 * YUI licensed under the BSD License:
3705 * http://developer.yahoo.net/yui/license.txt
3706 * <script type="text/javascript">
3710 Roo.lib.Motion = function(el, attributes, duration, method) {
3712 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3716 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3720 var superclass = Y.Motion.superclass;
3721 var proto = Y.Motion.prototype;
3723 proto.toString = function() {
3724 var el = this.getEl();
3725 var id = el.id || el.tagName;
3726 return ("Motion " + id);
3729 proto.patterns.points = /^points$/i;
3731 proto.setAttribute = function(attr, val, unit) {
3732 if (this.patterns.points.test(attr)) {
3733 unit = unit || 'px';
3734 superclass.setAttribute.call(this, 'left', val[0], unit);
3735 superclass.setAttribute.call(this, 'top', val[1], unit);
3737 superclass.setAttribute.call(this, attr, val, unit);
3741 proto.getAttribute = function(attr) {
3742 if (this.patterns.points.test(attr)) {
3744 superclass.getAttribute.call(this, 'left'),
3745 superclass.getAttribute.call(this, 'top')
3748 val = superclass.getAttribute.call(this, attr);
3754 proto.doMethod = function(attr, start, end) {
3757 if (this.patterns.points.test(attr)) {
3758 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3759 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3761 val = superclass.doMethod.call(this, attr, start, end);
3766 proto.setRuntimeAttribute = function(attr) {
3767 if (this.patterns.points.test(attr)) {
3768 var el = this.getEl();
3769 var attributes = this.attributes;
3771 var control = attributes['points']['control'] || [];
3775 if (control.length > 0 && !(control[0] instanceof Array)) {
3776 control = [control];
3779 for (i = 0,len = control.length; i < len; ++i) {
3780 tmp[i] = control[i];
3785 Roo.fly(el).position();
3787 if (isset(attributes['points']['from'])) {
3788 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3791 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3794 start = this.getAttribute('points');
3797 if (isset(attributes['points']['to'])) {
3798 end = translateValues.call(this, attributes['points']['to'], start);
3800 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3801 for (i = 0,len = control.length; i < len; ++i) {
3802 control[i] = translateValues.call(this, control[i], start);
3806 } else if (isset(attributes['points']['by'])) {
3807 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3809 for (i = 0,len = control.length; i < len; ++i) {
3810 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3814 this.runtimeAttributes[attr] = [start];
3816 if (control.length > 0) {
3817 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3820 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3823 superclass.setRuntimeAttribute.call(this, attr);
3827 var translateValues = function(val, start) {
3828 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3829 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3834 var isset = function(prop) {
3835 return (typeof prop !== 'undefined');
3839 * Portions of this file are based on pieces of Yahoo User Interface Library
3840 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3841 * YUI licensed under the BSD License:
3842 * http://developer.yahoo.net/yui/license.txt
3843 * <script type="text/javascript">
3847 Roo.lib.Scroll = function(el, attributes, duration, method) {
3849 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3853 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3857 var superclass = Y.Scroll.superclass;
3858 var proto = Y.Scroll.prototype;
3860 proto.toString = function() {
3861 var el = this.getEl();
3862 var id = el.id || el.tagName;
3863 return ("Scroll " + id);
3866 proto.doMethod = function(attr, start, end) {
3869 if (attr == 'scroll') {
3871 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3872 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3876 val = superclass.doMethod.call(this, attr, start, end);
3881 proto.getAttribute = function(attr) {
3883 var el = this.getEl();
3885 if (attr == 'scroll') {
3886 val = [ el.scrollLeft, el.scrollTop ];
3888 val = superclass.getAttribute.call(this, attr);
3894 proto.setAttribute = function(attr, val, unit) {
3895 var el = this.getEl();
3897 if (attr == 'scroll') {
3898 el.scrollLeft = val[0];
3899 el.scrollTop = val[1];
3901 superclass.setAttribute.call(this, attr, val, unit);
3907 * Ext JS Library 1.1.1
3908 * Copyright(c) 2006-2007, Ext JS, LLC.
3910 * Originally Released Under LGPL - original licence link has changed is not relivant.
3913 * <script type="text/javascript">
3918 * @class Roo.DomHelper
3919 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3920 * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
3923 Roo.DomHelper = function(){
3924 var tempTableEl = null;
3925 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3926 var tableRe = /^table|tbody|tr|td$/i;
3928 // build as innerHTML where available
3930 var createHtml = function(o){
3931 if(typeof o == 'string'){
3940 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3941 if(attr == "style"){
3943 if(typeof s == "function"){
3946 if(typeof s == "string"){
3947 b += ' style="' + s + '"';
3948 }else if(typeof s == "object"){
3951 if(typeof s[key] != "function"){
3952 b += key + ":" + s[key] + ";";
3959 b += ' class="' + o["cls"] + '"';
3960 }else if(attr == "htmlFor"){
3961 b += ' for="' + o["htmlFor"] + '"';
3963 b += " " + attr + '="' + o[attr] + '"';
3967 if(emptyTags.test(o.tag)){
3971 var cn = o.children || o.cn;
3973 //http://bugs.kde.org/show_bug.cgi?id=71506
3974 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
3975 for(var i = 0, len = cn.length; i < len; i++) {
3976 b += createHtml(cn[i], b);
3979 b += createHtml(cn, b);
3985 b += "</" + o.tag + ">";
3992 var createDom = function(o, parentNode){
3994 // defininition craeted..
3996 if (o.ns && o.ns != 'html') {
3998 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
3999 xmlns[o.ns] = o.xmlns;
4002 if (typeof(xmlns[o.ns]) == 'undefined') {
4003 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4009 if (typeof(o) == 'string') {
4010 return parentNode.appendChild(document.createTextNode(o));
4012 o.tag = o.tag || div;
4013 if (o.ns && Roo.isIE) {
4015 o.tag = o.ns + ':' + o.tag;
4018 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4019 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4022 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4023 attr == "style" || typeof o[attr] == "function") continue;
4025 if(attr=="cls" && Roo.isIE){
4026 el.className = o["cls"];
4028 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4029 else el[attr] = o[attr];
4032 Roo.DomHelper.applyStyles(el, o.style);
4033 var cn = o.children || o.cn;
4035 //http://bugs.kde.org/show_bug.cgi?id=71506
4036 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4037 for(var i = 0, len = cn.length; i < len; i++) {
4038 createDom(cn[i], el);
4045 el.innerHTML = o.html;
4048 parentNode.appendChild(el);
4053 var ieTable = function(depth, s, h, e){
4054 tempTableEl.innerHTML = [s, h, e].join('');
4055 var i = -1, el = tempTableEl;
4062 // kill repeat to save bytes
4066 tbe = '</tbody>'+te,
4072 * Nasty code for IE's broken table implementation
4074 var insertIntoTable = function(tag, where, el, html){
4076 tempTableEl = document.createElement('div');
4081 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4084 if(where == 'beforebegin'){
4088 before = el.nextSibling;
4091 node = ieTable(4, trs, html, tre);
4093 else if(tag == 'tr'){
4094 if(where == 'beforebegin'){
4097 node = ieTable(3, tbs, html, tbe);
4098 } else if(where == 'afterend'){
4099 before = el.nextSibling;
4101 node = ieTable(3, tbs, html, tbe);
4102 } else{ // INTO a TR
4103 if(where == 'afterbegin'){
4104 before = el.firstChild;
4106 node = ieTable(4, trs, html, tre);
4108 } else if(tag == 'tbody'){
4109 if(where == 'beforebegin'){
4112 node = ieTable(2, ts, html, te);
4113 } else if(where == 'afterend'){
4114 before = el.nextSibling;
4116 node = ieTable(2, ts, html, te);
4118 if(where == 'afterbegin'){
4119 before = el.firstChild;
4121 node = ieTable(3, tbs, html, tbe);
4124 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4127 if(where == 'afterbegin'){
4128 before = el.firstChild;
4130 node = ieTable(2, ts, html, te);
4132 el.insertBefore(node, before);
4137 /** True to force the use of DOM instead of html fragments @type Boolean */
4141 * Returns the markup for the passed Element(s) config
4142 * @param {Object} o The Dom object spec (and children)
4145 markup : function(o){
4146 return createHtml(o);
4150 * Applies a style specification to an element
4151 * @param {String/HTMLElement} el The element to apply styles to
4152 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4153 * a function which returns such a specification.
4155 applyStyles : function(el, styles){
4158 if(typeof styles == "string"){
4159 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4161 while ((matches = re.exec(styles)) != null){
4162 el.setStyle(matches[1], matches[2]);
4164 }else if (typeof styles == "object"){
4165 for (var style in styles){
4166 el.setStyle(style, styles[style]);
4168 }else if (typeof styles == "function"){
4169 Roo.DomHelper.applyStyles(el, styles.call());
4175 * Inserts an HTML fragment into the Dom
4176 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4177 * @param {HTMLElement} el The context element
4178 * @param {String} html The HTML fragmenet
4179 * @return {HTMLElement} The new node
4181 insertHtml : function(where, el, html){
4182 where = where.toLowerCase();
4183 if(el.insertAdjacentHTML){
4184 if(tableRe.test(el.tagName)){
4186 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4192 el.insertAdjacentHTML('BeforeBegin', html);
4193 return el.previousSibling;
4195 el.insertAdjacentHTML('AfterBegin', html);
4196 return el.firstChild;
4198 el.insertAdjacentHTML('BeforeEnd', html);
4199 return el.lastChild;
4201 el.insertAdjacentHTML('AfterEnd', html);
4202 return el.nextSibling;
4204 throw 'Illegal insertion point -> "' + where + '"';
4206 var range = el.ownerDocument.createRange();
4210 range.setStartBefore(el);
4211 frag = range.createContextualFragment(html);
4212 el.parentNode.insertBefore(frag, el);
4213 return el.previousSibling;
4216 range.setStartBefore(el.firstChild);
4217 frag = range.createContextualFragment(html);
4218 el.insertBefore(frag, el.firstChild);
4219 return el.firstChild;
4221 el.innerHTML = html;
4222 return el.firstChild;
4226 range.setStartAfter(el.lastChild);
4227 frag = range.createContextualFragment(html);
4228 el.appendChild(frag);
4229 return el.lastChild;
4231 el.innerHTML = html;
4232 return el.lastChild;
4235 range.setStartAfter(el);
4236 frag = range.createContextualFragment(html);
4237 el.parentNode.insertBefore(frag, el.nextSibling);
4238 return el.nextSibling;
4240 throw 'Illegal insertion point -> "' + where + '"';
4244 * Creates new Dom element(s) and inserts them before el
4245 * @param {String/HTMLElement/Element} el The context element
4246 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4247 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4248 * @return {HTMLElement/Roo.Element} The new node
4250 insertBefore : function(el, o, returnElement){
4251 return this.doInsert(el, o, returnElement, "beforeBegin");
4255 * Creates new Dom element(s) and inserts them after el
4256 * @param {String/HTMLElement/Element} el The context element
4257 * @param {Object} o The Dom object spec (and children)
4258 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4259 * @return {HTMLElement/Roo.Element} The new node
4261 insertAfter : function(el, o, returnElement){
4262 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4266 * Creates new Dom element(s) and inserts them as the first child of el
4267 * @param {String/HTMLElement/Element} el The context element
4268 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4269 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4270 * @return {HTMLElement/Roo.Element} The new node
4272 insertFirst : function(el, o, returnElement){
4273 return this.doInsert(el, o, returnElement, "afterBegin");
4277 doInsert : function(el, o, returnElement, pos, sibling){
4278 el = Roo.getDom(el);
4280 if(this.useDom || o.ns){
4281 newNode = createDom(o, null);
4282 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4284 var html = createHtml(o);
4285 newNode = this.insertHtml(pos, el, html);
4287 return returnElement ? Roo.get(newNode, true) : newNode;
4291 * Creates new Dom element(s) and appends them to el
4292 * @param {String/HTMLElement/Element} el The context element
4293 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4294 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4295 * @return {HTMLElement/Roo.Element} The new node
4297 append : function(el, o, returnElement){
4298 el = Roo.getDom(el);
4300 if(this.useDom || o.ns){
4301 newNode = createDom(o, null);
4302 el.appendChild(newNode);
4304 var html = createHtml(o);
4305 newNode = this.insertHtml("beforeEnd", el, html);
4307 return returnElement ? Roo.get(newNode, true) : newNode;
4311 * Creates new Dom element(s) and overwrites the contents of el with them
4312 * @param {String/HTMLElement/Element} el The context element
4313 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4314 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4315 * @return {HTMLElement/Roo.Element} The new node
4317 overwrite : function(el, o, returnElement){
4318 el = Roo.getDom(el);
4321 while (el.childNodes.length) {
4322 el.removeChild(el.firstChild);
4326 el.innerHTML = createHtml(o);
4329 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4333 * Creates a new Roo.DomHelper.Template from the Dom object spec
4334 * @param {Object} o The Dom object spec (and children)
4335 * @return {Roo.DomHelper.Template} The new template
4337 createTemplate : function(o){
4338 var html = createHtml(o);
4339 return new Roo.Template(html);
4345 * Ext JS Library 1.1.1
4346 * Copyright(c) 2006-2007, Ext JS, LLC.
4348 * Originally Released Under LGPL - original licence link has changed is not relivant.
4351 * <script type="text/javascript">
4355 * @class Roo.Template
4356 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4357 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4360 var t = new Roo.Template(
4361 '<div name="{id}">',
4362 '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
4365 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4367 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>.
4369 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4371 Roo.Template = function(html){
4372 if(html instanceof Array){
4373 html = html.join("");
4374 }else if(arguments.length > 1){
4375 html = Array.prototype.join.call(arguments, "");
4381 Roo.Template.prototype = {
4383 * Returns an HTML fragment of this template with the specified values applied.
4384 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4385 * @return {String} The HTML fragment
4387 applyTemplate : function(values){
4389 return this.compiled(values);
4391 var useF = this.disableFormats !== true;
4392 var fm = Roo.util.Format, tpl = this;
4393 var fn = function(m, name, format, args){
4395 if(format.substr(0, 5) == "this."){
4396 return tpl.call(format.substr(5), values[name], values);
4399 // quoted values are required for strings in compiled templates,
4400 // but for non compiled we need to strip them
4401 // quoted reversed for jsmin
4402 var re = /^\s*['"](.*)["']\s*$/;
4403 args = args.split(',');
4404 for(var i = 0, len = args.length; i < len; i++){
4405 args[i] = args[i].replace(re, "$1");
4407 args = [values[name]].concat(args);
4409 args = [values[name]];
4411 return fm[format].apply(fm, args);
4414 return values[name] !== undefined ? values[name] : "";
4417 return this.html.replace(this.re, fn);
4421 * Sets the HTML used as the template and optionally compiles it.
4422 * @param {String} html
4423 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4424 * @return {Roo.Template} this
4426 set : function(html, compile){
4428 this.compiled = null;
4436 * True to disable format functions (defaults to false)
4439 disableFormats : false,
4442 * The regular expression used to match template variables
4446 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4449 * Compiles the template into an internal function, eliminating the RegEx overhead.
4450 * @return {Roo.Template} this
4452 compile : function(){
4453 var fm = Roo.util.Format;
4454 var useF = this.disableFormats !== true;
4455 var sep = Roo.isGecko ? "+" : ",";
4456 var fn = function(m, name, format, args){
4458 args = args ? ',' + args : "";
4459 if(format.substr(0, 5) != "this."){
4460 format = "fm." + format + '(';
4462 format = 'this.call("'+ format.substr(5) + '", ';
4466 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4468 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4471 // branched to use + in gecko and [].join() in others
4473 body = "this.compiled = function(values){ return '" +
4474 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4477 body = ["this.compiled = function(values){ return ['"];
4478 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4479 body.push("'].join('');};");
4480 body = body.join('');
4490 // private function used to call members
4491 call : function(fnName, value, allValues){
4492 return this[fnName](value, allValues);
4496 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4497 * @param {String/HTMLElement/Roo.Element} el The context element
4498 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4499 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4500 * @return {HTMLElement/Roo.Element} The new node or Element
4502 insertFirst: function(el, values, returnElement){
4503 return this.doInsert('afterBegin', el, values, returnElement);
4507 * Applies the supplied values to the template and inserts the new node(s) before el.
4508 * @param {String/HTMLElement/Roo.Element} el The context element
4509 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4510 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4511 * @return {HTMLElement/Roo.Element} The new node or Element
4513 insertBefore: function(el, values, returnElement){
4514 return this.doInsert('beforeBegin', el, values, returnElement);
4518 * Applies the supplied values to the template and inserts the new node(s) after el.
4519 * @param {String/HTMLElement/Roo.Element} el The context element
4520 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4521 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4522 * @return {HTMLElement/Roo.Element} The new node or Element
4524 insertAfter : function(el, values, returnElement){
4525 return this.doInsert('afterEnd', el, values, returnElement);
4529 * Applies the supplied values to the template and appends the new node(s) to el.
4530 * @param {String/HTMLElement/Roo.Element} el The context element
4531 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4532 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4533 * @return {HTMLElement/Roo.Element} The new node or Element
4535 append : function(el, values, returnElement){
4536 return this.doInsert('beforeEnd', el, values, returnElement);
4539 doInsert : function(where, el, values, returnEl){
4540 el = Roo.getDom(el);
4541 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4542 return returnEl ? Roo.get(newNode, true) : newNode;
4546 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4547 * @param {String/HTMLElement/Roo.Element} el The context element
4548 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4549 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4550 * @return {HTMLElement/Roo.Element} The new node or Element
4552 overwrite : function(el, values, returnElement){
4553 el = Roo.getDom(el);
4554 el.innerHTML = this.applyTemplate(values);
4555 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4559 * Alias for {@link #applyTemplate}
4562 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4565 Roo.DomHelper.Template = Roo.Template;
4568 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4569 * @param {String/HTMLElement} el A DOM element or its id
4570 * @returns {Roo.Template} The created template
4573 Roo.Template.from = function(el){
4574 el = Roo.getDom(el);
4575 return new Roo.Template(el.value || el.innerHTML);
4578 * Ext JS Library 1.1.1
4579 * Copyright(c) 2006-2007, Ext JS, LLC.
4581 * Originally Released Under LGPL - original licence link has changed is not relivant.
4584 * <script type="text/javascript">
4589 * This is code is also distributed under MIT license for use
4590 * with jQuery and prototype JavaScript libraries.
4593 * @class Roo.DomQuery
4594 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4596 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4599 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4601 <h4>Element Selectors:</h4>
4603 <li> <b>*</b> any element</li>
4604 <li> <b>E</b> an element with the tag E</li>
4605 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4606 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4607 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4608 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4610 <h4>Attribute Selectors:</h4>
4611 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4613 <li> <b>E[foo]</b> has an attribute "foo"</li>
4614 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4615 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4616 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4617 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4618 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4619 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4621 <h4>Pseudo Classes:</h4>
4623 <li> <b>E:first-child</b> E is the first child of its parent</li>
4624 <li> <b>E:last-child</b> E is the last child of its parent</li>
4625 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4626 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4627 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4628 <li> <b>E:only-child</b> E is the only child of its parent</li>
4629 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4630 <li> <b>E:first</b> the first E in the resultset</li>
4631 <li> <b>E:last</b> the last E in the resultset</li>
4632 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4633 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4634 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4635 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4636 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4637 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4638 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4639 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4640 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4642 <h4>CSS Value Selectors:</h4>
4644 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4645 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4646 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4647 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4648 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4649 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4653 Roo.DomQuery = function(){
4654 var cache = {}, simpleCache = {}, valueCache = {};
4655 var nonSpace = /\S/;
4656 var trimRe = /^\s+|\s+$/g;
4657 var tplRe = /\{(\d+)\}/g;
4658 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4659 var tagTokenRe = /^(#)?([\w-\*]+)/;
4660 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4662 function child(p, index){
4664 var n = p.firstChild;
4666 if(n.nodeType == 1){
4677 while((n = n.nextSibling) && n.nodeType != 1);
4682 while((n = n.previousSibling) && n.nodeType != 1);
4686 function children(d){
4687 var n = d.firstChild, ni = -1;
4689 var nx = n.nextSibling;
4690 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4700 function byClassName(c, a, v){
4704 var r = [], ri = -1, cn;
4705 for(var i = 0, ci; ci = c[i]; i++){
4706 if((' '+ci.className+' ').indexOf(v) != -1){
4713 function attrValue(n, attr){
4714 if(!n.tagName && typeof n.length != "undefined"){
4723 if(attr == "class" || attr == "className"){
4726 return n.getAttribute(attr) || n[attr];
4730 function getNodes(ns, mode, tagName){
4731 var result = [], ri = -1, cs;
4735 tagName = tagName || "*";
4736 if(typeof ns.getElementsByTagName != "undefined"){
4740 for(var i = 0, ni; ni = ns[i]; i++){
4741 cs = ni.getElementsByTagName(tagName);
4742 for(var j = 0, ci; ci = cs[j]; j++){
4746 }else if(mode == "/" || mode == ">"){
4747 var utag = tagName.toUpperCase();
4748 for(var i = 0, ni, cn; ni = ns[i]; i++){
4749 cn = ni.children || ni.childNodes;
4750 for(var j = 0, cj; cj = cn[j]; j++){
4751 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4756 }else if(mode == "+"){
4757 var utag = tagName.toUpperCase();
4758 for(var i = 0, n; n = ns[i]; i++){
4759 while((n = n.nextSibling) && n.nodeType != 1);
4760 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4764 }else if(mode == "~"){
4765 for(var i = 0, n; n = ns[i]; i++){
4766 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4775 function concat(a, b){
4779 for(var i = 0, l = b.length; i < l; i++){
4785 function byTag(cs, tagName){
4786 if(cs.tagName || cs == document){
4792 var r = [], ri = -1;
4793 tagName = tagName.toLowerCase();
4794 for(var i = 0, ci; ci = cs[i]; i++){
4795 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4802 function byId(cs, attr, id){
4803 if(cs.tagName || cs == document){
4809 var r = [], ri = -1;
4810 for(var i = 0,ci; ci = cs[i]; i++){
4811 if(ci && ci.id == id){
4819 function byAttribute(cs, attr, value, op, custom){
4820 var r = [], ri = -1, st = custom=="{";
4821 var f = Roo.DomQuery.operators[op];
4822 for(var i = 0, ci; ci = cs[i]; i++){
4825 a = Roo.DomQuery.getStyle(ci, attr);
4827 else if(attr == "class" || attr == "className"){
4829 }else if(attr == "for"){
4831 }else if(attr == "href"){
4832 a = ci.getAttribute("href", 2);
4834 a = ci.getAttribute(attr);
4836 if((f && f(a, value)) || (!f && a)){
4843 function byPseudo(cs, name, value){
4844 return Roo.DomQuery.pseudos[name](cs, value);
4847 // This is for IE MSXML which does not support expandos.
4848 // IE runs the same speed using setAttribute, however FF slows way down
4849 // and Safari completely fails so they need to continue to use expandos.
4850 var isIE = window.ActiveXObject ? true : false;
4852 // this eval is stop the compressor from
4853 // renaming the variable to something shorter
4855 /** eval:var:batch */
4860 function nodupIEXml(cs){
4862 cs[0].setAttribute("_nodup", d);
4864 for(var i = 1, len = cs.length; i < len; i++){
4866 if(!c.getAttribute("_nodup") != d){
4867 c.setAttribute("_nodup", d);
4871 for(var i = 0, len = cs.length; i < len; i++){
4872 cs[i].removeAttribute("_nodup");
4881 var len = cs.length, c, i, r = cs, cj, ri = -1;
4882 if(!len || typeof cs.nodeType != "undefined" || len == 1){
4885 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4886 return nodupIEXml(cs);
4890 for(i = 1; c = cs[i]; i++){
4895 for(var j = 0; j < i; j++){
4898 for(j = i+1; cj = cs[j]; j++){
4910 function quickDiffIEXml(c1, c2){
4912 for(var i = 0, len = c1.length; i < len; i++){
4913 c1[i].setAttribute("_qdiff", d);
4916 for(var i = 0, len = c2.length; i < len; i++){
4917 if(c2[i].getAttribute("_qdiff") != d){
4918 r[r.length] = c2[i];
4921 for(var i = 0, len = c1.length; i < len; i++){
4922 c1[i].removeAttribute("_qdiff");
4927 function quickDiff(c1, c2){
4928 var len1 = c1.length;
4932 if(isIE && c1[0].selectSingleNode){
4933 return quickDiffIEXml(c1, c2);
4936 for(var i = 0; i < len1; i++){
4940 for(var i = 0, len = c2.length; i < len; i++){
4941 if(c2[i]._qdiff != d){
4942 r[r.length] = c2[i];
4948 function quickId(ns, mode, root, id){
4950 var d = root.ownerDocument || root;
4951 return d.getElementById(id);
4953 ns = getNodes(ns, mode, "*");
4954 return byId(ns, null, id);
4958 getStyle : function(el, name){
4959 return Roo.fly(el).getStyle(name);
4962 * Compiles a selector/xpath query into a reusable function. The returned function
4963 * takes one parameter "root" (optional), which is the context node from where the query should start.
4964 * @param {String} selector The selector/xpath query
4965 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
4966 * @return {Function}
4968 compile : function(path, type){
4969 type = type || "select";
4971 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
4972 var q = path, mode, lq;
4973 var tk = Roo.DomQuery.matchers;
4974 var tklen = tk.length;
4977 // accept leading mode switch
4978 var lmode = q.match(modeRe);
4979 if(lmode && lmode[1]){
4980 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
4981 q = q.replace(lmode[1], "");
4983 // strip leading slashes
4984 while(path.substr(0, 1)=="/"){
4985 path = path.substr(1);
4988 while(q && lq != q){
4990 var tm = q.match(tagTokenRe);
4991 if(type == "select"){
4994 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
4996 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
4998 q = q.replace(tm[0], "");
4999 }else if(q.substr(0, 1) != '@'){
5000 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5005 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5007 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5009 q = q.replace(tm[0], "");
5012 while(!(mm = q.match(modeRe))){
5013 var matched = false;
5014 for(var j = 0; j < tklen; j++){
5016 var m = q.match(t.re);
5018 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5021 q = q.replace(m[0], "");
5026 // prevent infinite loop on bad selector
5028 throw 'Error parsing selector, parsing failed at "' + q + '"';
5032 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5033 q = q.replace(mm[1], "");
5036 fn[fn.length] = "return nodup(n);\n}";
5039 * list of variables that need from compression as they are used by eval.
5049 * eval:var:byClassName
5051 * eval:var:byAttribute
5052 * eval:var:attrValue
5060 * Selects a group of elements.
5061 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5062 * @param {Node} root (optional) The start of the query (defaults to document).
5065 select : function(path, root, type){
5066 if(!root || root == document){
5069 if(typeof root == "string"){
5070 root = document.getElementById(root);
5072 var paths = path.split(",");
5074 for(var i = 0, len = paths.length; i < len; i++){
5075 var p = paths[i].replace(trimRe, "");
5077 cache[p] = Roo.DomQuery.compile(p);
5079 throw p + " is not a valid selector";
5082 var result = cache[p](root);
5083 if(result && result != document){
5084 results = results.concat(result);
5087 if(paths.length > 1){
5088 return nodup(results);
5094 * Selects a single element.
5095 * @param {String} selector The selector/xpath query
5096 * @param {Node} root (optional) The start of the query (defaults to document).
5099 selectNode : function(path, root){
5100 return Roo.DomQuery.select(path, root)[0];
5104 * Selects the value of a node, optionally replacing null with the defaultValue.
5105 * @param {String} selector The selector/xpath query
5106 * @param {Node} root (optional) The start of the query (defaults to document).
5107 * @param {String} defaultValue
5109 selectValue : function(path, root, defaultValue){
5110 path = path.replace(trimRe, "");
5111 if(!valueCache[path]){
5112 valueCache[path] = Roo.DomQuery.compile(path, "select");
5114 var n = valueCache[path](root);
5115 n = n[0] ? n[0] : n;
5116 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5117 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5121 * Selects the value of a node, parsing integers and floats.
5122 * @param {String} selector The selector/xpath query
5123 * @param {Node} root (optional) The start of the query (defaults to document).
5124 * @param {Number} defaultValue
5127 selectNumber : function(path, root, defaultValue){
5128 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5129 return parseFloat(v);
5133 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5134 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5135 * @param {String} selector The simple selector to test
5138 is : function(el, ss){
5139 if(typeof el == "string"){
5140 el = document.getElementById(el);
5142 var isArray = (el instanceof Array);
5143 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5144 return isArray ? (result.length == el.length) : (result.length > 0);
5148 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5149 * @param {Array} el An array of elements to filter
5150 * @param {String} selector The simple selector to test
5151 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5152 * the selector instead of the ones that match
5155 filter : function(els, ss, nonMatches){
5156 ss = ss.replace(trimRe, "");
5157 if(!simpleCache[ss]){
5158 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5160 var result = simpleCache[ss](els);
5161 return nonMatches ? quickDiff(result, els) : result;
5165 * Collection of matching regular expressions and code snippets.
5169 select: 'n = byClassName(n, null, " {1} ");'
5171 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5172 select: 'n = byPseudo(n, "{1}", "{2}");'
5174 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5175 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5178 select: 'n = byId(n, null, "{1}");'
5181 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5186 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5187 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5190 "=" : function(a, v){
5193 "!=" : function(a, v){
5196 "^=" : function(a, v){
5197 return a && a.substr(0, v.length) == v;
5199 "$=" : function(a, v){
5200 return a && a.substr(a.length-v.length) == v;
5202 "*=" : function(a, v){
5203 return a && a.indexOf(v) !== -1;
5205 "%=" : function(a, v){
5206 return (a % v) == 0;
5208 "|=" : function(a, v){
5209 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5211 "~=" : function(a, v){
5212 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5217 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5218 * and the argument (if any) supplied in the selector.
5221 "first-child" : function(c){
5222 var r = [], ri = -1, n;
5223 for(var i = 0, ci; ci = n = c[i]; i++){
5224 while((n = n.previousSibling) && n.nodeType != 1);
5232 "last-child" : function(c){
5233 var r = [], ri = -1, n;
5234 for(var i = 0, ci; ci = n = c[i]; i++){
5235 while((n = n.nextSibling) && n.nodeType != 1);
5243 "nth-child" : function(c, a) {
5244 var r = [], ri = -1;
5245 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5246 var f = (m[1] || 1) - 0, l = m[2] - 0;
5247 for(var i = 0, n; n = c[i]; i++){
5248 var pn = n.parentNode;
5249 if (batch != pn._batch) {
5251 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5252 if(cn.nodeType == 1){
5259 if (l == 0 || n.nodeIndex == l){
5262 } else if ((n.nodeIndex + l) % f == 0){
5270 "only-child" : function(c){
5271 var r = [], ri = -1;;
5272 for(var i = 0, ci; ci = c[i]; i++){
5273 if(!prev(ci) && !next(ci)){
5280 "empty" : function(c){
5281 var r = [], ri = -1;
5282 for(var i = 0, ci; ci = c[i]; i++){
5283 var cns = ci.childNodes, j = 0, cn, empty = true;
5286 if(cn.nodeType == 1 || cn.nodeType == 3){
5298 "contains" : function(c, v){
5299 var r = [], ri = -1;
5300 for(var i = 0, ci; ci = c[i]; i++){
5301 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5308 "nodeValue" : function(c, v){
5309 var r = [], ri = -1;
5310 for(var i = 0, ci; ci = c[i]; i++){
5311 if(ci.firstChild && ci.firstChild.nodeValue == v){
5318 "checked" : function(c){
5319 var r = [], ri = -1;
5320 for(var i = 0, ci; ci = c[i]; i++){
5321 if(ci.checked == true){
5328 "not" : function(c, ss){
5329 return Roo.DomQuery.filter(c, ss, true);
5332 "odd" : function(c){
5333 return this["nth-child"](c, "odd");
5336 "even" : function(c){
5337 return this["nth-child"](c, "even");
5340 "nth" : function(c, a){
5341 return c[a-1] || [];
5344 "first" : function(c){
5348 "last" : function(c){
5349 return c[c.length-1] || [];
5352 "has" : function(c, ss){
5353 var s = Roo.DomQuery.select;
5354 var r = [], ri = -1;
5355 for(var i = 0, ci; ci = c[i]; i++){
5356 if(s(ss, ci).length > 0){
5363 "next" : function(c, ss){
5364 var is = Roo.DomQuery.is;
5365 var r = [], ri = -1;
5366 for(var i = 0, ci; ci = c[i]; i++){
5375 "prev" : function(c, ss){
5376 var is = Roo.DomQuery.is;
5377 var r = [], ri = -1;
5378 for(var i = 0, ci; ci = c[i]; i++){
5391 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5392 * @param {String} path The selector/xpath query
5393 * @param {Node} root (optional) The start of the query (defaults to document).
5398 Roo.query = Roo.DomQuery.select;
5401 * Ext JS Library 1.1.1
5402 * Copyright(c) 2006-2007, Ext JS, LLC.
5404 * Originally Released Under LGPL - original licence link has changed is not relivant.
5407 * <script type="text/javascript">
5411 * @class Roo.util.Observable
5412 * Base class that provides a common interface for publishing events. Subclasses are expected to
5413 * to have a property "events" with all the events defined.<br>
5416 Employee = function(name){
5423 Roo.extend(Employee, Roo.util.Observable);
5425 * @param {Object} config properties to use (incuding events / listeners)
5428 Roo.util.Observable = function(cfg){
5431 this.addEvents(cfg.events || {});
5433 delete cfg.events; // make sure
5436 Roo.apply(this, cfg);
5439 this.on(this.listeners);
5440 delete this.listeners;
5443 Roo.util.Observable.prototype = {
5445 * @cfg {Object} listeners list of events and functions to call for this object,
5449 'click' : function(e) {
5459 * Fires the specified event with the passed parameters (minus the event name).
5460 * @param {String} eventName
5461 * @param {Object...} args Variable number of parameters are passed to handlers
5462 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5464 fireEvent : function(){
5465 var ce = this.events[arguments[0].toLowerCase()];
5466 if(typeof ce == "object"){
5467 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5474 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5477 * Appends an event handler to this component
5478 * @param {String} eventName The type of event to listen for
5479 * @param {Function} handler The method the event invokes
5480 * @param {Object} scope (optional) The scope in which to execute the handler
5481 * function. The handler function's "this" context.
5482 * @param {Object} options (optional) An object containing handler configuration
5483 * properties. This may contain any of the following properties:<ul>
5484 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5485 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5486 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5487 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5488 * by the specified number of milliseconds. If the event fires again within that time, the original
5489 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5492 * <b>Combining Options</b><br>
5493 * Using the options argument, it is possible to combine different types of listeners:<br>
5495 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5497 el.on('click', this.onClick, this, {
5504 * <b>Attaching multiple handlers in 1 call</b><br>
5505 * The method also allows for a single argument to be passed which is a config object containing properties
5506 * which specify multiple handlers.
5515 fn: this.onMouseOver,
5519 fn: this.onMouseOut,
5525 * Or a shorthand syntax which passes the same scope object to all handlers:
5528 'click': this.onClick,
5529 'mouseover': this.onMouseOver,
5530 'mouseout': this.onMouseOut,
5535 addListener : function(eventName, fn, scope, o){
5536 if(typeof eventName == "object"){
5539 if(this.filterOptRe.test(e)){
5542 if(typeof o[e] == "function"){
5544 this.addListener(e, o[e], o.scope, o);
5546 // individual options
5547 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5552 o = (!o || typeof o == "boolean") ? {} : o;
5553 eventName = eventName.toLowerCase();
5554 var ce = this.events[eventName] || true;
5555 if(typeof ce == "boolean"){
5556 ce = new Roo.util.Event(this, eventName);
5557 this.events[eventName] = ce;
5559 ce.addListener(fn, scope, o);
5563 * Removes a listener
5564 * @param {String} eventName The type of event to listen for
5565 * @param {Function} handler The handler to remove
5566 * @param {Object} scope (optional) The scope (this object) for the handler
5568 removeListener : function(eventName, fn, scope){
5569 var ce = this.events[eventName.toLowerCase()];
5570 if(typeof ce == "object"){
5571 ce.removeListener(fn, scope);
5576 * Removes all listeners for this object
5578 purgeListeners : function(){
5579 for(var evt in this.events){
5580 if(typeof this.events[evt] == "object"){
5581 this.events[evt].clearListeners();
5586 relayEvents : function(o, events){
5587 var createHandler = function(ename){
5589 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5592 for(var i = 0, len = events.length; i < len; i++){
5593 var ename = events[i];
5594 if(!this.events[ename]){ this.events[ename] = true; };
5595 o.on(ename, createHandler(ename), this);
5600 * Used to define events on this Observable
5601 * @param {Object} object The object with the events defined
5603 addEvents : function(o){
5607 Roo.applyIf(this.events, o);
5611 * Checks to see if this object has any listeners for a specified event
5612 * @param {String} eventName The name of the event to check for
5613 * @return {Boolean} True if the event is being listened for, else false
5615 hasListener : function(eventName){
5616 var e = this.events[eventName];
5617 return typeof e == "object" && e.listeners.length > 0;
5621 * Appends an event handler to this element (shorthand for addListener)
5622 * @param {String} eventName The type of event to listen for
5623 * @param {Function} handler The method the event invokes
5624 * @param {Object} scope (optional) The scope in which to execute the handler
5625 * function. The handler function's "this" context.
5626 * @param {Object} options (optional)
5629 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5631 * Removes a listener (shorthand for removeListener)
5632 * @param {String} eventName The type of event to listen for
5633 * @param {Function} handler The handler to remove
5634 * @param {Object} scope (optional) The scope (this object) for the handler
5637 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5640 * Starts capture on the specified Observable. All events will be passed
5641 * to the supplied function with the event name + standard signature of the event
5642 * <b>before</b> the event is fired. If the supplied function returns false,
5643 * the event will not fire.
5644 * @param {Observable} o The Observable to capture
5645 * @param {Function} fn The function to call
5646 * @param {Object} scope (optional) The scope (this object) for the fn
5649 Roo.util.Observable.capture = function(o, fn, scope){
5650 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5654 * Removes <b>all</b> added captures from the Observable.
5655 * @param {Observable} o The Observable to release
5658 Roo.util.Observable.releaseCapture = function(o){
5659 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5664 var createBuffered = function(h, o, scope){
5665 var task = new Roo.util.DelayedTask();
5667 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5671 var createSingle = function(h, e, fn, scope){
5673 e.removeListener(fn, scope);
5674 return h.apply(scope, arguments);
5678 var createDelayed = function(h, o, scope){
5680 var args = Array.prototype.slice.call(arguments, 0);
5681 setTimeout(function(){
5682 h.apply(scope, args);
5687 Roo.util.Event = function(obj, name){
5690 this.listeners = [];
5693 Roo.util.Event.prototype = {
5694 addListener : function(fn, scope, options){
5695 var o = options || {};
5696 scope = scope || this.obj;
5697 if(!this.isListening(fn, scope)){
5698 var l = {fn: fn, scope: scope, options: o};
5701 h = createDelayed(h, o, scope);
5704 h = createSingle(h, this, fn, scope);
5707 h = createBuffered(h, o, scope);
5710 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5711 this.listeners.push(l);
5713 this.listeners = this.listeners.slice(0);
5714 this.listeners.push(l);
5719 findListener : function(fn, scope){
5720 scope = scope || this.obj;
5721 var ls = this.listeners;
5722 for(var i = 0, len = ls.length; i < len; i++){
5724 if(l.fn == fn && l.scope == scope){
5731 isListening : function(fn, scope){
5732 return this.findListener(fn, scope) != -1;
5735 removeListener : function(fn, scope){
5737 if((index = this.findListener(fn, scope)) != -1){
5739 this.listeners.splice(index, 1);
5741 this.listeners = this.listeners.slice(0);
5742 this.listeners.splice(index, 1);
5749 clearListeners : function(){
5750 this.listeners = [];
5754 var ls = this.listeners, scope, len = ls.length;
5757 var args = Array.prototype.slice.call(arguments, 0);
5758 for(var i = 0; i < len; i++){
5760 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5761 this.firing = false;
5765 this.firing = false;
5772 * Ext JS Library 1.1.1
5773 * Copyright(c) 2006-2007, Ext JS, LLC.
5775 * Originally Released Under LGPL - original licence link has changed is not relivant.
5778 * <script type="text/javascript">
5782 * @class Roo.EventManager
5783 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5784 * several useful events directly.
5785 * See {@link Roo.EventObject} for more details on normalized event objects.
5788 Roo.EventManager = function(){
5789 var docReadyEvent, docReadyProcId, docReadyState = false;
5790 var resizeEvent, resizeTask, textEvent, textSize;
5791 var E = Roo.lib.Event;
5792 var D = Roo.lib.Dom;
5795 var fireDocReady = function(){
5797 docReadyState = true;
5800 clearInterval(docReadyProcId);
5802 if(Roo.isGecko || Roo.isOpera) {
5803 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5806 var defer = document.getElementById("ie-deferred-loader");
5808 defer.onreadystatechange = null;
5809 defer.parentNode.removeChild(defer);
5813 docReadyEvent.fire();
5814 docReadyEvent.clearListeners();
5819 var initDocReady = function(){
5820 docReadyEvent = new Roo.util.Event();
5821 if(Roo.isGecko || Roo.isOpera) {
5822 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5824 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5825 var defer = document.getElementById("ie-deferred-loader");
5826 defer.onreadystatechange = function(){
5827 if(this.readyState == "complete"){
5831 }else if(Roo.isSafari){
5832 docReadyProcId = setInterval(function(){
5833 var rs = document.readyState;
5834 if(rs == "complete") {
5839 // no matter what, make sure it fires on load
5840 E.on(window, "load", fireDocReady);
5843 var createBuffered = function(h, o){
5844 var task = new Roo.util.DelayedTask(h);
5846 // create new event object impl so new events don't wipe out properties
5847 e = new Roo.EventObjectImpl(e);
5848 task.delay(o.buffer, h, null, [e]);
5852 var createSingle = function(h, el, ename, fn){
5854 Roo.EventManager.removeListener(el, ename, fn);
5859 var createDelayed = function(h, o){
5861 // create new event object impl so new events don't wipe out properties
5862 e = new Roo.EventObjectImpl(e);
5863 setTimeout(function(){
5869 var listen = function(element, ename, opt, fn, scope){
5870 var o = (!opt || typeof opt == "boolean") ? {} : opt;
5871 fn = fn || o.fn; scope = scope || o.scope;
5872 var el = Roo.getDom(element);
5874 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5876 var h = function(e){
5877 e = Roo.EventObject.setEvent(e);
5880 t = e.getTarget(o.delegate, el);
5887 if(o.stopEvent === true){
5890 if(o.preventDefault === true){
5893 if(o.stopPropagation === true){
5894 e.stopPropagation();
5897 if(o.normalized === false){
5901 fn.call(scope || el, e, t, o);
5904 h = createDelayed(h, o);
5907 h = createSingle(h, el, ename, fn);
5910 h = createBuffered(h, o);
5912 fn._handlers = fn._handlers || [];
5913 fn._handlers.push([Roo.id(el), ename, h]);
5916 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5917 el.addEventListener("DOMMouseScroll", h, false);
5918 E.on(window, 'unload', function(){
5919 el.removeEventListener("DOMMouseScroll", h, false);
5922 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5923 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5928 var stopListening = function(el, ename, fn){
5929 var id = Roo.id(el), hds = fn._handlers, hd = fn;
5931 for(var i = 0, len = hds.length; i < len; i++){
5933 if(h[0] == id && h[1] == ename){
5940 E.un(el, ename, hd);
5941 el = Roo.getDom(el);
5942 if(ename == "mousewheel" && el.addEventListener){
5943 el.removeEventListener("DOMMouseScroll", hd, false);
5945 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5946 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5950 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
5957 * @scope Roo.EventManager
5962 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
5963 * object with a Roo.EventObject
5964 * @param {Function} fn The method the event invokes
5965 * @param {Object} scope An object that becomes the scope of the handler
5966 * @param {boolean} override If true, the obj passed in becomes
5967 * the execution scope of the listener
5968 * @return {Function} The wrapped function
5971 wrap : function(fn, scope, override){
5973 Roo.EventObject.setEvent(e);
5974 fn.call(override ? scope || window : window, Roo.EventObject, scope);
5979 * Appends an event handler to an element (shorthand for addListener)
5980 * @param {String/HTMLElement} element The html element or id to assign the
5981 * @param {String} eventName The type of event to listen for
5982 * @param {Function} handler The method the event invokes
5983 * @param {Object} scope (optional) The scope in which to execute the handler
5984 * function. The handler function's "this" context.
5985 * @param {Object} options (optional) An object containing handler configuration
5986 * properties. This may contain any of the following properties:<ul>
5987 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5988 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
5989 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
5990 * <li>preventDefault {Boolean} True to prevent the default action</li>
5991 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
5992 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
5993 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5994 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5995 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5996 * by the specified number of milliseconds. If the event fires again within that time, the original
5997 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6000 * <b>Combining Options</b><br>
6001 * Using the options argument, it is possible to combine different types of listeners:<br>
6003 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6005 el.on('click', this.onClick, this, {
6012 * <b>Attaching multiple handlers in 1 call</b><br>
6013 * The method also allows for a single argument to be passed which is a config object containing properties
6014 * which specify multiple handlers.
6024 fn: this.onMouseOver
6033 * Or a shorthand syntax:<br>
6036 'click' : this.onClick,
6037 'mouseover' : this.onMouseOver,
6038 'mouseout' : this.onMouseOut
6042 addListener : function(element, eventName, fn, scope, options){
6043 if(typeof eventName == "object"){
6049 if(typeof o[e] == "function"){
6051 listen(element, e, o, o[e], o.scope);
6053 // individual options
6054 listen(element, e, o[e]);
6059 return listen(element, eventName, options, fn, scope);
6063 * Removes an event handler
6065 * @param {String/HTMLElement} element The id or html element to remove the
6067 * @param {String} eventName The type of event
6068 * @param {Function} fn
6069 * @return {Boolean} True if a listener was actually removed
6071 removeListener : function(element, eventName, fn){
6072 return stopListening(element, eventName, fn);
6076 * Fires when the document is ready (before onload and before images are loaded). Can be
6077 * accessed shorthanded Roo.onReady().
6078 * @param {Function} fn The method the event invokes
6079 * @param {Object} scope An object that becomes the scope of the handler
6080 * @param {boolean} options
6082 onDocumentReady : function(fn, scope, options){
6083 if(docReadyState){ // if it already fired
6084 docReadyEvent.addListener(fn, scope, options);
6085 docReadyEvent.fire();
6086 docReadyEvent.clearListeners();
6092 docReadyEvent.addListener(fn, scope, options);
6096 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6097 * @param {Function} fn The method the event invokes
6098 * @param {Object} scope An object that becomes the scope of the handler
6099 * @param {boolean} options
6101 onWindowResize : function(fn, scope, options){
6103 resizeEvent = new Roo.util.Event();
6104 resizeTask = new Roo.util.DelayedTask(function(){
6105 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6107 E.on(window, "resize", function(){
6109 resizeTask.delay(50);
6111 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6115 resizeEvent.addListener(fn, scope, options);
6119 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6120 * @param {Function} fn The method the event invokes
6121 * @param {Object} scope An object that becomes the scope of the handler
6122 * @param {boolean} options
6124 onTextResize : function(fn, scope, options){
6126 textEvent = new Roo.util.Event();
6127 var textEl = new Roo.Element(document.createElement('div'));
6128 textEl.dom.className = 'x-text-resize';
6129 textEl.dom.innerHTML = 'X';
6130 textEl.appendTo(document.body);
6131 textSize = textEl.dom.offsetHeight;
6132 setInterval(function(){
6133 if(textEl.dom.offsetHeight != textSize){
6134 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6136 }, this.textResizeInterval);
6138 textEvent.addListener(fn, scope, options);
6142 * Removes the passed window resize listener.
6143 * @param {Function} fn The method the event invokes
6144 * @param {Object} scope The scope of handler
6146 removeResizeListener : function(fn, scope){
6148 resizeEvent.removeListener(fn, scope);
6153 fireResize : function(){
6155 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6159 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6163 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6165 textResizeInterval : 50
6170 * @scopeAlias pub=Roo.EventManager
6174 * Appends an event handler to an element (shorthand for addListener)
6175 * @param {String/HTMLElement} element The html element or id to assign the
6176 * @param {String} eventName The type of event to listen for
6177 * @param {Function} handler The method the event invokes
6178 * @param {Object} scope (optional) The scope in which to execute the handler
6179 * function. The handler function's "this" context.
6180 * @param {Object} options (optional) An object containing handler configuration
6181 * properties. This may contain any of the following properties:<ul>
6182 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6183 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6184 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6185 * <li>preventDefault {Boolean} True to prevent the default action</li>
6186 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6187 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6188 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6189 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6190 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6191 * by the specified number of milliseconds. If the event fires again within that time, the original
6192 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6195 * <b>Combining Options</b><br>
6196 * Using the options argument, it is possible to combine different types of listeners:<br>
6198 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6200 el.on('click', this.onClick, this, {
6207 * <b>Attaching multiple handlers in 1 call</b><br>
6208 * The method also allows for a single argument to be passed which is a config object containing properties
6209 * which specify multiple handlers.
6219 fn: this.onMouseOver
6228 * Or a shorthand syntax:<br>
6231 'click' : this.onClick,
6232 'mouseover' : this.onMouseOver,
6233 'mouseout' : this.onMouseOut
6237 pub.on = pub.addListener;
6238 pub.un = pub.removeListener;
6240 pub.stoppedMouseDownEvent = new Roo.util.Event();
6244 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6245 * @param {Function} fn The method the event invokes
6246 * @param {Object} scope An object that becomes the scope of the handler
6247 * @param {boolean} override If true, the obj passed in becomes
6248 * the execution scope of the listener
6252 Roo.onReady = Roo.EventManager.onDocumentReady;
6254 Roo.onReady(function(){
6255 var bd = Roo.get(document.body);
6260 : Roo.isGecko ? "roo-gecko"
6261 : Roo.isOpera ? "roo-opera"
6262 : Roo.isSafari ? "roo-safari" : ""];
6265 cls.push("roo-mac");
6268 cls.push("roo-linux");
6270 if(Roo.isBorderBox){
6271 cls.push('roo-border-box');
6273 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6274 var p = bd.dom.parentNode;
6276 p.className += ' roo-strict';
6279 bd.addClass(cls.join(' '));
6283 * @class Roo.EventObject
6284 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6285 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6288 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6290 var target = e.getTarget();
6293 var myDiv = Roo.get("myDiv");
6294 myDiv.on("click", handleClick);
6296 Roo.EventManager.on("myDiv", 'click', handleClick);
6297 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6301 Roo.EventObject = function(){
6303 var E = Roo.lib.Event;
6305 // safari keypress events for special keys return bad keycodes
6308 63235 : 39, // right
6311 63276 : 33, // page up
6312 63277 : 34, // page down
6313 63272 : 46, // delete
6318 // normalize button clicks
6319 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6320 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6322 Roo.EventObjectImpl = function(e){
6324 this.setEvent(e.browserEvent || e);
6327 Roo.EventObjectImpl.prototype = {
6329 * Used to fix doc tools.
6330 * @scope Roo.EventObject.prototype
6336 /** The normal browser event */
6337 browserEvent : null,
6338 /** The button pressed in a mouse event */
6340 /** True if the shift key was down during the event */
6342 /** True if the control key was down during the event */
6344 /** True if the alt key was down during the event */
6403 setEvent : function(e){
6404 if(e == this || (e && e.browserEvent)){ // already wrapped
6407 this.browserEvent = e;
6409 // normalize buttons
6410 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6411 if(e.type == 'click' && this.button == -1){
6415 this.shiftKey = e.shiftKey;
6416 // mac metaKey behaves like ctrlKey
6417 this.ctrlKey = e.ctrlKey || e.metaKey;
6418 this.altKey = e.altKey;
6419 // in getKey these will be normalized for the mac
6420 this.keyCode = e.keyCode;
6421 // keyup warnings on firefox.
6422 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6423 // cache the target for the delayed and or buffered events
6424 this.target = E.getTarget(e);
6426 this.xy = E.getXY(e);
6429 this.shiftKey = false;
6430 this.ctrlKey = false;
6431 this.altKey = false;
6441 * Stop the event (preventDefault and stopPropagation)
6443 stopEvent : function(){
6444 if(this.browserEvent){
6445 if(this.browserEvent.type == 'mousedown'){
6446 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6448 E.stopEvent(this.browserEvent);
6453 * Prevents the browsers default handling of the event.
6455 preventDefault : function(){
6456 if(this.browserEvent){
6457 E.preventDefault(this.browserEvent);
6462 isNavKeyPress : function(){
6463 var k = this.keyCode;
6464 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6465 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6468 isSpecialKey : function(){
6469 var k = this.keyCode;
6470 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6471 (k == 16) || (k == 17) ||
6472 (k >= 18 && k <= 20) ||
6473 (k >= 33 && k <= 35) ||
6474 (k >= 36 && k <= 39) ||
6475 (k >= 44 && k <= 45);
6478 * Cancels bubbling of the event.
6480 stopPropagation : function(){
6481 if(this.browserEvent){
6482 if(this.type == 'mousedown'){
6483 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6485 E.stopPropagation(this.browserEvent);
6490 * Gets the key code for the event.
6493 getCharCode : function(){
6494 return this.charCode || this.keyCode;
6498 * Returns a normalized keyCode for the event.
6499 * @return {Number} The key code
6501 getKey : function(){
6502 var k = this.keyCode || this.charCode;
6503 return Roo.isSafari ? (safariKeys[k] || k) : k;
6507 * Gets the x coordinate of the event.
6510 getPageX : function(){
6515 * Gets the y coordinate of the event.
6518 getPageY : function(){
6523 * Gets the time of the event.
6526 getTime : function(){
6527 if(this.browserEvent){
6528 return E.getTime(this.browserEvent);
6534 * Gets the page coordinates of the event.
6535 * @return {Array} The xy values like [x, y]
6542 * Gets the target for the event.
6543 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6544 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6545 search as a number or element (defaults to 10 || document.body)
6546 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6547 * @return {HTMLelement}
6549 getTarget : function(selector, maxDepth, returnEl){
6550 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6553 * Gets the related target.
6554 * @return {HTMLElement}
6556 getRelatedTarget : function(){
6557 if(this.browserEvent){
6558 return E.getRelatedTarget(this.browserEvent);
6564 * Normalizes mouse wheel delta across browsers
6565 * @return {Number} The delta
6567 getWheelDelta : function(){
6568 var e = this.browserEvent;
6570 if(e.wheelDelta){ /* IE/Opera. */
6571 delta = e.wheelDelta/120;
6572 }else if(e.detail){ /* Mozilla case. */
6573 delta = -e.detail/3;
6579 * Returns true if the control, meta, shift or alt key was pressed during this event.
6582 hasModifier : function(){
6583 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6587 * Returns true if the target of this event equals el or is a child of el
6588 * @param {String/HTMLElement/Element} el
6589 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6592 within : function(el, related){
6593 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6594 return t && Roo.fly(el).contains(t);
6597 getPoint : function(){
6598 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6602 return new Roo.EventObjectImpl();
6607 * Ext JS Library 1.1.1
6608 * Copyright(c) 2006-2007, Ext JS, LLC.
6610 * Originally Released Under LGPL - original licence link has changed is not relivant.
6613 * <script type="text/javascript">
6617 // was in Composite Element!??!?!
6620 var D = Roo.lib.Dom;
6621 var E = Roo.lib.Event;
6622 var A = Roo.lib.Anim;
6624 // local style camelizing for speed
6626 var camelRe = /(-[a-z])/gi;
6627 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6628 var view = document.defaultView;
6631 * @class Roo.Element
6632 * Represents an Element in the DOM.<br><br>
6635 var el = Roo.get("my-div");
6638 var el = getEl("my-div");
6640 // or with a DOM element
6641 var el = Roo.get(myDivElement);
6643 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6644 * each call instead of constructing a new one.<br><br>
6645 * <b>Animations</b><br />
6646 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6647 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6649 Option Default Description
6650 --------- -------- ---------------------------------------------
6651 duration .35 The duration of the animation in seconds
6652 easing easeOut The YUI easing method
6653 callback none A function to execute when the anim completes
6654 scope this The scope (this) of the callback function
6656 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6657 * manipulate the animation. Here's an example:
6659 var el = Roo.get("my-div");
6664 // default animation
6665 el.setWidth(100, true);
6667 // animation with some options set
6674 // using the "anim" property to get the Anim object
6680 el.setWidth(100, opt);
6682 if(opt.anim.isAnimated()){
6686 * <b> Composite (Collections of) Elements</b><br />
6687 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6688 * @constructor Create a new Element directly.
6689 * @param {String/HTMLElement} element
6690 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6692 Roo.Element = function(element, forceNew){
6693 var dom = typeof element == "string" ?
6694 document.getElementById(element) : element;
6695 if(!dom){ // invalid id/element
6699 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6700 return Roo.Element.cache[id];
6710 * The DOM element ID
6713 this.id = id || Roo.id(dom);
6716 var El = Roo.Element;
6720 * The element's default display mode (defaults to "")
6723 originalDisplay : "",
6727 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6732 * Sets the element's visibility mode. When setVisible() is called it
6733 * will use this to determine whether to set the visibility or the display property.
6734 * @param visMode Element.VISIBILITY or Element.DISPLAY
6735 * @return {Roo.Element} this
6737 setVisibilityMode : function(visMode){
6738 this.visibilityMode = visMode;
6742 * Convenience method for setVisibilityMode(Element.DISPLAY)
6743 * @param {String} display (optional) What to set display to when visible
6744 * @return {Roo.Element} this
6746 enableDisplayMode : function(display){
6747 this.setVisibilityMode(El.DISPLAY);
6748 if(typeof display != "undefined") this.originalDisplay = display;
6753 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6754 * @param {String} selector The simple selector to test
6755 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6756 search as a number or element (defaults to 10 || document.body)
6757 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6758 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6760 findParent : function(simpleSelector, maxDepth, returnEl){
6761 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6762 maxDepth = maxDepth || 50;
6763 if(typeof maxDepth != "number"){
6764 stopEl = Roo.getDom(maxDepth);
6767 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6768 if(dq.is(p, simpleSelector)){
6769 return returnEl ? Roo.get(p) : p;
6779 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6780 * @param {String} selector The simple selector to test
6781 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6782 search as a number or element (defaults to 10 || document.body)
6783 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6784 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6786 findParentNode : function(simpleSelector, maxDepth, returnEl){
6787 var p = Roo.fly(this.dom.parentNode, '_internal');
6788 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6792 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6793 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6794 * @param {String} selector The simple selector to test
6795 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6796 search as a number or element (defaults to 10 || document.body)
6797 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6799 up : function(simpleSelector, maxDepth){
6800 return this.findParentNode(simpleSelector, maxDepth, true);
6806 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6807 * @param {String} selector The simple selector to test
6808 * @return {Boolean} True if this element matches the selector, else false
6810 is : function(simpleSelector){
6811 return Roo.DomQuery.is(this.dom, simpleSelector);
6815 * Perform animation on this element.
6816 * @param {Object} args The YUI animation control args
6817 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6818 * @param {Function} onComplete (optional) Function to call when animation completes
6819 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6820 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6821 * @return {Roo.Element} this
6823 animate : function(args, duration, onComplete, easing, animType){
6824 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6829 * @private Internal animation call
6831 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6832 animType = animType || 'run';
6834 var anim = Roo.lib.Anim[animType](
6836 (opt.duration || defaultDur) || .35,
6837 (opt.easing || defaultEase) || 'easeOut',
6839 Roo.callback(cb, this);
6840 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6848 // private legacy anim prep
6849 preanim : function(a, i){
6850 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6854 * Removes worthless text nodes
6855 * @param {Boolean} forceReclean (optional) By default the element
6856 * keeps track if it has been cleaned already so
6857 * you can call this over and over. However, if you update the element and
6858 * need to force a reclean, you can pass true.
6860 clean : function(forceReclean){
6861 if(this.isCleaned && forceReclean !== true){
6865 var d = this.dom, n = d.firstChild, ni = -1;
6867 var nx = n.nextSibling;
6868 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6875 this.isCleaned = true;
6880 calcOffsetsTo : function(el){
6883 var restorePos = false;
6884 if(el.getStyle('position') == 'static'){
6885 el.position('relative');
6890 while(op && op != d && op.tagName != 'HTML'){
6893 op = op.offsetParent;
6896 el.position('static');
6902 * Scrolls this element into view within the passed container.
6903 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6904 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6905 * @return {Roo.Element} this
6907 scrollIntoView : function(container, hscroll){
6908 var c = Roo.getDom(container) || document.body;
6911 var o = this.calcOffsetsTo(c),
6914 b = t+el.offsetHeight,
6915 r = l+el.offsetWidth;
6917 var ch = c.clientHeight;
6918 var ct = parseInt(c.scrollTop, 10);
6919 var cl = parseInt(c.scrollLeft, 10);
6921 var cr = cl + c.clientWidth;
6929 if(hscroll !== false){
6933 c.scrollLeft = r-c.clientWidth;
6940 scrollChildIntoView : function(child, hscroll){
6941 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6945 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6946 * the new height may not be available immediately.
6947 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6948 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6949 * @param {Function} onComplete (optional) Function to call when animation completes
6950 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
6951 * @return {Roo.Element} this
6953 autoHeight : function(animate, duration, onComplete, easing){
6954 var oldHeight = this.getHeight();
6956 this.setHeight(1); // force clipping
6957 setTimeout(function(){
6958 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
6960 this.setHeight(height);
6962 if(typeof onComplete == "function"){
6966 this.setHeight(oldHeight); // restore original height
6967 this.setHeight(height, animate, duration, function(){
6969 if(typeof onComplete == "function") onComplete();
6970 }.createDelegate(this), easing);
6972 }.createDelegate(this), 0);
6977 * Returns true if this element is an ancestor of the passed element
6978 * @param {HTMLElement/String} el The element to check
6979 * @return {Boolean} True if this element is an ancestor of el, else false
6981 contains : function(el){
6982 if(!el){return false;}
6983 return D.isAncestor(this.dom, el.dom ? el.dom : el);
6987 * Checks whether the element is currently visible using both visibility and display properties.
6988 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
6989 * @return {Boolean} True if the element is currently visible, else false
6991 isVisible : function(deep) {
6992 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
6993 if(deep !== true || !vis){
6996 var p = this.dom.parentNode;
6997 while(p && p.tagName.toLowerCase() != "body"){
6998 if(!Roo.fly(p, '_isVisible').isVisible()){
7007 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7008 * @param {String} selector The CSS selector
7009 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7010 * @return {CompositeElement/CompositeElementLite} The composite element
7012 select : function(selector, unique){
7013 return El.select(selector, unique, this.dom);
7017 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7018 * @param {String} selector The CSS selector
7019 * @return {Array} An array of the matched nodes
7021 query : function(selector, unique){
7022 return Roo.DomQuery.select(selector, this.dom);
7026 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7027 * @param {String} selector The CSS selector
7028 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7029 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7031 child : function(selector, returnDom){
7032 var n = Roo.DomQuery.selectNode(selector, this.dom);
7033 return returnDom ? n : Roo.get(n);
7037 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7038 * @param {String} selector The CSS selector
7039 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7040 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7042 down : function(selector, returnDom){
7043 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7044 return returnDom ? n : Roo.get(n);
7048 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7049 * @param {String} group The group the DD object is member of
7050 * @param {Object} config The DD config object
7051 * @param {Object} overrides An object containing methods to override/implement on the DD object
7052 * @return {Roo.dd.DD} The DD object
7054 initDD : function(group, config, overrides){
7055 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7056 return Roo.apply(dd, overrides);
7060 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7061 * @param {String} group The group the DDProxy object is member of
7062 * @param {Object} config The DDProxy config object
7063 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7064 * @return {Roo.dd.DDProxy} The DDProxy object
7066 initDDProxy : function(group, config, overrides){
7067 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7068 return Roo.apply(dd, overrides);
7072 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7073 * @param {String} group The group the DDTarget object is member of
7074 * @param {Object} config The DDTarget config object
7075 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7076 * @return {Roo.dd.DDTarget} The DDTarget object
7078 initDDTarget : function(group, config, overrides){
7079 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7080 return Roo.apply(dd, overrides);
7084 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7085 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7086 * @param {Boolean} visible Whether the element is visible
7087 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7088 * @return {Roo.Element} this
7090 setVisible : function(visible, animate){
7092 if(this.visibilityMode == El.DISPLAY){
7093 this.setDisplayed(visible);
7096 this.dom.style.visibility = visible ? "visible" : "hidden";
7099 // closure for composites
7101 var visMode = this.visibilityMode;
7103 this.setOpacity(.01);
7104 this.setVisible(true);
7106 this.anim({opacity: { to: (visible?1:0) }},
7107 this.preanim(arguments, 1),
7108 null, .35, 'easeIn', function(){
7110 if(visMode == El.DISPLAY){
7111 dom.style.display = "none";
7113 dom.style.visibility = "hidden";
7115 Roo.get(dom).setOpacity(1);
7123 * Returns true if display is not "none"
7126 isDisplayed : function() {
7127 return this.getStyle("display") != "none";
7131 * Toggles the element's visibility or display, depending on visibility mode.
7132 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7133 * @return {Roo.Element} this
7135 toggle : function(animate){
7136 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7141 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7142 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7143 * @return {Roo.Element} this
7145 setDisplayed : function(value) {
7146 if(typeof value == "boolean"){
7147 value = value ? this.originalDisplay : "none";
7149 this.setStyle("display", value);
7154 * Tries to focus the element. Any exceptions are caught and ignored.
7155 * @return {Roo.Element} this
7157 focus : function() {
7165 * Tries to blur the element. Any exceptions are caught and ignored.
7166 * @return {Roo.Element} this
7176 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7177 * @param {String/Array} className The CSS class to add, or an array of classes
7178 * @return {Roo.Element} this
7180 addClass : function(className){
7181 if(className instanceof Array){
7182 for(var i = 0, len = className.length; i < len; i++) {
7183 this.addClass(className[i]);
7186 if(className && !this.hasClass(className)){
7187 this.dom.className = this.dom.className + " " + className;
7194 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7195 * @param {String/Array} className The CSS class to add, or an array of classes
7196 * @return {Roo.Element} this
7198 radioClass : function(className){
7199 var siblings = this.dom.parentNode.childNodes;
7200 for(var i = 0; i < siblings.length; i++) {
7201 var s = siblings[i];
7202 if(s.nodeType == 1){
7203 Roo.get(s).removeClass(className);
7206 this.addClass(className);
7211 * Removes one or more CSS classes from the element.
7212 * @param {String/Array} className The CSS class to remove, or an array of classes
7213 * @return {Roo.Element} this
7215 removeClass : function(className){
7216 if(!className || !this.dom.className){
7219 if(className instanceof Array){
7220 for(var i = 0, len = className.length; i < len; i++) {
7221 this.removeClass(className[i]);
7224 if(this.hasClass(className)){
7225 var re = this.classReCache[className];
7227 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7228 this.classReCache[className] = re;
7230 this.dom.className =
7231 this.dom.className.replace(re, " ");
7241 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7242 * @param {String} className The CSS class to toggle
7243 * @return {Roo.Element} this
7245 toggleClass : function(className){
7246 if(this.hasClass(className)){
7247 this.removeClass(className);
7249 this.addClass(className);
7255 * Checks if the specified CSS class exists on this element's DOM node.
7256 * @param {String} className The CSS class to check for
7257 * @return {Boolean} True if the class exists, else false
7259 hasClass : function(className){
7260 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7264 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7265 * @param {String} oldClassName The CSS class to replace
7266 * @param {String} newClassName The replacement CSS class
7267 * @return {Roo.Element} this
7269 replaceClass : function(oldClassName, newClassName){
7270 this.removeClass(oldClassName);
7271 this.addClass(newClassName);
7276 * Returns an object with properties matching the styles requested.
7277 * For example, el.getStyles('color', 'font-size', 'width') might return
7278 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7279 * @param {String} style1 A style name
7280 * @param {String} style2 A style name
7281 * @param {String} etc.
7282 * @return {Object} The style object
7284 getStyles : function(){
7285 var a = arguments, len = a.length, r = {};
7286 for(var i = 0; i < len; i++){
7287 r[a[i]] = this.getStyle(a[i]);
7293 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7294 * @param {String} property The style property whose value is returned.
7295 * @return {String} The current value of the style property for this element.
7297 getStyle : function(){
7298 return view && view.getComputedStyle ?
7300 var el = this.dom, v, cs, camel;
7301 if(prop == 'float'){
7304 if(el.style && (v = el.style[prop])){
7307 if(cs = view.getComputedStyle(el, "")){
7308 if(!(camel = propCache[prop])){
7309 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7316 var el = this.dom, v, cs, camel;
7317 if(prop == 'opacity'){
7318 if(typeof el.style.filter == 'string'){
7319 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7321 var fv = parseFloat(m[1]);
7323 return fv ? fv / 100 : 0;
7328 }else if(prop == 'float'){
7329 prop = "styleFloat";
7331 if(!(camel = propCache[prop])){
7332 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7334 if(v = el.style[camel]){
7337 if(cs = el.currentStyle){
7345 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7346 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7347 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7348 * @return {Roo.Element} this
7350 setStyle : function(prop, value){
7351 if(typeof prop == "string"){
7353 if(!(camel = propCache[prop])){
7354 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7356 if(camel == 'opacity') {
7357 this.setOpacity(value);
7359 this.dom.style[camel] = value;
7362 for(var style in prop){
7363 if(typeof prop[style] != "function"){
7364 this.setStyle(style, prop[style]);
7372 * More flexible version of {@link #setStyle} for setting style properties.
7373 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7374 * a function which returns such a specification.
7375 * @return {Roo.Element} this
7377 applyStyles : function(style){
7378 Roo.DomHelper.applyStyles(this.dom, style);
7383 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7384 * @return {Number} The X position of the element
7387 return D.getX(this.dom);
7391 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7392 * @return {Number} The Y position of the element
7395 return D.getY(this.dom);
7399 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7400 * @return {Array} The XY position of the element
7403 return D.getXY(this.dom);
7407 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7408 * @param {Number} The X position of the element
7409 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7410 * @return {Roo.Element} this
7412 setX : function(x, animate){
7414 D.setX(this.dom, x);
7416 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7422 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7423 * @param {Number} The Y position of the element
7424 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7425 * @return {Roo.Element} this
7427 setY : function(y, animate){
7429 D.setY(this.dom, y);
7431 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7437 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7438 * @param {String} left The left CSS property value
7439 * @return {Roo.Element} this
7441 setLeft : function(left){
7442 this.setStyle("left", this.addUnits(left));
7447 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7448 * @param {String} top The top CSS property value
7449 * @return {Roo.Element} this
7451 setTop : function(top){
7452 this.setStyle("top", this.addUnits(top));
7457 * Sets the element's CSS right style.
7458 * @param {String} right The right CSS property value
7459 * @return {Roo.Element} this
7461 setRight : function(right){
7462 this.setStyle("right", this.addUnits(right));
7467 * Sets the element's CSS bottom style.
7468 * @param {String} bottom The bottom CSS property value
7469 * @return {Roo.Element} this
7471 setBottom : function(bottom){
7472 this.setStyle("bottom", this.addUnits(bottom));
7477 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7478 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7479 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7480 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7481 * @return {Roo.Element} this
7483 setXY : function(pos, animate){
7485 D.setXY(this.dom, pos);
7487 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7493 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7494 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7495 * @param {Number} x X value for new position (coordinates are page-based)
7496 * @param {Number} y Y value for new position (coordinates are page-based)
7497 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7498 * @return {Roo.Element} this
7500 setLocation : function(x, y, animate){
7501 this.setXY([x, y], this.preanim(arguments, 2));
7506 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7507 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7508 * @param {Number} x X value for new position (coordinates are page-based)
7509 * @param {Number} y Y value for new position (coordinates are page-based)
7510 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7511 * @return {Roo.Element} this
7513 moveTo : function(x, y, animate){
7514 this.setXY([x, y], this.preanim(arguments, 2));
7519 * Returns the region of the given element.
7520 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7521 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7523 getRegion : function(){
7524 return D.getRegion(this.dom);
7528 * Returns the offset height of the element
7529 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7530 * @return {Number} The element's height
7532 getHeight : function(contentHeight){
7533 var h = this.dom.offsetHeight || 0;
7534 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7538 * Returns the offset width of the element
7539 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7540 * @return {Number} The element's width
7542 getWidth : function(contentWidth){
7543 var w = this.dom.offsetWidth || 0;
7544 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7548 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7549 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7550 * if a height has not been set using CSS.
7553 getComputedHeight : function(){
7554 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7556 h = parseInt(this.getStyle('height'), 10) || 0;
7557 if(!this.isBorderBox()){
7558 h += this.getFrameWidth('tb');
7565 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7566 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7567 * if a width has not been set using CSS.
7570 getComputedWidth : function(){
7571 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7573 w = parseInt(this.getStyle('width'), 10) || 0;
7574 if(!this.isBorderBox()){
7575 w += this.getFrameWidth('lr');
7582 * Returns the size of the element.
7583 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7584 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7586 getSize : function(contentSize){
7587 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7591 * Returns the width and height of the viewport.
7592 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7594 getViewSize : function(){
7595 var d = this.dom, doc = document, aw = 0, ah = 0;
7596 if(d == doc || d == doc.body){
7597 return {width : D.getViewWidth(), height: D.getViewHeight()};
7600 width : d.clientWidth,
7601 height: d.clientHeight
7607 * Returns the value of the "value" attribute
7608 * @param {Boolean} asNumber true to parse the value as a number
7609 * @return {String/Number}
7611 getValue : function(asNumber){
7612 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7616 adjustWidth : function(width){
7617 if(typeof width == "number"){
7618 if(this.autoBoxAdjust && !this.isBorderBox()){
7619 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7629 adjustHeight : function(height){
7630 if(typeof height == "number"){
7631 if(this.autoBoxAdjust && !this.isBorderBox()){
7632 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7642 * Set the width of the element
7643 * @param {Number} width The new width
7644 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7645 * @return {Roo.Element} this
7647 setWidth : function(width, animate){
7648 width = this.adjustWidth(width);
7650 this.dom.style.width = this.addUnits(width);
7652 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7658 * Set the height of the element
7659 * @param {Number} height The new height
7660 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7661 * @return {Roo.Element} this
7663 setHeight : function(height, animate){
7664 height = this.adjustHeight(height);
7666 this.dom.style.height = this.addUnits(height);
7668 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7674 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7675 * @param {Number} width The new width
7676 * @param {Number} height The new height
7677 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7678 * @return {Roo.Element} this
7680 setSize : function(width, height, animate){
7681 if(typeof width == "object"){ // in case of object from getSize()
7682 height = width.height; width = width.width;
7684 width = this.adjustWidth(width); height = this.adjustHeight(height);
7686 this.dom.style.width = this.addUnits(width);
7687 this.dom.style.height = this.addUnits(height);
7689 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7695 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7696 * @param {Number} x X value for new position (coordinates are page-based)
7697 * @param {Number} y Y value for new position (coordinates are page-based)
7698 * @param {Number} width The new width
7699 * @param {Number} height The new height
7700 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7701 * @return {Roo.Element} this
7703 setBounds : function(x, y, width, height, animate){
7705 this.setSize(width, height);
7706 this.setLocation(x, y);
7708 width = this.adjustWidth(width); height = this.adjustHeight(height);
7709 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7710 this.preanim(arguments, 4), 'motion');
7716 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7717 * @param {Roo.lib.Region} region The region to fill
7718 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7719 * @return {Roo.Element} this
7721 setRegion : function(region, animate){
7722 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7727 * Appends an event handler
7729 * @param {String} eventName The type of event to append
7730 * @param {Function} fn The method the event invokes
7731 * @param {Object} scope (optional) The scope (this object) of the fn
7732 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7734 addListener : function(eventName, fn, scope, options){
7735 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7739 * Removes an event handler from this element
7740 * @param {String} eventName the type of event to remove
7741 * @param {Function} fn the method the event invokes
7742 * @return {Roo.Element} this
7744 removeListener : function(eventName, fn){
7745 Roo.EventManager.removeListener(this.dom, eventName, fn);
7750 * Removes all previous added listeners from this element
7751 * @return {Roo.Element} this
7753 removeAllListeners : function(){
7754 E.purgeElement(this.dom);
7758 relayEvent : function(eventName, observable){
7759 this.on(eventName, function(e){
7760 observable.fireEvent(eventName, e);
7765 * Set the opacity of the element
7766 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7767 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7768 * @return {Roo.Element} this
7770 setOpacity : function(opacity, animate){
7772 var s = this.dom.style;
7775 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7776 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7778 s.opacity = opacity;
7781 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7787 * Gets the left X coordinate
7788 * @param {Boolean} local True to get the local css position instead of page coordinate
7791 getLeft : function(local){
7795 return parseInt(this.getStyle("left"), 10) || 0;
7800 * Gets the right X coordinate of the element (element X position + element width)
7801 * @param {Boolean} local True to get the local css position instead of page coordinate
7804 getRight : function(local){
7806 return this.getX() + this.getWidth();
7808 return (this.getLeft(true) + this.getWidth()) || 0;
7813 * Gets the top Y coordinate
7814 * @param {Boolean} local True to get the local css position instead of page coordinate
7817 getTop : function(local) {
7821 return parseInt(this.getStyle("top"), 10) || 0;
7826 * Gets the bottom Y coordinate of the element (element Y position + element height)
7827 * @param {Boolean} local True to get the local css position instead of page coordinate
7830 getBottom : function(local){
7832 return this.getY() + this.getHeight();
7834 return (this.getTop(true) + this.getHeight()) || 0;
7839 * Initializes positioning on this element. If a desired position is not passed, it will make the
7840 * the element positioned relative IF it is not already positioned.
7841 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7842 * @param {Number} zIndex (optional) The zIndex to apply
7843 * @param {Number} x (optional) Set the page X position
7844 * @param {Number} y (optional) Set the page Y position
7846 position : function(pos, zIndex, x, y){
7848 if(this.getStyle('position') == 'static'){
7849 this.setStyle('position', 'relative');
7852 this.setStyle("position", pos);
7855 this.setStyle("z-index", zIndex);
7857 if(x !== undefined && y !== undefined){
7859 }else if(x !== undefined){
7861 }else if(y !== undefined){
7867 * Clear positioning back to the default when the document was loaded
7868 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7869 * @return {Roo.Element} this
7871 clearPositioning : function(value){
7879 "position" : "static"
7885 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7886 * snapshot before performing an update and then restoring the element.
7889 getPositioning : function(){
7890 var l = this.getStyle("left");
7891 var t = this.getStyle("top");
7893 "position" : this.getStyle("position"),
7895 "right" : l ? "" : this.getStyle("right"),
7897 "bottom" : t ? "" : this.getStyle("bottom"),
7898 "z-index" : this.getStyle("z-index")
7903 * Gets the width of the border(s) for the specified side(s)
7904 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7905 * passing lr would get the border (l)eft width + the border (r)ight width.
7906 * @return {Number} The width of the sides passed added together
7908 getBorderWidth : function(side){
7909 return this.addStyles(side, El.borders);
7913 * Gets the width of the padding(s) for the specified side(s)
7914 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7915 * passing lr would get the padding (l)eft + the padding (r)ight.
7916 * @return {Number} The padding of the sides passed added together
7918 getPadding : function(side){
7919 return this.addStyles(side, El.paddings);
7923 * Set positioning with an object returned by getPositioning().
7924 * @param {Object} posCfg
7925 * @return {Roo.Element} this
7927 setPositioning : function(pc){
7928 this.applyStyles(pc);
7929 if(pc.right == "auto"){
7930 this.dom.style.right = "";
7932 if(pc.bottom == "auto"){
7933 this.dom.style.bottom = "";
7939 fixDisplay : function(){
7940 if(this.getStyle("display") == "none"){
7941 this.setStyle("visibility", "hidden");
7942 this.setStyle("display", this.originalDisplay); // first try reverting to default
7943 if(this.getStyle("display") == "none"){ // if that fails, default to block
7944 this.setStyle("display", "block");
7950 * Quick set left and top adding default units
7951 * @param {String} left The left CSS property value
7952 * @param {String} top The top CSS property value
7953 * @return {Roo.Element} this
7955 setLeftTop : function(left, top){
7956 this.dom.style.left = this.addUnits(left);
7957 this.dom.style.top = this.addUnits(top);
7962 * Move this element relative to its current position.
7963 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
7964 * @param {Number} distance How far to move the element in pixels
7965 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7966 * @return {Roo.Element} this
7968 move : function(direction, distance, animate){
7969 var xy = this.getXY();
7970 direction = direction.toLowerCase();
7974 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
7978 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
7983 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
7988 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
7995 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
7996 * @return {Roo.Element} this
7999 if(!this.isClipped){
8000 this.isClipped = true;
8001 this.originalClip = {
8002 "o": this.getStyle("overflow"),
8003 "x": this.getStyle("overflow-x"),
8004 "y": this.getStyle("overflow-y")
8006 this.setStyle("overflow", "hidden");
8007 this.setStyle("overflow-x", "hidden");
8008 this.setStyle("overflow-y", "hidden");
8014 * Return clipping (overflow) to original clipping before clip() was called
8015 * @return {Roo.Element} this
8017 unclip : function(){
8019 this.isClipped = false;
8020 var o = this.originalClip;
8021 if(o.o){this.setStyle("overflow", o.o);}
8022 if(o.x){this.setStyle("overflow-x", o.x);}
8023 if(o.y){this.setStyle("overflow-y", o.y);}
8030 * Gets the x,y coordinates specified by the anchor position on the element.
8031 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8032 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8033 * {width: (target width), height: (target height)} (defaults to the element's current size)
8034 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8035 * @return {Array} [x, y] An array containing the element's x and y coordinates
8037 getAnchorXY : function(anchor, local, s){
8038 //Passing a different size is useful for pre-calculating anchors,
8039 //especially for anchored animations that change the el size.
8041 var w, h, vp = false;
8044 if(d == document.body || d == document){
8046 w = D.getViewWidth(); h = D.getViewHeight();
8048 w = this.getWidth(); h = this.getHeight();
8051 w = s.width; h = s.height;
8053 var x = 0, y = 0, r = Math.round;
8054 switch((anchor || "tl").toLowerCase()){
8096 var sc = this.getScroll();
8097 return [x + sc.left, y + sc.top];
8099 //Add the element's offset xy
8100 var o = this.getXY();
8101 return [x+o[0], y+o[1]];
8105 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8106 * supported position values.
8107 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8108 * @param {String} position The position to align to.
8109 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8110 * @return {Array} [x, y]
8112 getAlignToXY : function(el, p, o){
8116 throw "Element.alignTo with an element that doesn't exist";
8118 var c = false; //constrain to viewport
8119 var p1 = "", p2 = "";
8126 }else if(p.indexOf("-") == -1){
8129 p = p.toLowerCase();
8130 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8132 throw "Element.alignTo with an invalid alignment " + p;
8134 p1 = m[1]; p2 = m[2]; c = !!m[3];
8136 //Subtract the aligned el's internal xy from the target's offset xy
8137 //plus custom offset to get the aligned el's new offset xy
8138 var a1 = this.getAnchorXY(p1, true);
8139 var a2 = el.getAnchorXY(p2, false);
8140 var x = a2[0] - a1[0] + o[0];
8141 var y = a2[1] - a1[1] + o[1];
8143 //constrain the aligned el to viewport if necessary
8144 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8145 // 5px of margin for ie
8146 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8148 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8149 //perpendicular to the vp border, allow the aligned el to slide on that border,
8150 //otherwise swap the aligned el to the opposite border of the target.
8151 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8152 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8153 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8154 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8157 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8158 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8160 if((x+w) > dw + scrollX){
8161 x = swapX ? r.left-w : dw+scrollX-w;
8164 x = swapX ? r.right : scrollX;
8166 if((y+h) > dh + scrollY){
8167 y = swapY ? r.top-h : dh+scrollY-h;
8170 y = swapY ? r.bottom : scrollY;
8177 getConstrainToXY : function(){
8178 var os = {top:0, left:0, bottom:0, right: 0};
8180 return function(el, local, offsets, proposedXY){
8182 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8184 var vw, vh, vx = 0, vy = 0;
8185 if(el.dom == document.body || el.dom == document){
8186 vw = Roo.lib.Dom.getViewWidth();
8187 vh = Roo.lib.Dom.getViewHeight();
8189 vw = el.dom.clientWidth;
8190 vh = el.dom.clientHeight;
8192 var vxy = el.getXY();
8198 var s = el.getScroll();
8200 vx += offsets.left + s.left;
8201 vy += offsets.top + s.top;
8203 vw -= offsets.right;
8204 vh -= offsets.bottom;
8209 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8210 var x = xy[0], y = xy[1];
8211 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8213 // only move it if it needs it
8216 // first validate right/bottom
8225 // then make sure top/left isn't negative
8234 return moved ? [x, y] : false;
8239 adjustForConstraints : function(xy, parent, offsets){
8240 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8244 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8245 * document it aligns it to the viewport.
8246 * The position parameter is optional, and can be specified in any one of the following formats:
8248 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8249 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8250 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8251 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8252 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8253 * element's anchor point, and the second value is used as the target's anchor point.</li>
8255 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8256 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8257 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8258 * that specified in order to enforce the viewport constraints.
8259 * Following are all of the supported anchor positions:
8262 ----- -----------------------------
8263 tl The top left corner (default)
8264 t The center of the top edge
8265 tr The top right corner
8266 l The center of the left edge
8267 c In the center of the element
8268 r The center of the right edge
8269 bl The bottom left corner
8270 b The center of the bottom edge
8271 br The bottom right corner
8275 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8276 el.alignTo("other-el");
8278 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8279 el.alignTo("other-el", "tr?");
8281 // align the bottom right corner of el with the center left edge of other-el
8282 el.alignTo("other-el", "br-l?");
8284 // align the center of el with the bottom left corner of other-el and
8285 // adjust the x position by -6 pixels (and the y position by 0)
8286 el.alignTo("other-el", "c-bl", [-6, 0]);
8288 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8289 * @param {String} position The position to align to.
8290 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8291 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8292 * @return {Roo.Element} this
8294 alignTo : function(element, position, offsets, animate){
8295 var xy = this.getAlignToXY(element, position, offsets);
8296 this.setXY(xy, this.preanim(arguments, 3));
8301 * Anchors an element to another element and realigns it when the window is resized.
8302 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8303 * @param {String} position The position to align to.
8304 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8305 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8306 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8307 * is a number, it is used as the buffer delay (defaults to 50ms).
8308 * @param {Function} callback The function to call after the animation finishes
8309 * @return {Roo.Element} this
8311 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8312 var action = function(){
8313 this.alignTo(el, alignment, offsets, animate);
8314 Roo.callback(callback, this);
8316 Roo.EventManager.onWindowResize(action, this);
8317 var tm = typeof monitorScroll;
8318 if(tm != 'undefined'){
8319 Roo.EventManager.on(window, 'scroll', action, this,
8320 {buffer: tm == 'number' ? monitorScroll : 50});
8322 action.call(this); // align immediately
8326 * Clears any opacity settings from this element. Required in some cases for IE.
8327 * @return {Roo.Element} this
8329 clearOpacity : function(){
8330 if (window.ActiveXObject) {
8331 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8332 this.dom.style.filter = "";
8335 this.dom.style.opacity = "";
8336 this.dom.style["-moz-opacity"] = "";
8337 this.dom.style["-khtml-opacity"] = "";
8343 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8344 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8345 * @return {Roo.Element} this
8347 hide : function(animate){
8348 this.setVisible(false, this.preanim(arguments, 0));
8353 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8354 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8355 * @return {Roo.Element} this
8357 show : function(animate){
8358 this.setVisible(true, this.preanim(arguments, 0));
8363 * @private Test if size has a unit, otherwise appends the default
8365 addUnits : function(size){
8366 return Roo.Element.addUnits(size, this.defaultUnit);
8370 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8371 * @return {Roo.Element} this
8373 beginMeasure : function(){
8375 if(el.offsetWidth || el.offsetHeight){
8376 return this; // offsets work already
8379 var p = this.dom, b = document.body; // start with this element
8380 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8381 var pe = Roo.get(p);
8382 if(pe.getStyle('display') == 'none'){
8383 changed.push({el: p, visibility: pe.getStyle("visibility")});
8384 p.style.visibility = "hidden";
8385 p.style.display = "block";
8389 this._measureChanged = changed;
8395 * Restores displays to before beginMeasure was called
8396 * @return {Roo.Element} this
8398 endMeasure : function(){
8399 var changed = this._measureChanged;
8401 for(var i = 0, len = changed.length; i < len; i++) {
8403 r.el.style.visibility = r.visibility;
8404 r.el.style.display = "none";
8406 this._measureChanged = null;
8412 * Update the innerHTML of this element, optionally searching for and processing scripts
8413 * @param {String} html The new HTML
8414 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8415 * @param {Function} callback For async script loading you can be noticed when the update completes
8416 * @return {Roo.Element} this
8418 update : function(html, loadScripts, callback){
8419 if(typeof html == "undefined"){
8422 if(loadScripts !== true){
8423 this.dom.innerHTML = html;
8424 if(typeof callback == "function"){
8432 html += '<span id="' + id + '"></span>';
8434 E.onAvailable(id, function(){
8435 var hd = document.getElementsByTagName("head")[0];
8436 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8437 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8438 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8441 while(match = re.exec(html)){
8442 var attrs = match[1];
8443 var srcMatch = attrs ? attrs.match(srcRe) : false;
8444 if(srcMatch && srcMatch[2]){
8445 var s = document.createElement("script");
8446 s.src = srcMatch[2];
8447 var typeMatch = attrs.match(typeRe);
8448 if(typeMatch && typeMatch[2]){
8449 s.type = typeMatch[2];
8452 }else if(match[2] && match[2].length > 0){
8453 if(window.execScript) {
8454 window.execScript(match[2]);
8462 window.eval(match[2]);
8466 var el = document.getElementById(id);
8467 if(el){el.parentNode.removeChild(el);}
8468 if(typeof callback == "function"){
8472 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8477 * Direct access to the UpdateManager update() method (takes the same parameters).
8478 * @param {String/Function} url The url for this request or a function to call to get the url
8479 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8480 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8481 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8482 * @return {Roo.Element} this
8485 var um = this.getUpdateManager();
8486 um.update.apply(um, arguments);
8491 * Gets this element's UpdateManager
8492 * @return {Roo.UpdateManager} The UpdateManager
8494 getUpdateManager : function(){
8495 if(!this.updateManager){
8496 this.updateManager = new Roo.UpdateManager(this);
8498 return this.updateManager;
8502 * Disables text selection for this element (normalized across browsers)
8503 * @return {Roo.Element} this
8505 unselectable : function(){
8506 this.dom.unselectable = "on";
8507 this.swallowEvent("selectstart", true);
8508 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8509 this.addClass("x-unselectable");
8514 * Calculates the x, y to center this element on the screen
8515 * @return {Array} The x, y values [x, y]
8517 getCenterXY : function(){
8518 return this.getAlignToXY(document, 'c-c');
8522 * Centers the Element in either the viewport, or another Element.
8523 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8525 center : function(centerIn){
8526 this.alignTo(centerIn || document, 'c-c');
8531 * Tests various css rules/browsers to determine if this element uses a border box
8534 isBorderBox : function(){
8535 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8539 * Return a box {x, y, width, height} that can be used to set another elements
8540 * size/location to match this element.
8541 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8542 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8543 * @return {Object} box An object in the format {x, y, width, height}
8545 getBox : function(contentBox, local){
8550 var left = parseInt(this.getStyle("left"), 10) || 0;
8551 var top = parseInt(this.getStyle("top"), 10) || 0;
8554 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8556 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8558 var l = this.getBorderWidth("l")+this.getPadding("l");
8559 var r = this.getBorderWidth("r")+this.getPadding("r");
8560 var t = this.getBorderWidth("t")+this.getPadding("t");
8561 var b = this.getBorderWidth("b")+this.getPadding("b");
8562 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8564 bx.right = bx.x + bx.width;
8565 bx.bottom = bx.y + bx.height;
8570 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8571 for more information about the sides.
8572 * @param {String} sides
8575 getFrameWidth : function(sides, onlyContentBox){
8576 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8580 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8581 * @param {Object} box The box to fill {x, y, width, height}
8582 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8583 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8584 * @return {Roo.Element} this
8586 setBox : function(box, adjust, animate){
8587 var w = box.width, h = box.height;
8588 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8589 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8590 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8592 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8597 * Forces the browser to repaint this element
8598 * @return {Roo.Element} this
8600 repaint : function(){
8602 this.addClass("x-repaint");
8603 setTimeout(function(){
8604 Roo.get(dom).removeClass("x-repaint");
8610 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8611 * then it returns the calculated width of the sides (see getPadding)
8612 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8613 * @return {Object/Number}
8615 getMargins : function(side){
8618 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8619 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8620 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8621 right: parseInt(this.getStyle("margin-right"), 10) || 0
8624 return this.addStyles(side, El.margins);
8629 addStyles : function(sides, styles){
8631 for(var i = 0, len = sides.length; i < len; i++){
8632 v = this.getStyle(styles[sides.charAt(i)]);
8634 w = parseInt(v, 10);
8642 * Creates a proxy element of this element
8643 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8644 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8645 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8646 * @return {Roo.Element} The new proxy element
8648 createProxy : function(config, renderTo, matchBox){
8650 renderTo = Roo.getDom(renderTo);
8652 renderTo = document.body;
8654 config = typeof config == "object" ?
8655 config : {tag : "div", cls: config};
8656 var proxy = Roo.DomHelper.append(renderTo, config, true);
8658 proxy.setBox(this.getBox());
8664 * Puts a mask over this element to disable user interaction. Requires core.css.
8665 * This method can only be applied to elements which accept child nodes.
8666 * @param {String} msg (optional) A message to display in the mask
8667 * @param {String} msgCls (optional) A css class to apply to the msg element
8668 * @return {Element} The mask element
8670 mask : function(msg, msgCls){
8671 if(this.getStyle("position") == "static"){
8672 this.setStyle("position", "relative");
8675 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8677 this.addClass("x-masked");
8678 this._mask.setDisplayed(true);
8679 if(typeof msg == 'string'){
8681 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8683 var mm = this._maskMsg;
8684 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8685 mm.dom.firstChild.innerHTML = msg;
8686 mm.setDisplayed(true);
8689 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8690 this._mask.setHeight(this.getHeight());
8696 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8697 * it is cached for reuse.
8699 unmask : function(removeEl){
8701 if(removeEl === true){
8702 this._mask.remove();
8705 this._maskMsg.remove();
8706 delete this._maskMsg;
8709 this._mask.setDisplayed(false);
8711 this._maskMsg.setDisplayed(false);
8715 this.removeClass("x-masked");
8719 * Returns true if this element is masked
8722 isMasked : function(){
8723 return this._mask && this._mask.isVisible();
8727 * Creates an iframe shim for this element to keep selects and other windowed objects from
8729 * @return {Roo.Element} The new shim element
8731 createShim : function(){
8732 var el = document.createElement('iframe');
8733 el.frameBorder = 'no';
8734 el.className = 'roo-shim';
8735 if(Roo.isIE && Roo.isSecure){
8736 el.src = Roo.SSL_SECURE_URL;
8738 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8739 shim.autoBoxAdjust = false;
8744 * Removes this element from the DOM and deletes it from the cache
8746 remove : function(){
8747 if(this.dom.parentNode){
8748 this.dom.parentNode.removeChild(this.dom);
8750 delete El.cache[this.dom.id];
8754 * Sets up event handlers to add and remove a css class when the mouse is over this element
8755 * @param {String} className
8756 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8757 * mouseout events for children elements
8758 * @return {Roo.Element} this
8760 addClassOnOver : function(className, preventFlicker){
8761 this.on("mouseover", function(){
8762 Roo.fly(this, '_internal').addClass(className);
8764 var removeFn = function(e){
8765 if(preventFlicker !== true || !e.within(this, true)){
8766 Roo.fly(this, '_internal').removeClass(className);
8769 this.on("mouseout", removeFn, this.dom);
8774 * Sets up event handlers to add and remove a css class when this element has the focus
8775 * @param {String} className
8776 * @return {Roo.Element} this
8778 addClassOnFocus : function(className){
8779 this.on("focus", function(){
8780 Roo.fly(this, '_internal').addClass(className);
8782 this.on("blur", function(){
8783 Roo.fly(this, '_internal').removeClass(className);
8788 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
8789 * @param {String} className
8790 * @return {Roo.Element} this
8792 addClassOnClick : function(className){
8794 this.on("mousedown", function(){
8795 Roo.fly(dom, '_internal').addClass(className);
8796 var d = Roo.get(document);
8797 var fn = function(){
8798 Roo.fly(dom, '_internal').removeClass(className);
8799 d.removeListener("mouseup", fn);
8801 d.on("mouseup", fn);
8807 * Stops the specified event from bubbling and optionally prevents the default action
8808 * @param {String} eventName
8809 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8810 * @return {Roo.Element} this
8812 swallowEvent : function(eventName, preventDefault){
8813 var fn = function(e){
8814 e.stopPropagation();
8819 if(eventName instanceof Array){
8820 for(var i = 0, len = eventName.length; i < len; i++){
8821 this.on(eventName[i], fn);
8825 this.on(eventName, fn);
8832 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8835 * Sizes this element to its parent element's dimensions performing
8836 * neccessary box adjustments.
8837 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8838 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8839 * @return {Roo.Element} this
8841 fitToParent : function(monitorResize, targetParent) {
8842 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8843 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8844 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8847 var p = Roo.get(targetParent || this.dom.parentNode);
8848 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8849 if (monitorResize === true) {
8850 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8851 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8857 * Gets the next sibling, skipping text nodes
8858 * @return {HTMLElement} The next sibling or null
8860 getNextSibling : function(){
8861 var n = this.dom.nextSibling;
8862 while(n && n.nodeType != 1){
8869 * Gets the previous sibling, skipping text nodes
8870 * @return {HTMLElement} The previous sibling or null
8872 getPrevSibling : function(){
8873 var n = this.dom.previousSibling;
8874 while(n && n.nodeType != 1){
8875 n = n.previousSibling;
8882 * Appends the passed element(s) to this element
8883 * @param {String/HTMLElement/Array/Element/CompositeElement} el
8884 * @return {Roo.Element} this
8886 appendChild: function(el){
8893 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8894 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
8895 * automatically generated with the specified attributes.
8896 * @param {HTMLElement} insertBefore (optional) a child element of this element
8897 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8898 * @return {Roo.Element} The new child element
8900 createChild: function(config, insertBefore, returnDom){
8901 config = config || {tag:'div'};
8903 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8905 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
8909 * Appends this element to the passed element
8910 * @param {String/HTMLElement/Element} el The new parent element
8911 * @return {Roo.Element} this
8913 appendTo: function(el){
8914 el = Roo.getDom(el);
8915 el.appendChild(this.dom);
8920 * Inserts this element before the passed element in the DOM
8921 * @param {String/HTMLElement/Element} el The element to insert before
8922 * @return {Roo.Element} this
8924 insertBefore: function(el){
8925 el = Roo.getDom(el);
8926 el.parentNode.insertBefore(this.dom, el);
8931 * Inserts this element after the passed element in the DOM
8932 * @param {String/HTMLElement/Element} el The element to insert after
8933 * @return {Roo.Element} this
8935 insertAfter: function(el){
8936 el = Roo.getDom(el);
8937 el.parentNode.insertBefore(this.dom, el.nextSibling);
8942 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8943 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8944 * @return {Roo.Element} The new child
8946 insertFirst: function(el, returnDom){
8948 if(typeof el == 'object' && !el.nodeType){ // dh config
8949 return this.createChild(el, this.dom.firstChild, returnDom);
8951 el = Roo.getDom(el);
8952 this.dom.insertBefore(el, this.dom.firstChild);
8953 return !returnDom ? Roo.get(el) : el;
8958 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
8959 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8960 * @param {String} where (optional) 'before' or 'after' defaults to before
8961 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8962 * @return {Roo.Element} the inserted Element
8964 insertSibling: function(el, where, returnDom){
8965 where = where ? where.toLowerCase() : 'before';
8967 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
8969 if(typeof el == 'object' && !el.nodeType){ // dh config
8970 if(where == 'after' && !this.dom.nextSibling){
8971 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
8973 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
8977 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
8978 where == 'before' ? this.dom : this.dom.nextSibling);
8987 * Creates and wraps this element with another element
8988 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
8989 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8990 * @return {HTMLElement/Element} The newly created wrapper element
8992 wrap: function(config, returnDom){
8994 config = {tag: "div"};
8996 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
8997 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9002 * Replaces the passed element with this element
9003 * @param {String/HTMLElement/Element} el The element to replace
9004 * @return {Roo.Element} this
9006 replace: function(el){
9008 this.insertBefore(el);
9014 * Inserts an html fragment into this element
9015 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9016 * @param {String} html The HTML fragment
9017 * @param {Boolean} returnEl True to return an Roo.Element
9018 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9020 insertHtml : function(where, html, returnEl){
9021 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9022 return returnEl ? Roo.get(el) : el;
9026 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9027 * @param {Object} o The object with the attributes
9028 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9029 * @return {Roo.Element} this
9031 set : function(o, useSet){
9033 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9035 if(attr == "style" || typeof o[attr] == "function") continue;
9037 el.className = o["cls"];
9039 if(useSet) el.setAttribute(attr, o[attr]);
9040 else el[attr] = o[attr];
9044 Roo.DomHelper.applyStyles(el, o.style);
9050 * Convenience method for constructing a KeyMap
9051 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9052 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9053 * @param {Function} fn The function to call
9054 * @param {Object} scope (optional) The scope of the function
9055 * @return {Roo.KeyMap} The KeyMap created
9057 addKeyListener : function(key, fn, scope){
9059 if(typeof key != "object" || key instanceof Array){
9075 return new Roo.KeyMap(this, config);
9079 * Creates a KeyMap for this element
9080 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9081 * @return {Roo.KeyMap} The KeyMap created
9083 addKeyMap : function(config){
9084 return new Roo.KeyMap(this, config);
9088 * Returns true if this element is scrollable.
9091 isScrollable : function(){
9093 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9097 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9098 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9099 * @param {Number} value The new scroll value
9100 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9101 * @return {Element} this
9104 scrollTo : function(side, value, animate){
9105 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9107 this.dom[prop] = value;
9109 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9110 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9116 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9117 * within this element's scrollable range.
9118 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9119 * @param {Number} distance How far to scroll the element in pixels
9120 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9121 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9122 * was scrolled as far as it could go.
9124 scroll : function(direction, distance, animate){
9125 if(!this.isScrollable()){
9129 var l = el.scrollLeft, t = el.scrollTop;
9130 var w = el.scrollWidth, h = el.scrollHeight;
9131 var cw = el.clientWidth, ch = el.clientHeight;
9132 direction = direction.toLowerCase();
9133 var scrolled = false;
9134 var a = this.preanim(arguments, 2);
9139 var v = Math.min(l + distance, w-cw);
9140 this.scrollTo("left", v, a);
9147 var v = Math.max(l - distance, 0);
9148 this.scrollTo("left", v, a);
9156 var v = Math.max(t - distance, 0);
9157 this.scrollTo("top", v, a);
9165 var v = Math.min(t + distance, h-ch);
9166 this.scrollTo("top", v, a);
9175 * Translates the passed page coordinates into left/top css values for this element
9176 * @param {Number/Array} x The page x or an array containing [x, y]
9177 * @param {Number} y The page y
9178 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9180 translatePoints : function(x, y){
9181 if(typeof x == 'object' || x instanceof Array){
9184 var p = this.getStyle('position');
9185 var o = this.getXY();
9187 var l = parseInt(this.getStyle('left'), 10);
9188 var t = parseInt(this.getStyle('top'), 10);
9191 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9194 t = (p == "relative") ? 0 : this.dom.offsetTop;
9197 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9201 * Returns the current scroll position of the element.
9202 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9204 getScroll : function(){
9205 var d = this.dom, doc = document;
9206 if(d == doc || d == doc.body){
9207 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9208 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9209 return {left: l, top: t};
9211 return {left: d.scrollLeft, top: d.scrollTop};
9216 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9217 * are convert to standard 6 digit hex color.
9218 * @param {String} attr The css attribute
9219 * @param {String} defaultValue The default value to use when a valid color isn't found
9220 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9223 getColor : function(attr, defaultValue, prefix){
9224 var v = this.getStyle(attr);
9225 if(!v || v == "transparent" || v == "inherit") {
9226 return defaultValue;
9228 var color = typeof prefix == "undefined" ? "#" : prefix;
9229 if(v.substr(0, 4) == "rgb("){
9230 var rvs = v.slice(4, v.length -1).split(",");
9231 for(var i = 0; i < 3; i++){
9232 var h = parseInt(rvs[i]).toString(16);
9239 if(v.substr(0, 1) == "#"){
9241 for(var i = 1; i < 4; i++){
9242 var c = v.charAt(i);
9245 }else if(v.length == 7){
9246 color += v.substr(1);
9250 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9254 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9255 * gradient background, rounded corners and a 4-way shadow.
9256 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9257 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9258 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9259 * @return {Roo.Element} this
9261 boxWrap : function(cls){
9262 cls = cls || 'x-box';
9263 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9264 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9269 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9270 * @param {String} namespace The namespace in which to look for the attribute
9271 * @param {String} name The attribute name
9272 * @return {String} The attribute value
9274 getAttributeNS : Roo.isIE ? function(ns, name){
9276 var type = typeof d[ns+":"+name];
9277 if(type != 'undefined' && type != 'unknown'){
9278 return d[ns+":"+name];
9281 } : function(ns, name){
9283 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9287 var ep = El.prototype;
9290 * Appends an event handler (Shorthand for addListener)
9291 * @param {String} eventName The type of event to append
9292 * @param {Function} fn The method the event invokes
9293 * @param {Object} scope (optional) The scope (this object) of the fn
9294 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9297 ep.on = ep.addListener;
9299 ep.mon = ep.addListener;
9302 * Removes an event handler from this element (shorthand for removeListener)
9303 * @param {String} eventName the type of event to remove
9304 * @param {Function} fn the method the event invokes
9305 * @return {Roo.Element} this
9308 ep.un = ep.removeListener;
9311 * true to automatically adjust width and height settings for box-model issues (default to true)
9313 ep.autoBoxAdjust = true;
9316 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9319 El.addUnits = function(v, defaultUnit){
9320 if(v === "" || v == "auto"){
9323 if(v === undefined){
9326 if(typeof v == "number" || !El.unitPattern.test(v)){
9327 return v + (defaultUnit || 'px');
9332 // special markup used throughout Roo when box wrapping elements
9333 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9335 * Visibility mode constant - Use visibility to hide element
9341 * Visibility mode constant - Use display to hide element
9347 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9348 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9349 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9361 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9362 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9363 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9364 * @return {Element} The Element object
9367 El.get = function(el){
9369 if(!el){ return null; }
9370 if(typeof el == "string"){ // element id
9371 if(!(elm = document.getElementById(el))){
9374 if(ex = El.cache[el]){
9377 ex = El.cache[el] = new El(elm);
9380 }else if(el.tagName){ // dom element
9384 if(ex = El.cache[id]){
9387 ex = El.cache[id] = new El(el);
9390 }else if(el instanceof El){
9392 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9393 // catch case where it hasn't been appended
9394 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9397 }else if(el.isComposite){
9399 }else if(el instanceof Array){
9400 return El.select(el);
9401 }else if(el == document){
9402 // create a bogus element object representing the document object
9404 var f = function(){};
9405 f.prototype = El.prototype;
9407 docEl.dom = document;
9415 El.uncache = function(el){
9416 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9418 delete El.cache[a[i].id || a[i]];
9424 // Garbage collection - uncache elements/purge listeners on orphaned elements
9425 // so we don't hold a reference and cause the browser to retain them
9426 El.garbageCollect = function(){
9427 if(!Roo.enableGarbageCollector){
9428 clearInterval(El.collectorThread);
9431 for(var eid in El.cache){
9432 var el = El.cache[eid], d = el.dom;
9433 // -------------------------------------------------------
9434 // Determining what is garbage:
9435 // -------------------------------------------------------
9437 // dom node is null, definitely garbage
9438 // -------------------------------------------------------
9440 // no parentNode == direct orphan, definitely garbage
9441 // -------------------------------------------------------
9442 // !d.offsetParent && !document.getElementById(eid)
9443 // display none elements have no offsetParent so we will
9444 // also try to look it up by it's id. However, check
9445 // offsetParent first so we don't do unneeded lookups.
9446 // This enables collection of elements that are not orphans
9447 // directly, but somewhere up the line they have an orphan
9449 // -------------------------------------------------------
9450 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9451 delete El.cache[eid];
9452 if(d && Roo.enableListenerCollection){
9458 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9462 El.Flyweight = function(dom){
9465 El.Flyweight.prototype = El.prototype;
9467 El._flyweights = {};
9469 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9470 * the dom node can be overwritten by other code.
9471 * @param {String/HTMLElement} el The dom node or id
9472 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9473 * prevent conflicts (e.g. internally Roo uses "_internal")
9475 * @return {Element} The shared Element object
9477 El.fly = function(el, named){
9478 named = named || '_global';
9479 el = Roo.getDom(el);
9483 if(!El._flyweights[named]){
9484 El._flyweights[named] = new El.Flyweight();
9486 El._flyweights[named].dom = el;
9487 return El._flyweights[named];
9491 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9492 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9493 * Shorthand of {@link Roo.Element#get}
9494 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9495 * @return {Element} The Element object
9501 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9502 * the dom node can be overwritten by other code.
9503 * Shorthand of {@link Roo.Element#fly}
9504 * @param {String/HTMLElement} el The dom node or id
9505 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9506 * prevent conflicts (e.g. internally Roo uses "_internal")
9508 * @return {Element} The shared Element object
9514 // speedy lookup for elements never to box adjust
9515 var noBoxAdjust = Roo.isStrict ? {
9518 input:1, select:1, textarea:1
9520 if(Roo.isIE || Roo.isGecko){
9521 noBoxAdjust['button'] = 1;
9525 Roo.EventManager.on(window, 'unload', function(){
9527 delete El._flyweights;
9535 Roo.Element.selectorFunction = Roo.DomQuery.select;
9538 Roo.Element.select = function(selector, unique, root){
9540 if(typeof selector == "string"){
9541 els = Roo.Element.selectorFunction(selector, root);
9542 }else if(selector.length !== undefined){
9545 throw "Invalid selector";
9547 if(unique === true){
9548 return new Roo.CompositeElement(els);
9550 return new Roo.CompositeElementLite(els);
9554 * Selects elements based on the passed CSS selector to enable working on them as 1.
9555 * @param {String/Array} selector The CSS selector or an array of elements
9556 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9557 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9558 * @return {CompositeElementLite/CompositeElement}
9562 Roo.select = Roo.Element.select;
9579 * Ext JS Library 1.1.1
9580 * Copyright(c) 2006-2007, Ext JS, LLC.
9582 * Originally Released Under LGPL - original licence link has changed is not relivant.
9585 * <script type="text/javascript">
9590 //Notifies Element that fx methods are available
9591 Roo.enableFx = true;
9595 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9596 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9597 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9598 * Element effects to work.</p><br/>
9600 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9601 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9602 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9603 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9604 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9605 * expected results and should be done with care.</p><br/>
9607 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9608 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9611 ----- -----------------------------
9612 tl The top left corner
9613 t The center of the top edge
9614 tr The top right corner
9615 l The center of the left edge
9616 r The center of the right edge
9617 bl The bottom left corner
9618 b The center of the bottom edge
9619 br The bottom right corner
9621 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9622 * below are common options that can be passed to any Fx method.</b>
9623 * @cfg {Function} callback A function called when the effect is finished
9624 * @cfg {Object} scope The scope of the effect function
9625 * @cfg {String} easing A valid Easing value for the effect
9626 * @cfg {String} afterCls A css class to apply after the effect
9627 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9628 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9629 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9630 * effects that end with the element being visually hidden, ignored otherwise)
9631 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9632 * a function which returns such a specification that will be applied to the Element after the effect finishes
9633 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9634 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
9635 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9639 * Slides the element into view. An anchor point can be optionally passed to set the point of
9640 * origin for the slide effect. This function automatically handles wrapping the element with
9641 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9644 // default: slide the element in from the top
9647 // custom: slide the element in from the right with a 2-second duration
9648 el.slideIn('r', { duration: 2 });
9650 // common config options shown with default values
9656 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9657 * @param {Object} options (optional) Object literal with any of the Fx config options
9658 * @return {Roo.Element} The Element
9660 slideIn : function(anchor, o){
9661 var el = this.getFxEl();
9664 el.queueFx(o, function(){
9666 anchor = anchor || "t";
9668 // fix display to visibility
9671 // restore values after effect
9672 var r = this.getFxRestore();
9673 var b = this.getBox();
9674 // fixed size for slide
9678 var wrap = this.fxWrap(r.pos, o, "hidden");
9680 var st = this.dom.style;
9681 st.visibility = "visible";
9682 st.position = "absolute";
9684 // clear out temp styles after slide and unwrap
9685 var after = function(){
9686 el.fxUnwrap(wrap, r.pos, o);
9688 st.height = r.height;
9691 // time to calc the positions
9692 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9694 switch(anchor.toLowerCase()){
9696 wrap.setSize(b.width, 0);
9697 st.left = st.bottom = "0";
9701 wrap.setSize(0, b.height);
9702 st.right = st.top = "0";
9706 wrap.setSize(0, b.height);
9708 st.left = st.top = "0";
9709 a = {width: bw, points: pt};
9712 wrap.setSize(b.width, 0);
9713 wrap.setY(b.bottom);
9714 st.left = st.top = "0";
9715 a = {height: bh, points: pt};
9719 st.right = st.bottom = "0";
9720 a = {width: bw, height: bh};
9724 wrap.setY(b.y+b.height);
9725 st.right = st.top = "0";
9726 a = {width: bw, height: bh, points: pt};
9730 wrap.setXY([b.right, b.bottom]);
9731 st.left = st.top = "0";
9732 a = {width: bw, height: bh, points: pt};
9736 wrap.setX(b.x+b.width);
9737 st.left = st.bottom = "0";
9738 a = {width: bw, height: bh, points: pt};
9741 this.dom.style.visibility = "visible";
9744 arguments.callee.anim = wrap.fxanim(a,
9754 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9755 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9756 * 'hidden') but block elements will still take up space in the document. The element must be removed
9757 * from the DOM using the 'remove' config option if desired. This function automatically handles
9758 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9761 // default: slide the element out to the top
9764 // custom: slide the element out to the right with a 2-second duration
9765 el.slideOut('r', { duration: 2 });
9767 // common config options shown with default values
9775 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9776 * @param {Object} options (optional) Object literal with any of the Fx config options
9777 * @return {Roo.Element} The Element
9779 slideOut : function(anchor, o){
9780 var el = this.getFxEl();
9783 el.queueFx(o, function(){
9785 anchor = anchor || "t";
9787 // restore values after effect
9788 var r = this.getFxRestore();
9790 var b = this.getBox();
9791 // fixed size for slide
9795 var wrap = this.fxWrap(r.pos, o, "visible");
9797 var st = this.dom.style;
9798 st.visibility = "visible";
9799 st.position = "absolute";
9803 var after = function(){
9805 el.setDisplayed(false);
9810 el.fxUnwrap(wrap, r.pos, o);
9813 st.height = r.height;
9818 var a, zero = {to: 0};
9819 switch(anchor.toLowerCase()){
9821 st.left = st.bottom = "0";
9825 st.right = st.top = "0";
9829 st.left = st.top = "0";
9830 a = {width: zero, points: {to:[b.right, b.y]}};
9833 st.left = st.top = "0";
9834 a = {height: zero, points: {to:[b.x, b.bottom]}};
9837 st.right = st.bottom = "0";
9838 a = {width: zero, height: zero};
9841 st.right = st.top = "0";
9842 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9845 st.left = st.top = "0";
9846 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9849 st.left = st.bottom = "0";
9850 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9854 arguments.callee.anim = wrap.fxanim(a,
9864 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
9865 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
9866 * The element must be removed from the DOM using the 'remove' config option if desired.
9872 // common config options shown with default values
9880 * @param {Object} options (optional) Object literal with any of the Fx config options
9881 * @return {Roo.Element} The Element
9884 var el = this.getFxEl();
9887 el.queueFx(o, function(){
9888 this.clearOpacity();
9891 // restore values after effect
9892 var r = this.getFxRestore();
9893 var st = this.dom.style;
9895 var after = function(){
9897 el.setDisplayed(false);
9904 el.setPositioning(r.pos);
9906 st.height = r.height;
9911 var width = this.getWidth();
9912 var height = this.getHeight();
9914 arguments.callee.anim = this.fxanim({
9915 width : {to: this.adjustWidth(width * 2)},
9916 height : {to: this.adjustHeight(height * 2)},
9917 points : {by: [-(width * .5), -(height * .5)]},
9919 fontSize: {to:200, unit: "%"}
9930 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9931 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
9932 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9938 // all config options shown with default values
9946 * @param {Object} options (optional) Object literal with any of the Fx config options
9947 * @return {Roo.Element} The Element
9949 switchOff : function(o){
9950 var el = this.getFxEl();
9953 el.queueFx(o, function(){
9954 this.clearOpacity();
9957 // restore values after effect
9958 var r = this.getFxRestore();
9959 var st = this.dom.style;
9961 var after = function(){
9963 el.setDisplayed(false);
9969 el.setPositioning(r.pos);
9971 st.height = r.height;
9976 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
9977 this.clearOpacity();
9981 points:{by:[0, this.getHeight() * .5]}
9982 }, o, 'motion', 0.3, 'easeIn', after);
9983 }).defer(100, this);
9990 * Highlights the Element by setting a color (applies to the background-color by default, but can be
9991 * changed using the "attr" config option) and then fading back to the original color. If no original
9992 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
9995 // default: highlight background to yellow
9998 // custom: highlight foreground text to blue for 2 seconds
9999 el.highlight("0000ff", { attr: 'color', duration: 2 });
10001 // common config options shown with default values
10002 el.highlight("ffff9c", {
10003 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10004 endColor: (current color) or "ffffff",
10009 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10010 * @param {Object} options (optional) Object literal with any of the Fx config options
10011 * @return {Roo.Element} The Element
10013 highlight : function(color, o){
10014 var el = this.getFxEl();
10017 el.queueFx(o, function(){
10018 color = color || "ffff9c";
10019 attr = o.attr || "backgroundColor";
10021 this.clearOpacity();
10024 var origColor = this.getColor(attr);
10025 var restoreColor = this.dom.style[attr];
10026 endColor = (o.endColor || origColor) || "ffffff";
10028 var after = function(){
10029 el.dom.style[attr] = restoreColor;
10034 a[attr] = {from: color, to: endColor};
10035 arguments.callee.anim = this.fxanim(a,
10045 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10048 // default: a single light blue ripple
10051 // custom: 3 red ripples lasting 3 seconds total
10052 el.frame("ff0000", 3, { duration: 3 });
10054 // common config options shown with default values
10055 el.frame("C3DAF9", 1, {
10056 duration: 1 //duration of entire animation (not each individual ripple)
10057 // Note: Easing is not configurable and will be ignored if included
10060 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10061 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10062 * @param {Object} options (optional) Object literal with any of the Fx config options
10063 * @return {Roo.Element} The Element
10065 frame : function(color, count, o){
10066 var el = this.getFxEl();
10069 el.queueFx(o, function(){
10070 color = color || "#C3DAF9";
10071 if(color.length == 6){
10072 color = "#" + color;
10074 count = count || 1;
10075 duration = o.duration || 1;
10078 var b = this.getBox();
10079 var animFn = function(){
10080 var proxy = this.createProxy({
10083 visbility:"hidden",
10084 position:"absolute",
10085 "z-index":"35000", // yee haw
10086 border:"0px solid " + color
10089 var scale = Roo.isBorderBox ? 2 : 1;
10091 top:{from:b.y, to:b.y - 20},
10092 left:{from:b.x, to:b.x - 20},
10093 borderWidth:{from:0, to:10},
10094 opacity:{from:1, to:0},
10095 height:{from:b.height, to:(b.height + (20*scale))},
10096 width:{from:b.width, to:(b.width + (20*scale))}
10097 }, duration, function(){
10101 animFn.defer((duration/2)*1000, this);
10112 * Creates a pause before any subsequent queued effects begin. If there are
10113 * no effects queued after the pause it will have no effect.
10118 * @param {Number} seconds The length of time to pause (in seconds)
10119 * @return {Roo.Element} The Element
10121 pause : function(seconds){
10122 var el = this.getFxEl();
10125 el.queueFx(o, function(){
10126 setTimeout(function(){
10128 }, seconds * 1000);
10134 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10135 * using the "endOpacity" config option.
10138 // default: fade in from opacity 0 to 100%
10141 // custom: fade in from opacity 0 to 75% over 2 seconds
10142 el.fadeIn({ endOpacity: .75, duration: 2});
10144 // common config options shown with default values
10146 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10151 * @param {Object} options (optional) Object literal with any of the Fx config options
10152 * @return {Roo.Element} The Element
10154 fadeIn : function(o){
10155 var el = this.getFxEl();
10157 el.queueFx(o, function(){
10158 this.setOpacity(0);
10160 this.dom.style.visibility = 'visible';
10161 var to = o.endOpacity || 1;
10162 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10163 o, null, .5, "easeOut", function(){
10165 this.clearOpacity();
10174 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10175 * using the "endOpacity" config option.
10178 // default: fade out from the element's current opacity to 0
10181 // custom: fade out from the element's current opacity to 25% over 2 seconds
10182 el.fadeOut({ endOpacity: .25, duration: 2});
10184 // common config options shown with default values
10186 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10193 * @param {Object} options (optional) Object literal with any of the Fx config options
10194 * @return {Roo.Element} The Element
10196 fadeOut : function(o){
10197 var el = this.getFxEl();
10199 el.queueFx(o, function(){
10200 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10201 o, null, .5, "easeOut", function(){
10202 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10203 this.dom.style.display = "none";
10205 this.dom.style.visibility = "hidden";
10207 this.clearOpacity();
10215 * Animates the transition of an element's dimensions from a starting height/width
10216 * to an ending height/width.
10219 // change height and width to 100x100 pixels
10220 el.scale(100, 100);
10222 // common config options shown with default values. The height and width will default to
10223 // the element's existing values if passed as null.
10226 [element's height], {
10231 * @param {Number} width The new width (pass undefined to keep the original width)
10232 * @param {Number} height The new height (pass undefined to keep the original height)
10233 * @param {Object} options (optional) Object literal with any of the Fx config options
10234 * @return {Roo.Element} The Element
10236 scale : function(w, h, o){
10237 this.shift(Roo.apply({}, o, {
10245 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10246 * Any of these properties not specified in the config object will not be changed. This effect
10247 * requires that at least one new dimension, position or opacity setting must be passed in on
10248 * the config object in order for the function to have any effect.
10251 // slide the element horizontally to x position 200 while changing the height and opacity
10252 el.shift({ x: 200, height: 50, opacity: .8 });
10254 // common config options shown with default values.
10256 width: [element's width],
10257 height: [element's height],
10258 x: [element's x position],
10259 y: [element's y position],
10260 opacity: [element's opacity],
10265 * @param {Object} options Object literal with any of the Fx config options
10266 * @return {Roo.Element} The Element
10268 shift : function(o){
10269 var el = this.getFxEl();
10271 el.queueFx(o, function(){
10272 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10273 if(w !== undefined){
10274 a.width = {to: this.adjustWidth(w)};
10276 if(h !== undefined){
10277 a.height = {to: this.adjustHeight(h)};
10279 if(x !== undefined || y !== undefined){
10281 x !== undefined ? x : this.getX(),
10282 y !== undefined ? y : this.getY()
10285 if(op !== undefined){
10286 a.opacity = {to: op};
10288 if(o.xy !== undefined){
10289 a.points = {to: o.xy};
10291 arguments.callee.anim = this.fxanim(a,
10292 o, 'motion', .35, "easeOut", function(){
10300 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10301 * ending point of the effect.
10304 // default: slide the element downward while fading out
10307 // custom: slide the element out to the right with a 2-second duration
10308 el.ghost('r', { duration: 2 });
10310 // common config options shown with default values
10318 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10319 * @param {Object} options (optional) Object literal with any of the Fx config options
10320 * @return {Roo.Element} The Element
10322 ghost : function(anchor, o){
10323 var el = this.getFxEl();
10326 el.queueFx(o, function(){
10327 anchor = anchor || "b";
10329 // restore values after effect
10330 var r = this.getFxRestore();
10331 var w = this.getWidth(),
10332 h = this.getHeight();
10334 var st = this.dom.style;
10336 var after = function(){
10338 el.setDisplayed(false);
10344 el.setPositioning(r.pos);
10345 st.width = r.width;
10346 st.height = r.height;
10351 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10352 switch(anchor.toLowerCase()){
10379 arguments.callee.anim = this.fxanim(a,
10389 * Ensures that all effects queued after syncFx is called on the element are
10390 * run concurrently. This is the opposite of {@link #sequenceFx}.
10391 * @return {Roo.Element} The Element
10393 syncFx : function(){
10394 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10403 * Ensures that all effects queued after sequenceFx is called on the element are
10404 * run in sequence. This is the opposite of {@link #syncFx}.
10405 * @return {Roo.Element} The Element
10407 sequenceFx : function(){
10408 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10410 concurrent : false,
10417 nextFx : function(){
10418 var ef = this.fxQueue[0];
10425 * Returns true if the element has any effects actively running or queued, else returns false.
10426 * @return {Boolean} True if element has active effects, else false
10428 hasActiveFx : function(){
10429 return this.fxQueue && this.fxQueue[0];
10433 * Stops any running effects and clears the element's internal effects queue if it contains
10434 * any additional effects that haven't started yet.
10435 * @return {Roo.Element} The Element
10437 stopFx : function(){
10438 if(this.hasActiveFx()){
10439 var cur = this.fxQueue[0];
10440 if(cur && cur.anim && cur.anim.isAnimated()){
10441 this.fxQueue = [cur]; // clear out others
10442 cur.anim.stop(true);
10449 beforeFx : function(o){
10450 if(this.hasActiveFx() && !o.concurrent){
10461 * Returns true if the element is currently blocking so that no other effect can be queued
10462 * until this effect is finished, else returns false if blocking is not set. This is commonly
10463 * used to ensure that an effect initiated by a user action runs to completion prior to the
10464 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10465 * @return {Boolean} True if blocking, else false
10467 hasFxBlock : function(){
10468 var q = this.fxQueue;
10469 return q && q[0] && q[0].block;
10473 queueFx : function(o, fn){
10477 if(!this.hasFxBlock()){
10478 Roo.applyIf(o, this.fxDefaults);
10480 var run = this.beforeFx(o);
10481 fn.block = o.block;
10482 this.fxQueue.push(fn);
10494 fxWrap : function(pos, o, vis){
10496 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10499 wrapXY = this.getXY();
10501 var div = document.createElement("div");
10502 div.style.visibility = vis;
10503 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10504 wrap.setPositioning(pos);
10505 if(wrap.getStyle("position") == "static"){
10506 wrap.position("relative");
10508 this.clearPositioning('auto');
10510 wrap.dom.appendChild(this.dom);
10512 wrap.setXY(wrapXY);
10519 fxUnwrap : function(wrap, pos, o){
10520 this.clearPositioning();
10521 this.setPositioning(pos);
10523 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10529 getFxRestore : function(){
10530 var st = this.dom.style;
10531 return {pos: this.getPositioning(), width: st.width, height : st.height};
10535 afterFx : function(o){
10537 this.applyStyles(o.afterStyle);
10540 this.addClass(o.afterCls);
10542 if(o.remove === true){
10545 Roo.callback(o.callback, o.scope, [this]);
10547 this.fxQueue.shift();
10553 getFxEl : function(){ // support for composite element fx
10554 return Roo.get(this.dom);
10558 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10559 animType = animType || 'run';
10561 var anim = Roo.lib.Anim[animType](
10563 (opt.duration || defaultDur) || .35,
10564 (opt.easing || defaultEase) || 'easeOut',
10566 Roo.callback(cb, this);
10575 // backwords compat
10576 Roo.Fx.resize = Roo.Fx.scale;
10578 //When included, Roo.Fx is automatically applied to Element so that all basic
10579 //effects are available directly via the Element API
10580 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10582 * Ext JS Library 1.1.1
10583 * Copyright(c) 2006-2007, Ext JS, LLC.
10585 * Originally Released Under LGPL - original licence link has changed is not relivant.
10588 * <script type="text/javascript">
10593 * @class Roo.CompositeElement
10594 * Standard composite class. Creates a Roo.Element for every element in the collection.
10596 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10597 * actions will be performed on all the elements in this collection.</b>
10599 * All methods return <i>this</i> and can be chained.
10601 var els = Roo.select("#some-el div.some-class", true);
10602 // or select directly from an existing element
10603 var el = Roo.get('some-el');
10604 el.select('div.some-class', true);
10606 els.setWidth(100); // all elements become 100 width
10607 els.hide(true); // all elements fade out and hide
10609 els.setWidth(100).hide(true);
10612 Roo.CompositeElement = function(els){
10613 this.elements = [];
10614 this.addElements(els);
10616 Roo.CompositeElement.prototype = {
10618 addElements : function(els){
10619 if(!els) return this;
10620 if(typeof els == "string"){
10621 els = Roo.Element.selectorFunction(els);
10623 var yels = this.elements;
10624 var index = yels.length-1;
10625 for(var i = 0, len = els.length; i < len; i++) {
10626 yels[++index] = Roo.get(els[i]);
10632 * Clears this composite and adds the elements returned by the passed selector.
10633 * @param {String/Array} els A string CSS selector, an array of elements or an element
10634 * @return {CompositeElement} this
10636 fill : function(els){
10637 this.elements = [];
10643 * Filters this composite to only elements that match the passed selector.
10644 * @param {String} selector A string CSS selector
10645 * @return {CompositeElement} this
10647 filter : function(selector){
10649 this.each(function(el){
10650 if(el.is(selector)){
10651 els[els.length] = el.dom;
10658 invoke : function(fn, args){
10659 var els = this.elements;
10660 for(var i = 0, len = els.length; i < len; i++) {
10661 Roo.Element.prototype[fn].apply(els[i], args);
10666 * Adds elements to this composite.
10667 * @param {String/Array} els A string CSS selector, an array of elements or an element
10668 * @return {CompositeElement} this
10670 add : function(els){
10671 if(typeof els == "string"){
10672 this.addElements(Roo.Element.selectorFunction(els));
10673 }else if(els.length !== undefined){
10674 this.addElements(els);
10676 this.addElements([els]);
10681 * Calls the passed function passing (el, this, index) for each element in this composite.
10682 * @param {Function} fn The function to call
10683 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10684 * @return {CompositeElement} this
10686 each : function(fn, scope){
10687 var els = this.elements;
10688 for(var i = 0, len = els.length; i < len; i++){
10689 if(fn.call(scope || els[i], els[i], this, i) === false) {
10697 * Returns the Element object at the specified index
10698 * @param {Number} index
10699 * @return {Roo.Element}
10701 item : function(index){
10702 return this.elements[index] || null;
10706 * Returns the first Element
10707 * @return {Roo.Element}
10709 first : function(){
10710 return this.item(0);
10714 * Returns the last Element
10715 * @return {Roo.Element}
10718 return this.item(this.elements.length-1);
10722 * Returns the number of elements in this composite
10725 getCount : function(){
10726 return this.elements.length;
10730 * Returns true if this composite contains the passed element
10733 contains : function(el){
10734 return this.indexOf(el) !== -1;
10738 * Returns true if this composite contains the passed element
10741 indexOf : function(el){
10742 return this.elements.indexOf(Roo.get(el));
10747 * Removes the specified element(s).
10748 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10749 * or an array of any of those.
10750 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10751 * @return {CompositeElement} this
10753 removeElement : function(el, removeDom){
10754 if(el instanceof Array){
10755 for(var i = 0, len = el.length; i < len; i++){
10756 this.removeElement(el[i]);
10760 var index = typeof el == 'number' ? el : this.indexOf(el);
10763 var d = this.elements[index];
10767 d.parentNode.removeChild(d);
10770 this.elements.splice(index, 1);
10776 * Replaces the specified element with the passed element.
10777 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10779 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10780 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10781 * @return {CompositeElement} this
10783 replaceElement : function(el, replacement, domReplace){
10784 var index = typeof el == 'number' ? el : this.indexOf(el);
10787 this.elements[index].replaceWith(replacement);
10789 this.elements.splice(index, 1, Roo.get(replacement))
10796 * Removes all elements.
10798 clear : function(){
10799 this.elements = [];
10803 Roo.CompositeElement.createCall = function(proto, fnName){
10804 if(!proto[fnName]){
10805 proto[fnName] = function(){
10806 return this.invoke(fnName, arguments);
10810 for(var fnName in Roo.Element.prototype){
10811 if(typeof Roo.Element.prototype[fnName] == "function"){
10812 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10818 * Ext JS Library 1.1.1
10819 * Copyright(c) 2006-2007, Ext JS, LLC.
10821 * Originally Released Under LGPL - original licence link has changed is not relivant.
10824 * <script type="text/javascript">
10828 * @class Roo.CompositeElementLite
10829 * @extends Roo.CompositeElement
10830 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10832 var els = Roo.select("#some-el div.some-class");
10833 // or select directly from an existing element
10834 var el = Roo.get('some-el');
10835 el.select('div.some-class');
10837 els.setWidth(100); // all elements become 100 width
10838 els.hide(true); // all elements fade out and hide
10840 els.setWidth(100).hide(true);
10841 </code></pre><br><br>
10842 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10843 * actions will be performed on all the elements in this collection.</b>
10845 Roo.CompositeElementLite = function(els){
10846 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10847 this.el = new Roo.Element.Flyweight();
10849 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10850 addElements : function(els){
10852 if(els instanceof Array){
10853 this.elements = this.elements.concat(els);
10855 var yels = this.elements;
10856 var index = yels.length-1;
10857 for(var i = 0, len = els.length; i < len; i++) {
10858 yels[++index] = els[i];
10864 invoke : function(fn, args){
10865 var els = this.elements;
10867 for(var i = 0, len = els.length; i < len; i++) {
10869 Roo.Element.prototype[fn].apply(el, args);
10874 * Returns a flyweight Element of the dom element object at the specified index
10875 * @param {Number} index
10876 * @return {Roo.Element}
10878 item : function(index){
10879 if(!this.elements[index]){
10882 this.el.dom = this.elements[index];
10886 // fixes scope with flyweight
10887 addListener : function(eventName, handler, scope, opt){
10888 var els = this.elements;
10889 for(var i = 0, len = els.length; i < len; i++) {
10890 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10896 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10897 * passed is the flyweight (shared) Roo.Element instance, so if you require a
10898 * a reference to the dom node, use el.dom.</b>
10899 * @param {Function} fn The function to call
10900 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10901 * @return {CompositeElement} this
10903 each : function(fn, scope){
10904 var els = this.elements;
10906 for(var i = 0, len = els.length; i < len; i++){
10908 if(fn.call(scope || el, el, this, i) === false){
10915 indexOf : function(el){
10916 return this.elements.indexOf(Roo.getDom(el));
10919 replaceElement : function(el, replacement, domReplace){
10920 var index = typeof el == 'number' ? el : this.indexOf(el);
10922 replacement = Roo.getDom(replacement);
10924 var d = this.elements[index];
10925 d.parentNode.insertBefore(replacement, d);
10926 d.parentNode.removeChild(d);
10928 this.elements.splice(index, 1, replacement);
10933 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10937 * Ext JS Library 1.1.1
10938 * Copyright(c) 2006-2007, Ext JS, LLC.
10940 * Originally Released Under LGPL - original licence link has changed is not relivant.
10943 * <script type="text/javascript">
10949 * @class Roo.data.Connection
10950 * @extends Roo.util.Observable
10951 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
10952 * either to a configured URL, or to a URL specified at request time.<br><br>
10954 * Requests made by this class are asynchronous, and will return immediately. No data from
10955 * the server will be available to the statement immediately following the {@link #request} call.
10956 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
10958 * Note: If you are doing a file upload, you will not get a normal response object sent back to
10959 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
10960 * The response object is created using the innerHTML of the IFRAME's document as the responseText
10961 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
10962 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
10963 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
10964 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
10965 * standard DOM methods.
10967 * @param {Object} config a configuration object.
10969 Roo.data.Connection = function(config){
10970 Roo.apply(this, config);
10973 * @event beforerequest
10974 * Fires before a network request is made to retrieve a data object.
10975 * @param {Connection} conn This Connection object.
10976 * @param {Object} options The options config object passed to the {@link #request} method.
10978 "beforerequest" : true,
10980 * @event requestcomplete
10981 * Fires if the request was successfully completed.
10982 * @param {Connection} conn This Connection object.
10983 * @param {Object} response The XHR object containing the response data.
10984 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
10985 * @param {Object} options The options config object passed to the {@link #request} method.
10987 "requestcomplete" : true,
10989 * @event requestexception
10990 * Fires if an error HTTP status was returned from the server.
10991 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
10992 * @param {Connection} conn This Connection object.
10993 * @param {Object} response The XHR object containing the response data.
10994 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
10995 * @param {Object} options The options config object passed to the {@link #request} method.
10997 "requestexception" : true
10999 Roo.data.Connection.superclass.constructor.call(this);
11002 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11004 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11007 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11008 * extra parameters to each request made by this object. (defaults to undefined)
11011 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11012 * to each request made by this object. (defaults to undefined)
11015 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11018 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11022 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11028 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11031 disableCaching: true,
11034 * Sends an HTTP request to a remote server.
11035 * @param {Object} options An object which may contain the following properties:<ul>
11036 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11037 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11038 * request, a url encoded string or a function to call to get either.</li>
11039 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11040 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11041 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11042 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11043 * <li>options {Object} The parameter to the request call.</li>
11044 * <li>success {Boolean} True if the request succeeded.</li>
11045 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11047 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11048 * The callback is passed the following parameters:<ul>
11049 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11050 * <li>options {Object} The parameter to the request call.</li>
11052 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11053 * The callback is passed the following parameters:<ul>
11054 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11055 * <li>options {Object} The parameter to the request call.</li>
11057 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11058 * for the callback function. Defaults to the browser window.</li>
11059 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11060 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11061 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11062 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11063 * params for the post data. Any params will be appended to the URL.</li>
11064 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11066 * @return {Number} transactionId
11068 request : function(o){
11069 if(this.fireEvent("beforerequest", this, o) !== false){
11072 if(typeof p == "function"){
11073 p = p.call(o.scope||window, o);
11075 if(typeof p == "object"){
11076 p = Roo.urlEncode(o.params);
11078 if(this.extraParams){
11079 var extras = Roo.urlEncode(this.extraParams);
11080 p = p ? (p + '&' + extras) : extras;
11083 var url = o.url || this.url;
11084 if(typeof url == 'function'){
11085 url = url.call(o.scope||window, o);
11089 var form = Roo.getDom(o.form);
11090 url = url || form.action;
11092 var enctype = form.getAttribute("enctype");
11093 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11094 return this.doFormUpload(o, p, url);
11096 var f = Roo.lib.Ajax.serializeForm(form);
11097 p = p ? (p + '&' + f) : f;
11100 var hs = o.headers;
11101 if(this.defaultHeaders){
11102 hs = Roo.apply(hs || {}, this.defaultHeaders);
11109 success: this.handleResponse,
11110 failure: this.handleFailure,
11112 argument: {options: o},
11113 timeout : this.timeout
11116 var method = o.method||this.method||(p ? "POST" : "GET");
11118 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11119 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11122 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11126 }else if(this.autoAbort !== false){
11130 if((method == 'GET' && p) || o.xmlData){
11131 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11134 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11135 return this.transId;
11137 Roo.callback(o.callback, o.scope, [o, null, null]);
11143 * Determine whether this object has a request outstanding.
11144 * @param {Number} transactionId (Optional) defaults to the last transaction
11145 * @return {Boolean} True if there is an outstanding request.
11147 isLoading : function(transId){
11149 return Roo.lib.Ajax.isCallInProgress(transId);
11151 return this.transId ? true : false;
11156 * Aborts any outstanding request.
11157 * @param {Number} transactionId (Optional) defaults to the last transaction
11159 abort : function(transId){
11160 if(transId || this.isLoading()){
11161 Roo.lib.Ajax.abort(transId || this.transId);
11166 handleResponse : function(response){
11167 this.transId = false;
11168 var options = response.argument.options;
11169 response.argument = options ? options.argument : null;
11170 this.fireEvent("requestcomplete", this, response, options);
11171 Roo.callback(options.success, options.scope, [response, options]);
11172 Roo.callback(options.callback, options.scope, [options, true, response]);
11176 handleFailure : function(response, e){
11177 this.transId = false;
11178 var options = response.argument.options;
11179 response.argument = options ? options.argument : null;
11180 this.fireEvent("requestexception", this, response, options, e);
11181 Roo.callback(options.failure, options.scope, [response, options]);
11182 Roo.callback(options.callback, options.scope, [options, false, response]);
11186 doFormUpload : function(o, ps, url){
11188 var frame = document.createElement('iframe');
11191 frame.className = 'x-hidden';
11193 frame.src = Roo.SSL_SECURE_URL;
11195 document.body.appendChild(frame);
11198 document.frames[id].name = id;
11201 var form = Roo.getDom(o.form);
11203 form.method = 'POST';
11204 form.enctype = form.encoding = 'multipart/form-data';
11210 if(ps){ // add dynamic params
11212 ps = Roo.urlDecode(ps, false);
11214 if(ps.hasOwnProperty(k)){
11215 hd = document.createElement('input');
11216 hd.type = 'hidden';
11219 form.appendChild(hd);
11226 var r = { // bogus response object
11231 r.argument = o ? o.argument : null;
11236 doc = frame.contentWindow.document;
11238 doc = (frame.contentDocument || window.frames[id].document);
11240 if(doc && doc.body){
11241 r.responseText = doc.body.innerHTML;
11243 if(doc && doc.XMLDocument){
11244 r.responseXML = doc.XMLDocument;
11246 r.responseXML = doc;
11253 Roo.EventManager.removeListener(frame, 'load', cb, this);
11255 this.fireEvent("requestcomplete", this, r, o);
11256 Roo.callback(o.success, o.scope, [r, o]);
11257 Roo.callback(o.callback, o.scope, [o, true, r]);
11259 setTimeout(function(){document.body.removeChild(frame);}, 100);
11262 Roo.EventManager.on(frame, 'load', cb, this);
11265 if(hiddens){ // remove dynamic params
11266 for(var i = 0, len = hiddens.length; i < len; i++){
11267 form.removeChild(hiddens[i]);
11275 * @extends Roo.data.Connection
11276 * Global Ajax request class.
11280 Roo.Ajax = new Roo.data.Connection({
11283 * @cfg {String} url @hide
11286 * @cfg {Object} extraParams @hide
11289 * @cfg {Object} defaultHeaders @hide
11292 * @cfg {String} method (Optional) @hide
11295 * @cfg {Number} timeout (Optional) @hide
11298 * @cfg {Boolean} autoAbort (Optional) @hide
11302 * @cfg {Boolean} disableCaching (Optional) @hide
11306 * @property disableCaching
11307 * True to add a unique cache-buster param to GET requests. (defaults to true)
11312 * The default URL to be used for requests to the server. (defaults to undefined)
11316 * @property extraParams
11317 * An object containing properties which are used as
11318 * extra parameters to each request made by this object. (defaults to undefined)
11322 * @property defaultHeaders
11323 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11328 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11332 * @property timeout
11333 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11338 * @property autoAbort
11339 * Whether a new request should abort any pending requests. (defaults to false)
11345 * Serialize the passed form into a url encoded string
11346 * @param {String/HTMLElement} form
11349 serializeForm : function(form){
11350 return Roo.lib.Ajax.serializeForm(form);
11354 * Ext JS Library 1.1.1
11355 * Copyright(c) 2006-2007, Ext JS, LLC.
11357 * Originally Released Under LGPL - original licence link has changed is not relivant.
11360 * <script type="text/javascript">
11365 * @extends Roo.data.Connection
11366 * Global Ajax request class.
11368 * @instanceOf Roo.data.Connection
11370 Roo.Ajax = new Roo.data.Connection({
11379 * @cfg {String} url @hide
11382 * @cfg {Object} extraParams @hide
11385 * @cfg {Object} defaultHeaders @hide
11388 * @cfg {String} method (Optional) @hide
11391 * @cfg {Number} timeout (Optional) @hide
11394 * @cfg {Boolean} autoAbort (Optional) @hide
11398 * @cfg {Boolean} disableCaching (Optional) @hide
11402 * @property disableCaching
11403 * True to add a unique cache-buster param to GET requests. (defaults to true)
11408 * The default URL to be used for requests to the server. (defaults to undefined)
11412 * @property extraParams
11413 * An object containing properties which are used as
11414 * extra parameters to each request made by this object. (defaults to undefined)
11418 * @property defaultHeaders
11419 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11424 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11428 * @property timeout
11429 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11434 * @property autoAbort
11435 * Whether a new request should abort any pending requests. (defaults to false)
11441 * Serialize the passed form into a url encoded string
11442 * @param {String/HTMLElement} form
11445 serializeForm : function(form){
11446 return Roo.lib.Ajax.serializeForm(form);
11450 * Ext JS Library 1.1.1
11451 * Copyright(c) 2006-2007, Ext JS, LLC.
11453 * Originally Released Under LGPL - original licence link has changed is not relivant.
11456 * <script type="text/javascript">
11461 * @class Roo.UpdateManager
11462 * @extends Roo.util.Observable
11463 * Provides AJAX-style update for Element object.<br><br>
11466 * // Get it from a Roo.Element object
11467 * var el = Roo.get("foo");
11468 * var mgr = el.getUpdateManager();
11469 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11471 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11473 * // or directly (returns the same UpdateManager instance)
11474 * var mgr = new Roo.UpdateManager("myElementId");
11475 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11476 * mgr.on("update", myFcnNeedsToKnow);
11478 // short handed call directly from the element object
11479 Roo.get("foo").load({
11483 text: "Loading Foo..."
11487 * Create new UpdateManager directly.
11488 * @param {String/HTMLElement/Roo.Element} el The element to update
11489 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11491 Roo.UpdateManager = function(el, forceNew){
11493 if(!forceNew && el.updateManager){
11494 return el.updateManager;
11497 * The Element object
11498 * @type Roo.Element
11502 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11505 this.defaultUrl = null;
11509 * @event beforeupdate
11510 * Fired before an update is made, return false from your handler and the update is cancelled.
11511 * @param {Roo.Element} el
11512 * @param {String/Object/Function} url
11513 * @param {String/Object} params
11515 "beforeupdate": true,
11518 * Fired after successful update is made.
11519 * @param {Roo.Element} el
11520 * @param {Object} oResponseObject The response Object
11525 * Fired on update failure.
11526 * @param {Roo.Element} el
11527 * @param {Object} oResponseObject The response Object
11531 var d = Roo.UpdateManager.defaults;
11533 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11536 this.sslBlankUrl = d.sslBlankUrl;
11538 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11541 this.disableCaching = d.disableCaching;
11543 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11546 this.indicatorText = d.indicatorText;
11548 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11551 this.showLoadIndicator = d.showLoadIndicator;
11553 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11556 this.timeout = d.timeout;
11559 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11562 this.loadScripts = d.loadScripts;
11565 * Transaction object of current executing transaction
11567 this.transaction = null;
11572 this.autoRefreshProcId = null;
11574 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11577 this.refreshDelegate = this.refresh.createDelegate(this);
11579 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11582 this.updateDelegate = this.update.createDelegate(this);
11584 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11587 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11591 this.successDelegate = this.processSuccess.createDelegate(this);
11595 this.failureDelegate = this.processFailure.createDelegate(this);
11597 if(!this.renderer){
11599 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11601 this.renderer = new Roo.UpdateManager.BasicRenderer();
11604 Roo.UpdateManager.superclass.constructor.call(this);
11607 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11609 * Get the Element this UpdateManager is bound to
11610 * @return {Roo.Element} The element
11612 getEl : function(){
11616 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11617 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11620 url: "your-url.php",<br/>
11621 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11622 callback: yourFunction,<br/>
11623 scope: yourObject, //(optional scope) <br/>
11624 discardUrl: false, <br/>
11625 nocache: false,<br/>
11626 text: "Loading...",<br/>
11628 scripts: false<br/>
11631 * The only required property is url. The optional properties nocache, text and scripts
11632 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11633 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11634 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11635 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11637 update : function(url, params, callback, discardUrl){
11638 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11639 var method = this.method, cfg;
11640 if(typeof url == "object"){ // must be config object
11643 params = params || cfg.params;
11644 callback = callback || cfg.callback;
11645 discardUrl = discardUrl || cfg.discardUrl;
11646 if(callback && cfg.scope){
11647 callback = callback.createDelegate(cfg.scope);
11649 if(typeof cfg.method != "undefined"){method = cfg.method;};
11650 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11651 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11652 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11653 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11655 this.showLoading();
11657 this.defaultUrl = url;
11659 if(typeof url == "function"){
11660 url = url.call(this);
11663 method = method || (params ? "POST" : "GET");
11664 if(method == "GET"){
11665 url = this.prepareUrl(url);
11668 var o = Roo.apply(cfg ||{}, {
11671 success: this.successDelegate,
11672 failure: this.failureDelegate,
11673 callback: undefined,
11674 timeout: (this.timeout*1000),
11675 argument: {"url": url, "form": null, "callback": callback, "params": params}
11678 this.transaction = Roo.Ajax.request(o);
11683 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11684 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11685 * @param {String/HTMLElement} form The form Id or form element
11686 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11687 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11688 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11690 formUpdate : function(form, url, reset, callback){
11691 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11692 if(typeof url == "function"){
11693 url = url.call(this);
11695 form = Roo.getDom(form);
11696 this.transaction = Roo.Ajax.request({
11699 success: this.successDelegate,
11700 failure: this.failureDelegate,
11701 timeout: (this.timeout*1000),
11702 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11704 this.showLoading.defer(1, this);
11709 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11710 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11712 refresh : function(callback){
11713 if(this.defaultUrl == null){
11716 this.update(this.defaultUrl, null, callback, true);
11720 * Set this element to auto refresh.
11721 * @param {Number} interval How often to update (in seconds).
11722 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11723 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11724 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11725 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11727 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11729 this.update(url || this.defaultUrl, params, callback, true);
11731 if(this.autoRefreshProcId){
11732 clearInterval(this.autoRefreshProcId);
11734 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11738 * Stop auto refresh on this element.
11740 stopAutoRefresh : function(){
11741 if(this.autoRefreshProcId){
11742 clearInterval(this.autoRefreshProcId);
11743 delete this.autoRefreshProcId;
11747 isAutoRefreshing : function(){
11748 return this.autoRefreshProcId ? true : false;
11751 * Called to update the element to "Loading" state. Override to perform custom action.
11753 showLoading : function(){
11754 if(this.showLoadIndicator){
11755 this.el.update(this.indicatorText);
11760 * Adds unique parameter to query string if disableCaching = true
11763 prepareUrl : function(url){
11764 if(this.disableCaching){
11765 var append = "_dc=" + (new Date().getTime());
11766 if(url.indexOf("?") !== -1){
11767 url += "&" + append;
11769 url += "?" + append;
11778 processSuccess : function(response){
11779 this.transaction = null;
11780 if(response.argument.form && response.argument.reset){
11781 try{ // put in try/catch since some older FF releases had problems with this
11782 response.argument.form.reset();
11785 if(this.loadScripts){
11786 this.renderer.render(this.el, response, this,
11787 this.updateComplete.createDelegate(this, [response]));
11789 this.renderer.render(this.el, response, this);
11790 this.updateComplete(response);
11794 updateComplete : function(response){
11795 this.fireEvent("update", this.el, response);
11796 if(typeof response.argument.callback == "function"){
11797 response.argument.callback(this.el, true, response);
11804 processFailure : function(response){
11805 this.transaction = null;
11806 this.fireEvent("failure", this.el, response);
11807 if(typeof response.argument.callback == "function"){
11808 response.argument.callback(this.el, false, response);
11813 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11814 * @param {Object} renderer The object implementing the render() method
11816 setRenderer : function(renderer){
11817 this.renderer = renderer;
11820 getRenderer : function(){
11821 return this.renderer;
11825 * Set the defaultUrl used for updates
11826 * @param {String/Function} defaultUrl The url or a function to call to get the url
11828 setDefaultUrl : function(defaultUrl){
11829 this.defaultUrl = defaultUrl;
11833 * Aborts the executing transaction
11835 abort : function(){
11836 if(this.transaction){
11837 Roo.Ajax.abort(this.transaction);
11842 * Returns true if an update is in progress
11843 * @return {Boolean}
11845 isUpdating : function(){
11846 if(this.transaction){
11847 return Roo.Ajax.isLoading(this.transaction);
11854 * @class Roo.UpdateManager.defaults
11855 * @static (not really - but it helps the doc tool)
11856 * The defaults collection enables customizing the default properties of UpdateManager
11858 Roo.UpdateManager.defaults = {
11860 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11866 * True to process scripts by default (Defaults to false).
11869 loadScripts : false,
11872 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11875 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11877 * Whether to append unique parameter on get request to disable caching (Defaults to false).
11880 disableCaching : false,
11882 * Whether to show indicatorText when loading (Defaults to true).
11885 showLoadIndicator : true,
11887 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
11890 indicatorText : '<div class="loading-indicator">Loading...</div>'
11894 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11896 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11897 * @param {String/HTMLElement/Roo.Element} el The element to update
11898 * @param {String} url The url
11899 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11900 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11903 * @member Roo.UpdateManager
11905 Roo.UpdateManager.updateElement = function(el, url, params, options){
11906 var um = Roo.get(el, true).getUpdateManager();
11907 Roo.apply(um, options);
11908 um.update(url, params, options ? options.callback : null);
11910 // alias for backwards compat
11911 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11913 * @class Roo.UpdateManager.BasicRenderer
11914 * Default Content renderer. Updates the elements innerHTML with the responseText.
11916 Roo.UpdateManager.BasicRenderer = function(){};
11918 Roo.UpdateManager.BasicRenderer.prototype = {
11920 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11921 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11922 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11923 * @param {Roo.Element} el The element being rendered
11924 * @param {Object} response The YUI Connect response object
11925 * @param {UpdateManager} updateManager The calling update manager
11926 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11928 render : function(el, response, updateManager, callback){
11929 el.update(response.responseText, updateManager.loadScripts, callback);
11934 * Ext JS Library 1.1.1
11935 * Copyright(c) 2006-2007, Ext JS, LLC.
11937 * Originally Released Under LGPL - original licence link has changed is not relivant.
11940 * <script type="text/javascript">
11944 * @class Roo.util.DelayedTask
11945 * Provides a convenient method of performing setTimeout where a new
11946 * timeout cancels the old timeout. An example would be performing validation on a keypress.
11947 * You can use this class to buffer
11948 * the keypress events for a certain number of milliseconds, and perform only if they stop
11949 * for that amount of time.
11950 * @constructor The parameters to this constructor serve as defaults and are not required.
11951 * @param {Function} fn (optional) The default function to timeout
11952 * @param {Object} scope (optional) The default scope of that timeout
11953 * @param {Array} args (optional) The default Array of arguments
11955 Roo.util.DelayedTask = function(fn, scope, args){
11956 var id = null, d, t;
11958 var call = function(){
11959 var now = new Date().getTime();
11963 fn.apply(scope, args || []);
11967 * Cancels any pending timeout and queues a new one
11968 * @param {Number} delay The milliseconds to delay
11969 * @param {Function} newFn (optional) Overrides function passed to constructor
11970 * @param {Object} newScope (optional) Overrides scope passed to constructor
11971 * @param {Array} newArgs (optional) Overrides args passed to constructor
11973 this.delay = function(delay, newFn, newScope, newArgs){
11974 if(id && delay != d){
11978 t = new Date().getTime();
11980 scope = newScope || scope;
11981 args = newArgs || args;
11983 id = setInterval(call, d);
11988 * Cancel the last queued timeout
11990 this.cancel = function(){
11998 * Ext JS Library 1.1.1
11999 * Copyright(c) 2006-2007, Ext JS, LLC.
12001 * Originally Released Under LGPL - original licence link has changed is not relivant.
12004 * <script type="text/javascript">
12008 Roo.util.TaskRunner = function(interval){
12009 interval = interval || 10;
12010 var tasks = [], removeQueue = [];
12012 var running = false;
12014 var stopThread = function(){
12020 var startThread = function(){
12023 id = setInterval(runTasks, interval);
12027 var removeTask = function(task){
12028 removeQueue.push(task);
12034 var runTasks = function(){
12035 if(removeQueue.length > 0){
12036 for(var i = 0, len = removeQueue.length; i < len; i++){
12037 tasks.remove(removeQueue[i]);
12040 if(tasks.length < 1){
12045 var now = new Date().getTime();
12046 for(var i = 0, len = tasks.length; i < len; ++i){
12048 var itime = now - t.taskRunTime;
12049 if(t.interval <= itime){
12050 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12051 t.taskRunTime = now;
12052 if(rt === false || t.taskRunCount === t.repeat){
12057 if(t.duration && t.duration <= (now - t.taskStartTime)){
12064 * Queues a new task.
12065 * @param {Object} task
12067 this.start = function(task){
12069 task.taskStartTime = new Date().getTime();
12070 task.taskRunTime = 0;
12071 task.taskRunCount = 0;
12076 this.stop = function(task){
12081 this.stopAll = function(){
12083 for(var i = 0, len = tasks.length; i < len; i++){
12084 if(tasks[i].onStop){
12093 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12095 * Ext JS Library 1.1.1
12096 * Copyright(c) 2006-2007, Ext JS, LLC.
12098 * Originally Released Under LGPL - original licence link has changed is not relivant.
12101 * <script type="text/javascript">
12106 * @class Roo.util.MixedCollection
12107 * @extends Roo.util.Observable
12108 * A Collection class that maintains both numeric indexes and keys and exposes events.
12110 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12111 * collection (defaults to false)
12112 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12113 * and return the key value for that item. This is used when available to look up the key on items that
12114 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12115 * equivalent to providing an implementation for the {@link #getKey} method.
12117 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12125 * Fires when the collection is cleared.
12130 * Fires when an item is added to the collection.
12131 * @param {Number} index The index at which the item was added.
12132 * @param {Object} o The item added.
12133 * @param {String} key The key associated with the added item.
12138 * Fires when an item is replaced in the collection.
12139 * @param {String} key he key associated with the new added.
12140 * @param {Object} old The item being replaced.
12141 * @param {Object} new The new item.
12146 * Fires when an item is removed from the collection.
12147 * @param {Object} o The item being removed.
12148 * @param {String} key (optional) The key associated with the removed item.
12153 this.allowFunctions = allowFunctions === true;
12155 this.getKey = keyFn;
12157 Roo.util.MixedCollection.superclass.constructor.call(this);
12160 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12161 allowFunctions : false,
12164 * Adds an item to the collection.
12165 * @param {String} key The key to associate with the item
12166 * @param {Object} o The item to add.
12167 * @return {Object} The item added.
12169 add : function(key, o){
12170 if(arguments.length == 1){
12172 key = this.getKey(o);
12174 if(typeof key == "undefined" || key === null){
12176 this.items.push(o);
12177 this.keys.push(null);
12179 var old = this.map[key];
12181 return this.replace(key, o);
12184 this.items.push(o);
12186 this.keys.push(key);
12188 this.fireEvent("add", this.length-1, o, key);
12193 * MixedCollection has a generic way to fetch keys if you implement getKey.
12196 var mc = new Roo.util.MixedCollection();
12197 mc.add(someEl.dom.id, someEl);
12198 mc.add(otherEl.dom.id, otherEl);
12202 var mc = new Roo.util.MixedCollection();
12203 mc.getKey = function(el){
12209 // or via the constructor
12210 var mc = new Roo.util.MixedCollection(false, function(el){
12216 * @param o {Object} The item for which to find the key.
12217 * @return {Object} The key for the passed item.
12219 getKey : function(o){
12224 * Replaces an item in the collection.
12225 * @param {String} key The key associated with the item to replace, or the item to replace.
12226 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12227 * @return {Object} The new item.
12229 replace : function(key, o){
12230 if(arguments.length == 1){
12232 key = this.getKey(o);
12234 var old = this.item(key);
12235 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12236 return this.add(key, o);
12238 var index = this.indexOfKey(key);
12239 this.items[index] = o;
12241 this.fireEvent("replace", key, old, o);
12246 * Adds all elements of an Array or an Object to the collection.
12247 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12248 * an Array of values, each of which are added to the collection.
12250 addAll : function(objs){
12251 if(arguments.length > 1 || objs instanceof Array){
12252 var args = arguments.length > 1 ? arguments : objs;
12253 for(var i = 0, len = args.length; i < len; i++){
12257 for(var key in objs){
12258 if(this.allowFunctions || typeof objs[key] != "function"){
12259 this.add(key, objs[key]);
12266 * Executes the specified function once for every item in the collection, passing each
12267 * item as the first and only parameter. returning false from the function will stop the iteration.
12268 * @param {Function} fn The function to execute for each item.
12269 * @param {Object} scope (optional) The scope in which to execute the function.
12271 each : function(fn, scope){
12272 var items = [].concat(this.items); // each safe for removal
12273 for(var i = 0, len = items.length; i < len; i++){
12274 if(fn.call(scope || items[i], items[i], i, len) === false){
12281 * Executes the specified function once for every key in the collection, passing each
12282 * key, and its associated item as the first two parameters.
12283 * @param {Function} fn The function to execute for each item.
12284 * @param {Object} scope (optional) The scope in which to execute the function.
12286 eachKey : function(fn, scope){
12287 for(var i = 0, len = this.keys.length; i < len; i++){
12288 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12293 * Returns the first item in the collection which elicits a true return value from the
12294 * passed selection function.
12295 * @param {Function} fn The selection function to execute for each item.
12296 * @param {Object} scope (optional) The scope in which to execute the function.
12297 * @return {Object} The first item in the collection which returned true from the selection function.
12299 find : function(fn, scope){
12300 for(var i = 0, len = this.items.length; i < len; i++){
12301 if(fn.call(scope || window, this.items[i], this.keys[i])){
12302 return this.items[i];
12309 * Inserts an item at the specified index in the collection.
12310 * @param {Number} index The index to insert the item at.
12311 * @param {String} key The key to associate with the new item, or the item itself.
12312 * @param {Object} o (optional) If the second parameter was a key, the new item.
12313 * @return {Object} The item inserted.
12315 insert : function(index, key, o){
12316 if(arguments.length == 2){
12318 key = this.getKey(o);
12320 if(index >= this.length){
12321 return this.add(key, o);
12324 this.items.splice(index, 0, o);
12325 if(typeof key != "undefined" && key != null){
12328 this.keys.splice(index, 0, key);
12329 this.fireEvent("add", index, o, key);
12334 * Removed an item from the collection.
12335 * @param {Object} o The item to remove.
12336 * @return {Object} The item removed.
12338 remove : function(o){
12339 return this.removeAt(this.indexOf(o));
12343 * Remove an item from a specified index in the collection.
12344 * @param {Number} index The index within the collection of the item to remove.
12346 removeAt : function(index){
12347 if(index < this.length && index >= 0){
12349 var o = this.items[index];
12350 this.items.splice(index, 1);
12351 var key = this.keys[index];
12352 if(typeof key != "undefined"){
12353 delete this.map[key];
12355 this.keys.splice(index, 1);
12356 this.fireEvent("remove", o, key);
12361 * Removed an item associated with the passed key fom the collection.
12362 * @param {String} key The key of the item to remove.
12364 removeKey : function(key){
12365 return this.removeAt(this.indexOfKey(key));
12369 * Returns the number of items in the collection.
12370 * @return {Number} the number of items in the collection.
12372 getCount : function(){
12373 return this.length;
12377 * Returns index within the collection of the passed Object.
12378 * @param {Object} o The item to find the index of.
12379 * @return {Number} index of the item.
12381 indexOf : function(o){
12382 if(!this.items.indexOf){
12383 for(var i = 0, len = this.items.length; i < len; i++){
12384 if(this.items[i] == o) return i;
12388 return this.items.indexOf(o);
12393 * Returns index within the collection of the passed key.
12394 * @param {String} key The key to find the index of.
12395 * @return {Number} index of the key.
12397 indexOfKey : function(key){
12398 if(!this.keys.indexOf){
12399 for(var i = 0, len = this.keys.length; i < len; i++){
12400 if(this.keys[i] == key) return i;
12404 return this.keys.indexOf(key);
12409 * Returns the item associated with the passed key OR index. Key has priority over index.
12410 * @param {String/Number} key The key or index of the item.
12411 * @return {Object} The item associated with the passed key.
12413 item : function(key){
12414 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12415 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12419 * Returns the item at the specified index.
12420 * @param {Number} index The index of the item.
12423 itemAt : function(index){
12424 return this.items[index];
12428 * Returns the item associated with the passed key.
12429 * @param {String/Number} key The key of the item.
12430 * @return {Object} The item associated with the passed key.
12432 key : function(key){
12433 return this.map[key];
12437 * Returns true if the collection contains the passed Object as an item.
12438 * @param {Object} o The Object to look for in the collection.
12439 * @return {Boolean} True if the collection contains the Object as an item.
12441 contains : function(o){
12442 return this.indexOf(o) != -1;
12446 * Returns true if the collection contains the passed Object as a key.
12447 * @param {String} key The key to look for in the collection.
12448 * @return {Boolean} True if the collection contains the Object as a key.
12450 containsKey : function(key){
12451 return typeof this.map[key] != "undefined";
12455 * Removes all items from the collection.
12457 clear : function(){
12462 this.fireEvent("clear");
12466 * Returns the first item in the collection.
12467 * @return {Object} the first item in the collection..
12469 first : function(){
12470 return this.items[0];
12474 * Returns the last item in the collection.
12475 * @return {Object} the last item in the collection..
12478 return this.items[this.length-1];
12481 _sort : function(property, dir, fn){
12482 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12483 fn = fn || function(a, b){
12486 var c = [], k = this.keys, items = this.items;
12487 for(var i = 0, len = items.length; i < len; i++){
12488 c[c.length] = {key: k[i], value: items[i], index: i};
12490 c.sort(function(a, b){
12491 var v = fn(a[property], b[property]) * dsc;
12493 v = (a.index < b.index ? -1 : 1);
12497 for(var i = 0, len = c.length; i < len; i++){
12498 items[i] = c[i].value;
12501 this.fireEvent("sort", this);
12505 * Sorts this collection with the passed comparison function
12506 * @param {String} direction (optional) "ASC" or "DESC"
12507 * @param {Function} fn (optional) comparison function
12509 sort : function(dir, fn){
12510 this._sort("value", dir, fn);
12514 * Sorts this collection by keys
12515 * @param {String} direction (optional) "ASC" or "DESC"
12516 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12518 keySort : function(dir, fn){
12519 this._sort("key", dir, fn || function(a, b){
12520 return String(a).toUpperCase()-String(b).toUpperCase();
12525 * Returns a range of items in this collection
12526 * @param {Number} startIndex (optional) defaults to 0
12527 * @param {Number} endIndex (optional) default to the last item
12528 * @return {Array} An array of items
12530 getRange : function(start, end){
12531 var items = this.items;
12532 if(items.length < 1){
12535 start = start || 0;
12536 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12539 for(var i = start; i <= end; i++) {
12540 r[r.length] = items[i];
12543 for(var i = start; i >= end; i--) {
12544 r[r.length] = items[i];
12551 * Filter the <i>objects</i> in this collection by a specific property.
12552 * Returns a new collection that has been filtered.
12553 * @param {String} property A property on your objects
12554 * @param {String/RegExp} value Either string that the property values
12555 * should start with or a RegExp to test against the property
12556 * @return {MixedCollection} The new filtered collection
12558 filter : function(property, value){
12559 if(!value.exec){ // not a regex
12560 value = String(value);
12561 if(value.length == 0){
12562 return this.clone();
12564 value = new RegExp("^" + Roo.escapeRe(value), "i");
12566 return this.filterBy(function(o){
12567 return o && value.test(o[property]);
12572 * Filter by a function. * Returns a new collection that has been filtered.
12573 * The passed function will be called with each
12574 * object in the collection. If the function returns true, the value is included
12575 * otherwise it is filtered.
12576 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12577 * @param {Object} scope (optional) The scope of the function (defaults to this)
12578 * @return {MixedCollection} The new filtered collection
12580 filterBy : function(fn, scope){
12581 var r = new Roo.util.MixedCollection();
12582 r.getKey = this.getKey;
12583 var k = this.keys, it = this.items;
12584 for(var i = 0, len = it.length; i < len; i++){
12585 if(fn.call(scope||this, it[i], k[i])){
12586 r.add(k[i], it[i]);
12593 * Creates a duplicate of this collection
12594 * @return {MixedCollection}
12596 clone : function(){
12597 var r = new Roo.util.MixedCollection();
12598 var k = this.keys, it = this.items;
12599 for(var i = 0, len = it.length; i < len; i++){
12600 r.add(k[i], it[i]);
12602 r.getKey = this.getKey;
12607 * Returns the item associated with the passed key or index.
12609 * @param {String/Number} key The key or index of the item.
12610 * @return {Object} The item associated with the passed key.
12612 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12614 * Ext JS Library 1.1.1
12615 * Copyright(c) 2006-2007, Ext JS, LLC.
12617 * Originally Released Under LGPL - original licence link has changed is not relivant.
12620 * <script type="text/javascript">
12623 * @class Roo.util.JSON
12624 * Modified version of Douglas Crockford"s json.js that doesn"t
12625 * mess with the Object prototype
12626 * http://www.json.org/js.html
12629 Roo.util.JSON = new (function(){
12630 var useHasOwn = {}.hasOwnProperty ? true : false;
12632 // crashes Safari in some instances
12633 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12635 var pad = function(n) {
12636 return n < 10 ? "0" + n : n;
12649 var encodeString = function(s){
12650 if (/["\\\x00-\x1f]/.test(s)) {
12651 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12656 c = b.charCodeAt();
12658 Math.floor(c / 16).toString(16) +
12659 (c % 16).toString(16);
12662 return '"' + s + '"';
12665 var encodeArray = function(o){
12666 var a = ["["], b, i, l = o.length, v;
12667 for (i = 0; i < l; i += 1) {
12669 switch (typeof v) {
12678 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12686 var encodeDate = function(o){
12687 return '"' + o.getFullYear() + "-" +
12688 pad(o.getMonth() + 1) + "-" +
12689 pad(o.getDate()) + "T" +
12690 pad(o.getHours()) + ":" +
12691 pad(o.getMinutes()) + ":" +
12692 pad(o.getSeconds()) + '"';
12696 * Encodes an Object, Array or other value
12697 * @param {Mixed} o The variable to encode
12698 * @return {String} The JSON string
12700 this.encode = function(o){
12701 if(typeof o == "undefined" || o === null){
12703 }else if(o instanceof Array){
12704 return encodeArray(o);
12705 }else if(o instanceof Date){
12706 return encodeDate(o);
12707 }else if(typeof o == "string"){
12708 return encodeString(o);
12709 }else if(typeof o == "number"){
12710 return isFinite(o) ? String(o) : "null";
12711 }else if(typeof o == "boolean"){
12714 var a = ["{"], b, i, v;
12716 if(!useHasOwn || o.hasOwnProperty(i)) {
12718 switch (typeof v) {
12727 a.push(this.encode(i), ":",
12728 v === null ? "null" : this.encode(v));
12739 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12740 * @param {String} json The JSON string
12741 * @return {Object} The resulting object
12743 this.decode = function(json){
12747 return eval("(" + json + ')');
12751 * Shorthand for {@link Roo.util.JSON#encode}
12752 * @member Roo encode
12754 Roo.encode = Roo.util.JSON.encode;
12756 * Shorthand for {@link Roo.util.JSON#decode}
12757 * @member Roo decode
12759 Roo.decode = Roo.util.JSON.decode;
12762 * Ext JS Library 1.1.1
12763 * Copyright(c) 2006-2007, Ext JS, LLC.
12765 * Originally Released Under LGPL - original licence link has changed is not relivant.
12768 * <script type="text/javascript">
12772 * @class Roo.util.Format
12773 * Reusable data formatting functions
12776 Roo.util.Format = function(){
12777 var trimRe = /^\s+|\s+$/g;
12780 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12781 * @param {String} value The string to truncate
12782 * @param {Number} length The maximum length to allow before truncating
12783 * @return {String} The converted text
12785 ellipsis : function(value, len){
12786 if(value && value.length > len){
12787 return value.substr(0, len-3)+"...";
12793 * Checks a reference and converts it to empty string if it is undefined
12794 * @param {Mixed} value Reference to check
12795 * @return {Mixed} Empty string if converted, otherwise the original value
12797 undef : function(value){
12798 return typeof value != "undefined" ? value : "";
12802 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12803 * @param {String} value The string to encode
12804 * @return {String} The encoded text
12806 htmlEncode : function(value){
12807 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12811 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12812 * @param {String} value The string to decode
12813 * @return {String} The decoded text
12815 htmlDecode : function(value){
12816 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12820 * Trims any whitespace from either side of a string
12821 * @param {String} value The text to trim
12822 * @return {String} The trimmed text
12824 trim : function(value){
12825 return String(value).replace(trimRe, "");
12829 * Returns a substring from within an original string
12830 * @param {String} value The original text
12831 * @param {Number} start The start index of the substring
12832 * @param {Number} length The length of the substring
12833 * @return {String} The substring
12835 substr : function(value, start, length){
12836 return String(value).substr(start, length);
12840 * Converts a string to all lower case letters
12841 * @param {String} value The text to convert
12842 * @return {String} The converted text
12844 lowercase : function(value){
12845 return String(value).toLowerCase();
12849 * Converts a string to all upper case letters
12850 * @param {String} value The text to convert
12851 * @return {String} The converted text
12853 uppercase : function(value){
12854 return String(value).toUpperCase();
12858 * Converts the first character only of a string to upper case
12859 * @param {String} value The text to convert
12860 * @return {String} The converted text
12862 capitalize : function(value){
12863 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12867 call : function(value, fn){
12868 if(arguments.length > 2){
12869 var args = Array.prototype.slice.call(arguments, 2);
12870 args.unshift(value);
12872 return /** eval:var:value */ eval(fn).apply(window, args);
12874 /** eval:var:value */
12875 return /** eval:var:value */ eval(fn).call(window, value);
12880 * Format a number as US currency
12881 * @param {Number/String} value The numeric value to format
12882 * @return {String} The formatted currency string
12884 usMoney : function(v){
12885 v = (Math.round((v-0)*100))/100;
12886 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12888 var ps = v.split('.');
12890 var sub = ps[1] ? '.'+ ps[1] : '.00';
12891 var r = /(\d+)(\d{3})/;
12892 while (r.test(whole)) {
12893 whole = whole.replace(r, '$1' + ',' + '$2');
12895 return "$" + whole + sub ;
12899 * Parse a value into a formatted date using the specified format pattern.
12900 * @param {Mixed} value The value to format
12901 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12902 * @return {String} The formatted date string
12904 date : function(v, format){
12908 if(!(v instanceof Date)){
12909 v = new Date(Date.parse(v));
12911 return v.dateFormat(format || "m/d/Y");
12915 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12916 * @param {String} format Any valid date format string
12917 * @return {Function} The date formatting function
12919 dateRenderer : function(format){
12920 return function(v){
12921 return Roo.util.Format.date(v, format);
12926 stripTagsRE : /<\/?[^>]+>/gi,
12929 * Strips all HTML tags
12930 * @param {Mixed} value The text from which to strip tags
12931 * @return {String} The stripped text
12933 stripTags : function(v){
12934 return !v ? v : String(v).replace(this.stripTagsRE, "");
12939 * Ext JS Library 1.1.1
12940 * Copyright(c) 2006-2007, Ext JS, LLC.
12942 * Originally Released Under LGPL - original licence link has changed is not relivant.
12945 * <script type="text/javascript">
12952 * @class Roo.MasterTemplate
12953 * @extends Roo.Template
12954 * Provides a template that can have child templates. The syntax is:
12956 var t = new Roo.MasterTemplate(
12957 '<select name="{name}">',
12958 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
12961 t.add('options', {value: 'foo', text: 'bar'});
12962 // or you can add multiple child elements in one shot
12963 t.addAll('options', [
12964 {value: 'foo', text: 'bar'},
12965 {value: 'foo2', text: 'bar2'},
12966 {value: 'foo3', text: 'bar3'}
12968 // then append, applying the master template values
12969 t.append('my-form', {name: 'my-select'});
12971 * A name attribute for the child template is not required if you have only one child
12972 * template or you want to refer to them by index.
12974 Roo.MasterTemplate = function(){
12975 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
12976 this.originalHtml = this.html;
12978 var m, re = this.subTemplateRe;
12981 while(m = re.exec(this.html)){
12982 var name = m[1], content = m[2];
12987 tpl : new Roo.Template(content)
12990 st[name] = st[subIndex];
12992 st[subIndex].tpl.compile();
12993 st[subIndex].tpl.call = this.call.createDelegate(this);
12996 this.subCount = subIndex;
12999 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13001 * The regular expression used to match sub templates
13005 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13008 * Applies the passed values to a child template.
13009 * @param {String/Number} name (optional) The name or index of the child template
13010 * @param {Array/Object} values The values to be applied to the template
13011 * @return {MasterTemplate} this
13013 add : function(name, values){
13014 if(arguments.length == 1){
13015 values = arguments[0];
13018 var s = this.subs[name];
13019 s.buffer[s.buffer.length] = s.tpl.apply(values);
13024 * Applies all the passed values to a child template.
13025 * @param {String/Number} name (optional) The name or index of the child template
13026 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13027 * @param {Boolean} reset (optional) True to reset the template first
13028 * @return {MasterTemplate} this
13030 fill : function(name, values, reset){
13032 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13040 for(var i = 0, len = values.length; i < len; i++){
13041 this.add(name, values[i]);
13047 * Resets the template for reuse
13048 * @return {MasterTemplate} this
13050 reset : function(){
13052 for(var i = 0; i < this.subCount; i++){
13058 applyTemplate : function(values){
13060 var replaceIndex = -1;
13061 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13062 return s[++replaceIndex].buffer.join("");
13064 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13067 apply : function(){
13068 return this.applyTemplate.apply(this, arguments);
13071 compile : function(){return this;}
13075 * Alias for fill().
13078 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13080 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13081 * var tpl = Roo.MasterTemplate.from('element-id');
13082 * @param {String/HTMLElement} el
13083 * @param {Object} config
13086 Roo.MasterTemplate.from = function(el, config){
13087 el = Roo.getDom(el);
13088 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13091 * Ext JS Library 1.1.1
13092 * Copyright(c) 2006-2007, Ext JS, LLC.
13094 * Originally Released Under LGPL - original licence link has changed is not relivant.
13097 * <script type="text/javascript">
13102 * @class Roo.util.CSS
13103 * Utility class for manipulating CSS rules
13106 Roo.util.CSS = function(){
13108 var doc = document;
13110 var camelRe = /(-[a-z])/gi;
13111 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13115 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13116 * tag and appended to the HEAD of the document.
13117 * @param {String} cssText The text containing the css rules
13118 * @param {String} id An id to add to the stylesheet for later removal
13119 * @return {StyleSheet}
13121 createStyleSheet : function(cssText, id){
13123 var head = doc.getElementsByTagName("head")[0];
13124 var rules = doc.createElement("style");
13125 rules.setAttribute("type", "text/css");
13127 rules.setAttribute("id", id);
13130 head.appendChild(rules);
13131 ss = rules.styleSheet;
13132 ss.cssText = cssText;
13135 rules.appendChild(doc.createTextNode(cssText));
13137 rules.cssText = cssText;
13139 head.appendChild(rules);
13140 ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13142 this.cacheStyleSheet(ss);
13147 * Removes a style or link tag by id
13148 * @param {String} id The id of the tag
13150 removeStyleSheet : function(id){
13151 var existing = doc.getElementById(id);
13153 existing.parentNode.removeChild(existing);
13158 * Dynamically swaps an existing stylesheet reference for a new one
13159 * @param {String} id The id of an existing link tag to remove
13160 * @param {String} url The href of the new stylesheet to include
13162 swapStyleSheet : function(id, url){
13163 this.removeStyleSheet(id);
13164 var ss = doc.createElement("link");
13165 ss.setAttribute("rel", "stylesheet");
13166 ss.setAttribute("type", "text/css");
13167 ss.setAttribute("id", id);
13168 ss.setAttribute("href", url);
13169 doc.getElementsByTagName("head")[0].appendChild(ss);
13173 * Refresh the rule cache if you have dynamically added stylesheets
13174 * @return {Object} An object (hash) of rules indexed by selector
13176 refreshCache : function(){
13177 return this.getRules(true);
13181 cacheStyleSheet : function(ss){
13185 try{// try catch for cross domain access issue
13186 var ssRules = ss.cssRules || ss.rules;
13187 for(var j = ssRules.length-1; j >= 0; --j){
13188 rules[ssRules[j].selectorText] = ssRules[j];
13194 * Gets all css rules for the document
13195 * @param {Boolean} refreshCache true to refresh the internal cache
13196 * @return {Object} An object (hash) of rules indexed by selector
13198 getRules : function(refreshCache){
13199 if(rules == null || refreshCache){
13201 var ds = doc.styleSheets;
13202 for(var i =0, len = ds.length; i < len; i++){
13204 this.cacheStyleSheet(ds[i]);
13212 * Gets an an individual CSS rule by selector(s)
13213 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13214 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13215 * @return {CSSRule} The CSS rule or null if one is not found
13217 getRule : function(selector, refreshCache){
13218 var rs = this.getRules(refreshCache);
13219 if(!(selector instanceof Array)){
13220 return rs[selector];
13222 for(var i = 0; i < selector.length; i++){
13223 if(rs[selector[i]]){
13224 return rs[selector[i]];
13232 * Updates a rule property
13233 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13234 * @param {String} property The css property
13235 * @param {String} value The new value for the property
13236 * @return {Boolean} true If a rule was found and updated
13238 updateRule : function(selector, property, value){
13239 if(!(selector instanceof Array)){
13240 var rule = this.getRule(selector);
13242 rule.style[property.replace(camelRe, camelFn)] = value;
13246 for(var i = 0; i < selector.length; i++){
13247 if(this.updateRule(selector[i], property, value)){
13257 * Ext JS Library 1.1.1
13258 * Copyright(c) 2006-2007, Ext JS, LLC.
13260 * Originally Released Under LGPL - original licence link has changed is not relivant.
13263 * <script type="text/javascript">
13269 * @class Roo.util.ClickRepeater
13270 * @extends Roo.util.Observable
13272 * A wrapper class which can be applied to any element. Fires a "click" event while the
13273 * mouse is pressed. The interval between firings may be specified in the config but
13274 * defaults to 10 milliseconds.
13276 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13278 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13279 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13280 * Similar to an autorepeat key delay.
13281 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13282 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13283 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13284 * "interval" and "delay" are ignored. "immediate" is honored.
13285 * @cfg {Boolean} preventDefault True to prevent the default click event
13286 * @cfg {Boolean} stopDefault True to stop the default click event
13289 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13290 * 2007-02-02 jvs Renamed to ClickRepeater
13291 * 2007-02-03 jvs Modifications for FF Mac and Safari
13294 * @param {String/HTMLElement/Element} el The element to listen on
13295 * @param {Object} config
13297 Roo.util.ClickRepeater = function(el, config)
13299 this.el = Roo.get(el);
13300 this.el.unselectable();
13302 Roo.apply(this, config);
13307 * Fires when the mouse button is depressed.
13308 * @param {Roo.util.ClickRepeater} this
13310 "mousedown" : true,
13313 * Fires on a specified interval during the time the element is pressed.
13314 * @param {Roo.util.ClickRepeater} this
13319 * Fires when the mouse key is released.
13320 * @param {Roo.util.ClickRepeater} this
13325 this.el.on("mousedown", this.handleMouseDown, this);
13326 if(this.preventDefault || this.stopDefault){
13327 this.el.on("click", function(e){
13328 if(this.preventDefault){
13329 e.preventDefault();
13331 if(this.stopDefault){
13337 // allow inline handler
13339 this.on("click", this.handler, this.scope || this);
13342 Roo.util.ClickRepeater.superclass.constructor.call(this);
13345 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13348 preventDefault : true,
13349 stopDefault : false,
13353 handleMouseDown : function(){
13354 clearTimeout(this.timer);
13356 if(this.pressClass){
13357 this.el.addClass(this.pressClass);
13359 this.mousedownTime = new Date();
13361 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13362 this.el.on("mouseout", this.handleMouseOut, this);
13364 this.fireEvent("mousedown", this);
13365 this.fireEvent("click", this);
13367 this.timer = this.click.defer(this.delay || this.interval, this);
13371 click : function(){
13372 this.fireEvent("click", this);
13373 this.timer = this.click.defer(this.getInterval(), this);
13377 getInterval: function(){
13378 if(!this.accelerate){
13379 return this.interval;
13381 var pressTime = this.mousedownTime.getElapsed();
13382 if(pressTime < 500){
13384 }else if(pressTime < 1700){
13386 }else if(pressTime < 2600){
13388 }else if(pressTime < 3500){
13390 }else if(pressTime < 4400){
13392 }else if(pressTime < 5300){
13394 }else if(pressTime < 6200){
13402 handleMouseOut : function(){
13403 clearTimeout(this.timer);
13404 if(this.pressClass){
13405 this.el.removeClass(this.pressClass);
13407 this.el.on("mouseover", this.handleMouseReturn, this);
13411 handleMouseReturn : function(){
13412 this.el.un("mouseover", this.handleMouseReturn);
13413 if(this.pressClass){
13414 this.el.addClass(this.pressClass);
13420 handleMouseUp : function(){
13421 clearTimeout(this.timer);
13422 this.el.un("mouseover", this.handleMouseReturn);
13423 this.el.un("mouseout", this.handleMouseOut);
13424 Roo.get(document).un("mouseup", this.handleMouseUp);
13425 this.el.removeClass(this.pressClass);
13426 this.fireEvent("mouseup", this);
13430 * Ext JS Library 1.1.1
13431 * Copyright(c) 2006-2007, Ext JS, LLC.
13433 * Originally Released Under LGPL - original licence link has changed is not relivant.
13436 * <script type="text/javascript">
13441 * @class Roo.KeyNav
13442 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13443 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13444 * way to implement custom navigation schemes for any UI component.</p>
13445 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13446 * pageUp, pageDown, del, home, end. Usage:</p>
13448 var nav = new Roo.KeyNav("my-element", {
13449 "left" : function(e){
13450 this.moveLeft(e.ctrlKey);
13452 "right" : function(e){
13453 this.moveRight(e.ctrlKey);
13455 "enter" : function(e){
13462 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13463 * @param {Object} config The config
13465 Roo.KeyNav = function(el, config){
13466 this.el = Roo.get(el);
13467 Roo.apply(this, config);
13468 if(!this.disabled){
13469 this.disabled = true;
13474 Roo.KeyNav.prototype = {
13476 * @cfg {Boolean} disabled
13477 * True to disable this KeyNav instance (defaults to false)
13481 * @cfg {String} defaultEventAction
13482 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13483 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13484 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13486 defaultEventAction: "stopEvent",
13488 * @cfg {Boolean} forceKeyDown
13489 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13490 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13491 * handle keydown instead of keypress.
13493 forceKeyDown : false,
13496 prepareEvent : function(e){
13497 var k = e.getKey();
13498 var h = this.keyToHandler[k];
13499 //if(h && this[h]){
13500 // e.stopPropagation();
13502 if(Roo.isSafari && h && k >= 37 && k <= 40){
13508 relay : function(e){
13509 var k = e.getKey();
13510 var h = this.keyToHandler[k];
13512 if(this.doRelay(e, this[h], h) !== true){
13513 e[this.defaultEventAction]();
13519 doRelay : function(e, h, hname){
13520 return h.call(this.scope || this, e);
13523 // possible handlers
13537 // quick lookup hash
13554 * Enable this KeyNav
13556 enable: function(){
13558 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13559 // the EventObject will normalize Safari automatically
13560 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13561 this.el.on("keydown", this.relay, this);
13563 this.el.on("keydown", this.prepareEvent, this);
13564 this.el.on("keypress", this.relay, this);
13566 this.disabled = false;
13571 * Disable this KeyNav
13573 disable: function(){
13574 if(!this.disabled){
13575 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13576 this.el.un("keydown", this.relay);
13578 this.el.un("keydown", this.prepareEvent);
13579 this.el.un("keypress", this.relay);
13581 this.disabled = true;
13586 * Ext JS Library 1.1.1
13587 * Copyright(c) 2006-2007, Ext JS, LLC.
13589 * Originally Released Under LGPL - original licence link has changed is not relivant.
13592 * <script type="text/javascript">
13597 * @class Roo.KeyMap
13598 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13599 * The constructor accepts the same config object as defined by {@link #addBinding}.
13600 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13601 * combination it will call the function with this signature (if the match is a multi-key
13602 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13603 * A KeyMap can also handle a string representation of keys.<br />
13606 // map one key by key code
13607 var map = new Roo.KeyMap("my-element", {
13608 key: 13, // or Roo.EventObject.ENTER
13613 // map multiple keys to one action by string
13614 var map = new Roo.KeyMap("my-element", {
13620 // map multiple keys to multiple actions by strings and array of codes
13621 var map = new Roo.KeyMap("my-element", [
13624 fn: function(){ alert("Return was pressed"); }
13627 fn: function(){ alert('a, b or c was pressed'); }
13632 fn: function(){ alert('Control + shift + tab was pressed.'); }
13636 * <b>Note: A KeyMap starts enabled</b>
13638 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13639 * @param {Object} config The config (see {@link #addBinding})
13640 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13642 Roo.KeyMap = function(el, config, eventName){
13643 this.el = Roo.get(el);
13644 this.eventName = eventName || "keydown";
13645 this.bindings = [];
13647 this.addBinding(config);
13652 Roo.KeyMap.prototype = {
13654 * True to stop the event from bubbling and prevent the default browser action if the
13655 * key was handled by the KeyMap (defaults to false)
13661 * Add a new binding to this KeyMap. The following config object properties are supported:
13663 Property Type Description
13664 ---------- --------------- ----------------------------------------------------------------------
13665 key String/Array A single keycode or an array of keycodes to handle
13666 shift Boolean True to handle key only when shift is pressed (defaults to false)
13667 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13668 alt Boolean True to handle key only when alt is pressed (defaults to false)
13669 fn Function The function to call when KeyMap finds the expected key combination
13670 scope Object The scope of the callback function
13676 var map = new Roo.KeyMap(document, {
13677 key: Roo.EventObject.ENTER,
13682 //Add a new binding to the existing KeyMap later
13690 * @param {Object/Array} config A single KeyMap config or an array of configs
13692 addBinding : function(config){
13693 if(config instanceof Array){
13694 for(var i = 0, len = config.length; i < len; i++){
13695 this.addBinding(config[i]);
13699 var keyCode = config.key,
13700 shift = config.shift,
13701 ctrl = config.ctrl,
13704 scope = config.scope;
13705 if(typeof keyCode == "string"){
13707 var keyString = keyCode.toUpperCase();
13708 for(var j = 0, len = keyString.length; j < len; j++){
13709 ks.push(keyString.charCodeAt(j));
13713 var keyArray = keyCode instanceof Array;
13714 var handler = function(e){
13715 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13716 var k = e.getKey();
13718 for(var i = 0, len = keyCode.length; i < len; i++){
13719 if(keyCode[i] == k){
13720 if(this.stopEvent){
13723 fn.call(scope || window, k, e);
13729 if(this.stopEvent){
13732 fn.call(scope || window, k, e);
13737 this.bindings.push(handler);
13741 * Shorthand for adding a single key listener
13742 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13743 * following options:
13744 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13745 * @param {Function} fn The function to call
13746 * @param {Object} scope (optional) The scope of the function
13748 on : function(key, fn, scope){
13749 var keyCode, shift, ctrl, alt;
13750 if(typeof key == "object" && !(key instanceof Array)){
13769 handleKeyDown : function(e){
13770 if(this.enabled){ //just in case
13771 var b = this.bindings;
13772 for(var i = 0, len = b.length; i < len; i++){
13773 b[i].call(this, e);
13779 * Returns true if this KeyMap is enabled
13780 * @return {Boolean}
13782 isEnabled : function(){
13783 return this.enabled;
13787 * Enables this KeyMap
13789 enable: function(){
13791 this.el.on(this.eventName, this.handleKeyDown, this);
13792 this.enabled = true;
13797 * Disable this KeyMap
13799 disable: function(){
13801 this.el.removeListener(this.eventName, this.handleKeyDown, this);
13802 this.enabled = false;
13807 * Ext JS Library 1.1.1
13808 * Copyright(c) 2006-2007, Ext JS, LLC.
13810 * Originally Released Under LGPL - original licence link has changed is not relivant.
13813 * <script type="text/javascript">
13818 * @class Roo.util.TextMetrics
13819 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13820 * wide, in pixels, a given block of text will be.
13823 Roo.util.TextMetrics = function(){
13827 * Measures the size of the specified text
13828 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13829 * that can affect the size of the rendered text
13830 * @param {String} text The text to measure
13831 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13832 * in order to accurately measure the text height
13833 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13835 measure : function(el, text, fixedWidth){
13837 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13840 shared.setFixedWidth(fixedWidth || 'auto');
13841 return shared.getSize(text);
13845 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13846 * the overhead of multiple calls to initialize the style properties on each measurement.
13847 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13848 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13849 * in order to accurately measure the text height
13850 * @return {Roo.util.TextMetrics.Instance} instance The new instance
13852 createInstance : function(el, fixedWidth){
13853 return Roo.util.TextMetrics.Instance(el, fixedWidth);
13858 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13859 var ml = new Roo.Element(document.createElement('div'));
13860 document.body.appendChild(ml.dom);
13861 ml.position('absolute');
13862 ml.setLeftTop(-1000, -1000);
13866 ml.setWidth(fixedWidth);
13871 * Returns the size of the specified text based on the internal element's style and width properties
13872 * @param {String} text The text to measure
13873 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13875 getSize : function(text){
13877 var s = ml.getSize();
13883 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13884 * that can affect the size of the rendered text
13885 * @param {String/HTMLElement} el The element, dom node or id
13887 bind : function(el){
13889 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13894 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
13895 * to set a fixed width in order to accurately measure the text height.
13896 * @param {Number} width The width to set on the element
13898 setFixedWidth : function(width){
13899 ml.setWidth(width);
13903 * Returns the measured width of the specified text
13904 * @param {String} text The text to measure
13905 * @return {Number} width The width in pixels
13907 getWidth : function(text){
13908 ml.dom.style.width = 'auto';
13909 return this.getSize(text).width;
13913 * Returns the measured height of the specified text. For multiline text, be sure to call
13914 * {@link #setFixedWidth} if necessary.
13915 * @param {String} text The text to measure
13916 * @return {Number} height The height in pixels
13918 getHeight : function(text){
13919 return this.getSize(text).height;
13923 instance.bind(bindTo);
13928 // backwards compat
13929 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13931 * Ext JS Library 1.1.1
13932 * Copyright(c) 2006-2007, Ext JS, LLC.
13934 * Originally Released Under LGPL - original licence link has changed is not relivant.
13937 * <script type="text/javascript">
13941 * @class Roo.state.Provider
13942 * Abstract base class for state provider implementations. This class provides methods
13943 * for encoding and decoding <b>typed</b> variables including dates and defines the
13944 * Provider interface.
13946 Roo.state.Provider = function(){
13948 * @event statechange
13949 * Fires when a state change occurs.
13950 * @param {Provider} this This state provider
13951 * @param {String} key The state key which was changed
13952 * @param {String} value The encoded value for the state
13955 "statechange": true
13958 Roo.state.Provider.superclass.constructor.call(this);
13960 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
13962 * Returns the current value for a key
13963 * @param {String} name The key name
13964 * @param {Mixed} defaultValue A default value to return if the key's value is not found
13965 * @return {Mixed} The state data
13967 get : function(name, defaultValue){
13968 return typeof this.state[name] == "undefined" ?
13969 defaultValue : this.state[name];
13973 * Clears a value from the state
13974 * @param {String} name The key name
13976 clear : function(name){
13977 delete this.state[name];
13978 this.fireEvent("statechange", this, name, null);
13982 * Sets the value for a key
13983 * @param {String} name The key name
13984 * @param {Mixed} value The value to set
13986 set : function(name, value){
13987 this.state[name] = value;
13988 this.fireEvent("statechange", this, name, value);
13992 * Decodes a string previously encoded with {@link #encodeValue}.
13993 * @param {String} value The value to decode
13994 * @return {Mixed} The decoded value
13996 decodeValue : function(cookie){
13997 var re = /^(a|n|d|b|s|o)\:(.*)$/;
13998 var matches = re.exec(unescape(cookie));
13999 if(!matches || !matches[1]) return; // non state cookie
14000 var type = matches[1];
14001 var v = matches[2];
14004 return parseFloat(v);
14006 return new Date(Date.parse(v));
14011 var values = v.split("^");
14012 for(var i = 0, len = values.length; i < len; i++){
14013 all.push(this.decodeValue(values[i]));
14018 var values = v.split("^");
14019 for(var i = 0, len = values.length; i < len; i++){
14020 var kv = values[i].split("=");
14021 all[kv[0]] = this.decodeValue(kv[1]);
14030 * Encodes a value including type information. Decode with {@link #decodeValue}.
14031 * @param {Mixed} value The value to encode
14032 * @return {String} The encoded value
14034 encodeValue : function(v){
14036 if(typeof v == "number"){
14038 }else if(typeof v == "boolean"){
14039 enc = "b:" + (v ? "1" : "0");
14040 }else if(v instanceof Date){
14041 enc = "d:" + v.toGMTString();
14042 }else if(v instanceof Array){
14044 for(var i = 0, len = v.length; i < len; i++){
14045 flat += this.encodeValue(v[i]);
14046 if(i != len-1) flat += "^";
14049 }else if(typeof v == "object"){
14052 if(typeof v[key] != "function"){
14053 flat += key + "=" + this.encodeValue(v[key]) + "^";
14056 enc = "o:" + flat.substring(0, flat.length-1);
14060 return escape(enc);
14066 * Ext JS Library 1.1.1
14067 * Copyright(c) 2006-2007, Ext JS, LLC.
14069 * Originally Released Under LGPL - original licence link has changed is not relivant.
14072 * <script type="text/javascript">
14075 * @class Roo.state.Manager
14076 * This is the global state manager. By default all components that are "state aware" check this class
14077 * for state information if you don't pass them a custom state provider. In order for this class
14078 * to be useful, it must be initialized with a provider when your application initializes.
14080 // in your initialization function
14082 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14084 // supposed you have a {@link Roo.BorderLayout}
14085 var layout = new Roo.BorderLayout(...);
14086 layout.restoreState();
14087 // or a {Roo.BasicDialog}
14088 var dialog = new Roo.BasicDialog(...);
14089 dialog.restoreState();
14093 Roo.state.Manager = function(){
14094 var provider = new Roo.state.Provider();
14098 * Configures the default state provider for your application
14099 * @param {Provider} stateProvider The state provider to set
14101 setProvider : function(stateProvider){
14102 provider = stateProvider;
14106 * Returns the current value for a key
14107 * @param {String} name The key name
14108 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14109 * @return {Mixed} The state data
14111 get : function(key, defaultValue){
14112 return provider.get(key, defaultValue);
14116 * Sets the value for a key
14117 * @param {String} name The key name
14118 * @param {Mixed} value The state data
14120 set : function(key, value){
14121 provider.set(key, value);
14125 * Clears a value from the state
14126 * @param {String} name The key name
14128 clear : function(key){
14129 provider.clear(key);
14133 * Gets the currently configured state provider
14134 * @return {Provider} The state provider
14136 getProvider : function(){
14143 * Ext JS Library 1.1.1
14144 * Copyright(c) 2006-2007, Ext JS, LLC.
14146 * Originally Released Under LGPL - original licence link has changed is not relivant.
14149 * <script type="text/javascript">
14152 * @class Roo.state.CookieProvider
14153 * @extends Roo.state.Provider
14154 * The default Provider implementation which saves state via cookies.
14157 var cp = new Roo.state.CookieProvider({
14159 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14160 domain: "roojs.com"
14162 Roo.state.Manager.setProvider(cp);
14164 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14165 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14166 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14167 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14168 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14169 * domain the page is running on including the 'www' like 'www.roojs.com')
14170 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14172 * Create a new CookieProvider
14173 * @param {Object} config The configuration object
14175 Roo.state.CookieProvider = function(config){
14176 Roo.state.CookieProvider.superclass.constructor.call(this);
14178 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14179 this.domain = null;
14180 this.secure = false;
14181 Roo.apply(this, config);
14182 this.state = this.readCookies();
14185 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14187 set : function(name, value){
14188 if(typeof value == "undefined" || value === null){
14192 this.setCookie(name, value);
14193 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14197 clear : function(name){
14198 this.clearCookie(name);
14199 Roo.state.CookieProvider.superclass.clear.call(this, name);
14203 readCookies : function(){
14205 var c = document.cookie + ";";
14206 var re = /\s?(.*?)=(.*?);/g;
14208 while((matches = re.exec(c)) != null){
14209 var name = matches[1];
14210 var value = matches[2];
14211 if(name && name.substring(0,3) == "ys-"){
14212 cookies[name.substr(3)] = this.decodeValue(value);
14219 setCookie : function(name, value){
14220 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14221 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14222 ((this.path == null) ? "" : ("; path=" + this.path)) +
14223 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14224 ((this.secure == true) ? "; secure" : "");
14228 clearCookie : function(name){
14229 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14230 ((this.path == null) ? "" : ("; path=" + this.path)) +
14231 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14232 ((this.secure == true) ? "; secure" : "");
14236 * Ext JS Library 1.1.1
14237 * Copyright(c) 2006-2007, Ext JS, LLC.
14239 * Originally Released Under LGPL - original licence link has changed is not relivant.
14242 * <script type="text/javascript">
14248 * These classes are derivatives of the similarly named classes in the YUI Library.
14249 * The original license:
14250 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14251 * Code licensed under the BSD License:
14252 * http://developer.yahoo.net/yui/license.txt
14257 var Event=Roo.EventManager;
14258 var Dom=Roo.lib.Dom;
14261 * @class Roo.dd.DragDrop
14262 * Defines the interface and base operation of items that that can be
14263 * dragged or can be drop targets. It was designed to be extended, overriding
14264 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14265 * Up to three html elements can be associated with a DragDrop instance:
14267 * <li>linked element: the element that is passed into the constructor.
14268 * This is the element which defines the boundaries for interaction with
14269 * other DragDrop objects.</li>
14270 * <li>handle element(s): The drag operation only occurs if the element that
14271 * was clicked matches a handle element. By default this is the linked
14272 * element, but there are times that you will want only a portion of the
14273 * linked element to initiate the drag operation, and the setHandleElId()
14274 * method provides a way to define this.</li>
14275 * <li>drag element: this represents the element that would be moved along
14276 * with the cursor during a drag operation. By default, this is the linked
14277 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14278 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14281 * This class should not be instantiated until the onload event to ensure that
14282 * the associated elements are available.
14283 * The following would define a DragDrop obj that would interact with any
14284 * other DragDrop obj in the "group1" group:
14286 * dd = new Roo.dd.DragDrop("div1", "group1");
14288 * Since none of the event handlers have been implemented, nothing would
14289 * actually happen if you were to run the code above. Normally you would
14290 * override this class or one of the default implementations, but you can
14291 * also override the methods you want on an instance of the class...
14293 * dd.onDragDrop = function(e, id) {
14294 * alert("dd was dropped on " + id);
14298 * @param {String} id of the element that is linked to this instance
14299 * @param {String} sGroup the group of related DragDrop objects
14300 * @param {object} config an object containing configurable attributes
14301 * Valid properties for DragDrop:
14302 * padding, isTarget, maintainOffset, primaryButtonOnly
14304 Roo.dd.DragDrop = function(id, sGroup, config) {
14306 this.init(id, sGroup, config);
14310 Roo.dd.DragDrop.prototype = {
14313 * The id of the element associated with this object. This is what we
14314 * refer to as the "linked element" because the size and position of
14315 * this element is used to determine when the drag and drop objects have
14323 * Configuration attributes passed into the constructor
14330 * The id of the element that will be dragged. By default this is same
14331 * as the linked element , but could be changed to another element. Ex:
14333 * @property dragElId
14340 * the id of the element that initiates the drag operation. By default
14341 * this is the linked element, but could be changed to be a child of this
14342 * element. This lets us do things like only starting the drag when the
14343 * header element within the linked html element is clicked.
14344 * @property handleElId
14351 * An associative array of HTML tags that will be ignored if clicked.
14352 * @property invalidHandleTypes
14353 * @type {string: string}
14355 invalidHandleTypes: null,
14358 * An associative array of ids for elements that will be ignored if clicked
14359 * @property invalidHandleIds
14360 * @type {string: string}
14362 invalidHandleIds: null,
14365 * An indexted array of css class names for elements that will be ignored
14367 * @property invalidHandleClasses
14370 invalidHandleClasses: null,
14373 * The linked element's absolute X position at the time the drag was
14375 * @property startPageX
14382 * The linked element's absolute X position at the time the drag was
14384 * @property startPageY
14391 * The group defines a logical collection of DragDrop objects that are
14392 * related. Instances only get events when interacting with other
14393 * DragDrop object in the same group. This lets us define multiple
14394 * groups using a single DragDrop subclass if we want.
14396 * @type {string: string}
14401 * Individual drag/drop instances can be locked. This will prevent
14402 * onmousedown start drag.
14410 * Lock this instance
14413 lock: function() { this.locked = true; },
14416 * Unlock this instace
14419 unlock: function() { this.locked = false; },
14422 * By default, all insances can be a drop target. This can be disabled by
14423 * setting isTarget to false.
14430 * The padding configured for this drag and drop object for calculating
14431 * the drop zone intersection with this object.
14438 * Cached reference to the linked element
14439 * @property _domRef
14445 * Internal typeof flag
14446 * @property __ygDragDrop
14449 __ygDragDrop: true,
14452 * Set to true when horizontal contraints are applied
14453 * @property constrainX
14460 * Set to true when vertical contraints are applied
14461 * @property constrainY
14468 * The left constraint
14476 * The right constraint
14484 * The up constraint
14493 * The down constraint
14501 * Maintain offsets when we resetconstraints. Set to true when you want
14502 * the position of the element relative to its parent to stay the same
14503 * when the page changes
14505 * @property maintainOffset
14508 maintainOffset: false,
14511 * Array of pixel locations the element will snap to if we specified a
14512 * horizontal graduation/interval. This array is generated automatically
14513 * when you define a tick interval.
14520 * Array of pixel locations the element will snap to if we specified a
14521 * vertical graduation/interval. This array is generated automatically
14522 * when you define a tick interval.
14529 * By default the drag and drop instance will only respond to the primary
14530 * button click (left button for a right-handed mouse). Set to true to
14531 * allow drag and drop to start with any mouse click that is propogated
14533 * @property primaryButtonOnly
14536 primaryButtonOnly: true,
14539 * The availabe property is false until the linked dom element is accessible.
14540 * @property available
14546 * By default, drags can only be initiated if the mousedown occurs in the
14547 * region the linked element is. This is done in part to work around a
14548 * bug in some browsers that mis-report the mousedown if the previous
14549 * mouseup happened outside of the window. This property is set to true
14550 * if outer handles are defined.
14552 * @property hasOuterHandles
14556 hasOuterHandles: false,
14559 * Code that executes immediately before the startDrag event
14560 * @method b4StartDrag
14563 b4StartDrag: function(x, y) { },
14566 * Abstract method called after a drag/drop object is clicked
14567 * and the drag or mousedown time thresholds have beeen met.
14568 * @method startDrag
14569 * @param {int} X click location
14570 * @param {int} Y click location
14572 startDrag: function(x, y) { /* override this */ },
14575 * Code that executes immediately before the onDrag event
14579 b4Drag: function(e) { },
14582 * Abstract method called during the onMouseMove event while dragging an
14585 * @param {Event} e the mousemove event
14587 onDrag: function(e) { /* override this */ },
14590 * Abstract method called when this element fist begins hovering over
14591 * another DragDrop obj
14592 * @method onDragEnter
14593 * @param {Event} e the mousemove event
14594 * @param {String|DragDrop[]} id In POINT mode, the element
14595 * id this is hovering over. In INTERSECT mode, an array of one or more
14596 * dragdrop items being hovered over.
14598 onDragEnter: function(e, id) { /* override this */ },
14601 * Code that executes immediately before the onDragOver event
14602 * @method b4DragOver
14605 b4DragOver: function(e) { },
14608 * Abstract method called when this element is hovering over another
14610 * @method onDragOver
14611 * @param {Event} e the mousemove event
14612 * @param {String|DragDrop[]} id In POINT mode, the element
14613 * id this is hovering over. In INTERSECT mode, an array of dd items
14614 * being hovered over.
14616 onDragOver: function(e, id) { /* override this */ },
14619 * Code that executes immediately before the onDragOut event
14620 * @method b4DragOut
14623 b4DragOut: function(e) { },
14626 * Abstract method called when we are no longer hovering over an element
14627 * @method onDragOut
14628 * @param {Event} e the mousemove event
14629 * @param {String|DragDrop[]} id In POINT mode, the element
14630 * id this was hovering over. In INTERSECT mode, an array of dd items
14631 * that the mouse is no longer over.
14633 onDragOut: function(e, id) { /* override this */ },
14636 * Code that executes immediately before the onDragDrop event
14637 * @method b4DragDrop
14640 b4DragDrop: function(e) { },
14643 * Abstract method called when this item is dropped on another DragDrop
14645 * @method onDragDrop
14646 * @param {Event} e the mouseup event
14647 * @param {String|DragDrop[]} id In POINT mode, the element
14648 * id this was dropped on. In INTERSECT mode, an array of dd items this
14651 onDragDrop: function(e, id) { /* override this */ },
14654 * Abstract method called when this item is dropped on an area with no
14656 * @method onInvalidDrop
14657 * @param {Event} e the mouseup event
14659 onInvalidDrop: function(e) { /* override this */ },
14662 * Code that executes immediately before the endDrag event
14663 * @method b4EndDrag
14666 b4EndDrag: function(e) { },
14669 * Fired when we are done dragging the object
14671 * @param {Event} e the mouseup event
14673 endDrag: function(e) { /* override this */ },
14676 * Code executed immediately before the onMouseDown event
14677 * @method b4MouseDown
14678 * @param {Event} e the mousedown event
14681 b4MouseDown: function(e) { },
14684 * Event handler that fires when a drag/drop obj gets a mousedown
14685 * @method onMouseDown
14686 * @param {Event} e the mousedown event
14688 onMouseDown: function(e) { /* override this */ },
14691 * Event handler that fires when a drag/drop obj gets a mouseup
14692 * @method onMouseUp
14693 * @param {Event} e the mouseup event
14695 onMouseUp: function(e) { /* override this */ },
14698 * Override the onAvailable method to do what is needed after the initial
14699 * position was determined.
14700 * @method onAvailable
14702 onAvailable: function () {
14706 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14709 defaultPadding : {left:0, right:0, top:0, bottom:0},
14712 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14716 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14717 { dragElId: "existingProxyDiv" });
14718 dd.startDrag = function(){
14719 this.constrainTo("parent-id");
14722 * Or you can initalize it using the {@link Roo.Element} object:
14724 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14725 startDrag : function(){
14726 this.constrainTo("parent-id");
14730 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14731 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14732 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14733 * an object containing the sides to pad. For example: {right:10, bottom:10}
14734 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14736 constrainTo : function(constrainTo, pad, inContent){
14737 if(typeof pad == "number"){
14738 pad = {left: pad, right:pad, top:pad, bottom:pad};
14740 pad = pad || this.defaultPadding;
14741 var b = Roo.get(this.getEl()).getBox();
14742 var ce = Roo.get(constrainTo);
14743 var s = ce.getScroll();
14744 var c, cd = ce.dom;
14745 if(cd == document.body){
14746 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14749 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14753 var topSpace = b.y - c.y;
14754 var leftSpace = b.x - c.x;
14756 this.resetConstraints();
14757 this.setXConstraint(leftSpace - (pad.left||0), // left
14758 c.width - leftSpace - b.width - (pad.right||0) //right
14760 this.setYConstraint(topSpace - (pad.top||0), //top
14761 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14766 * Returns a reference to the linked element
14768 * @return {HTMLElement} the html element
14770 getEl: function() {
14771 if (!this._domRef) {
14772 this._domRef = Roo.getDom(this.id);
14775 return this._domRef;
14779 * Returns a reference to the actual element to drag. By default this is
14780 * the same as the html element, but it can be assigned to another
14781 * element. An example of this can be found in Roo.dd.DDProxy
14782 * @method getDragEl
14783 * @return {HTMLElement} the html element
14785 getDragEl: function() {
14786 return Roo.getDom(this.dragElId);
14790 * Sets up the DragDrop object. Must be called in the constructor of any
14791 * Roo.dd.DragDrop subclass
14793 * @param id the id of the linked element
14794 * @param {String} sGroup the group of related items
14795 * @param {object} config configuration attributes
14797 init: function(id, sGroup, config) {
14798 this.initTarget(id, sGroup, config);
14799 Event.on(this.id, "mousedown", this.handleMouseDown, this);
14800 // Event.on(this.id, "selectstart", Event.preventDefault);
14804 * Initializes Targeting functionality only... the object does not
14805 * get a mousedown handler.
14806 * @method initTarget
14807 * @param id the id of the linked element
14808 * @param {String} sGroup the group of related items
14809 * @param {object} config configuration attributes
14811 initTarget: function(id, sGroup, config) {
14813 // configuration attributes
14814 this.config = config || {};
14816 // create a local reference to the drag and drop manager
14817 this.DDM = Roo.dd.DDM;
14818 // initialize the groups array
14821 // assume that we have an element reference instead of an id if the
14822 // parameter is not a string
14823 if (typeof id !== "string") {
14830 // add to an interaction group
14831 this.addToGroup((sGroup) ? sGroup : "default");
14833 // We don't want to register this as the handle with the manager
14834 // so we just set the id rather than calling the setter.
14835 this.handleElId = id;
14837 // the linked element is the element that gets dragged by default
14838 this.setDragElId(id);
14840 // by default, clicked anchors will not start drag operations.
14841 this.invalidHandleTypes = { A: "A" };
14842 this.invalidHandleIds = {};
14843 this.invalidHandleClasses = [];
14845 this.applyConfig();
14847 this.handleOnAvailable();
14851 * Applies the configuration parameters that were passed into the constructor.
14852 * This is supposed to happen at each level through the inheritance chain. So
14853 * a DDProxy implentation will execute apply config on DDProxy, DD, and
14854 * DragDrop in order to get all of the parameters that are available in
14856 * @method applyConfig
14858 applyConfig: function() {
14860 // configurable properties:
14861 // padding, isTarget, maintainOffset, primaryButtonOnly
14862 this.padding = this.config.padding || [0, 0, 0, 0];
14863 this.isTarget = (this.config.isTarget !== false);
14864 this.maintainOffset = (this.config.maintainOffset);
14865 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
14870 * Executed when the linked element is available
14871 * @method handleOnAvailable
14874 handleOnAvailable: function() {
14875 this.available = true;
14876 this.resetConstraints();
14877 this.onAvailable();
14881 * Configures the padding for the target zone in px. Effectively expands
14882 * (or reduces) the virtual object size for targeting calculations.
14883 * Supports css-style shorthand; if only one parameter is passed, all sides
14884 * will have that padding, and if only two are passed, the top and bottom
14885 * will have the first param, the left and right the second.
14886 * @method setPadding
14887 * @param {int} iTop Top pad
14888 * @param {int} iRight Right pad
14889 * @param {int} iBot Bot pad
14890 * @param {int} iLeft Left pad
14892 setPadding: function(iTop, iRight, iBot, iLeft) {
14893 // this.padding = [iLeft, iRight, iTop, iBot];
14894 if (!iRight && 0 !== iRight) {
14895 this.padding = [iTop, iTop, iTop, iTop];
14896 } else if (!iBot && 0 !== iBot) {
14897 this.padding = [iTop, iRight, iTop, iRight];
14899 this.padding = [iTop, iRight, iBot, iLeft];
14904 * Stores the initial placement of the linked element.
14905 * @method setInitialPosition
14906 * @param {int} diffX the X offset, default 0
14907 * @param {int} diffY the Y offset, default 0
14909 setInitPosition: function(diffX, diffY) {
14910 var el = this.getEl();
14912 if (!this.DDM.verifyEl(el)) {
14916 var dx = diffX || 0;
14917 var dy = diffY || 0;
14919 var p = Dom.getXY( el );
14921 this.initPageX = p[0] - dx;
14922 this.initPageY = p[1] - dy;
14924 this.lastPageX = p[0];
14925 this.lastPageY = p[1];
14928 this.setStartPosition(p);
14932 * Sets the start position of the element. This is set when the obj
14933 * is initialized, the reset when a drag is started.
14934 * @method setStartPosition
14935 * @param pos current position (from previous lookup)
14938 setStartPosition: function(pos) {
14939 var p = pos || Dom.getXY( this.getEl() );
14940 this.deltaSetXY = null;
14942 this.startPageX = p[0];
14943 this.startPageY = p[1];
14947 * Add this instance to a group of related drag/drop objects. All
14948 * instances belong to at least one group, and can belong to as many
14949 * groups as needed.
14950 * @method addToGroup
14951 * @param sGroup {string} the name of the group
14953 addToGroup: function(sGroup) {
14954 this.groups[sGroup] = true;
14955 this.DDM.regDragDrop(this, sGroup);
14959 * Remove's this instance from the supplied interaction group
14960 * @method removeFromGroup
14961 * @param {string} sGroup The group to drop
14963 removeFromGroup: function(sGroup) {
14964 if (this.groups[sGroup]) {
14965 delete this.groups[sGroup];
14968 this.DDM.removeDDFromGroup(this, sGroup);
14972 * Allows you to specify that an element other than the linked element
14973 * will be moved with the cursor during a drag
14974 * @method setDragElId
14975 * @param id {string} the id of the element that will be used to initiate the drag
14977 setDragElId: function(id) {
14978 this.dragElId = id;
14982 * Allows you to specify a child of the linked element that should be
14983 * used to initiate the drag operation. An example of this would be if
14984 * you have a content div with text and links. Clicking anywhere in the
14985 * content area would normally start the drag operation. Use this method
14986 * to specify that an element inside of the content div is the element
14987 * that starts the drag operation.
14988 * @method setHandleElId
14989 * @param id {string} the id of the element that will be used to
14990 * initiate the drag.
14992 setHandleElId: function(id) {
14993 if (typeof id !== "string") {
14996 this.handleElId = id;
14997 this.DDM.regHandle(this.id, id);
15001 * Allows you to set an element outside of the linked element as a drag
15003 * @method setOuterHandleElId
15004 * @param id the id of the element that will be used to initiate the drag
15006 setOuterHandleElId: function(id) {
15007 if (typeof id !== "string") {
15010 Event.on(id, "mousedown",
15011 this.handleMouseDown, this);
15012 this.setHandleElId(id);
15014 this.hasOuterHandles = true;
15018 * Remove all drag and drop hooks for this element
15021 unreg: function() {
15022 Event.un(this.id, "mousedown",
15023 this.handleMouseDown);
15024 this._domRef = null;
15025 this.DDM._remove(this);
15028 destroy : function(){
15033 * Returns true if this instance is locked, or the drag drop mgr is locked
15034 * (meaning that all drag/drop is disabled on the page.)
15036 * @return {boolean} true if this obj or all drag/drop is locked, else
15039 isLocked: function() {
15040 return (this.DDM.isLocked() || this.locked);
15044 * Fired when this object is clicked
15045 * @method handleMouseDown
15047 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15050 handleMouseDown: function(e, oDD){
15051 if (this.primaryButtonOnly && e.button != 0) {
15055 if (this.isLocked()) {
15059 this.DDM.refreshCache(this.groups);
15061 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15062 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15064 if (this.clickValidator(e)) {
15066 // set the initial element position
15067 this.setStartPosition();
15070 this.b4MouseDown(e);
15071 this.onMouseDown(e);
15073 this.DDM.handleMouseDown(e, this);
15075 this.DDM.stopEvent(e);
15083 clickValidator: function(e) {
15084 var target = e.getTarget();
15085 return ( this.isValidHandleChild(target) &&
15086 (this.id == this.handleElId ||
15087 this.DDM.handleWasClicked(target, this.id)) );
15091 * Allows you to specify a tag name that should not start a drag operation
15092 * when clicked. This is designed to facilitate embedding links within a
15093 * drag handle that do something other than start the drag.
15094 * @method addInvalidHandleType
15095 * @param {string} tagName the type of element to exclude
15097 addInvalidHandleType: function(tagName) {
15098 var type = tagName.toUpperCase();
15099 this.invalidHandleTypes[type] = type;
15103 * Lets you to specify an element id for a child of a drag handle
15104 * that should not initiate a drag
15105 * @method addInvalidHandleId
15106 * @param {string} id the element id of the element you wish to ignore
15108 addInvalidHandleId: function(id) {
15109 if (typeof id !== "string") {
15112 this.invalidHandleIds[id] = id;
15116 * Lets you specify a css class of elements that will not initiate a drag
15117 * @method addInvalidHandleClass
15118 * @param {string} cssClass the class of the elements you wish to ignore
15120 addInvalidHandleClass: function(cssClass) {
15121 this.invalidHandleClasses.push(cssClass);
15125 * Unsets an excluded tag name set by addInvalidHandleType
15126 * @method removeInvalidHandleType
15127 * @param {string} tagName the type of element to unexclude
15129 removeInvalidHandleType: function(tagName) {
15130 var type = tagName.toUpperCase();
15131 // this.invalidHandleTypes[type] = null;
15132 delete this.invalidHandleTypes[type];
15136 * Unsets an invalid handle id
15137 * @method removeInvalidHandleId
15138 * @param {string} id the id of the element to re-enable
15140 removeInvalidHandleId: function(id) {
15141 if (typeof id !== "string") {
15144 delete this.invalidHandleIds[id];
15148 * Unsets an invalid css class
15149 * @method removeInvalidHandleClass
15150 * @param {string} cssClass the class of the element(s) you wish to
15153 removeInvalidHandleClass: function(cssClass) {
15154 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15155 if (this.invalidHandleClasses[i] == cssClass) {
15156 delete this.invalidHandleClasses[i];
15162 * Checks the tag exclusion list to see if this click should be ignored
15163 * @method isValidHandleChild
15164 * @param {HTMLElement} node the HTMLElement to evaluate
15165 * @return {boolean} true if this is a valid tag type, false if not
15167 isValidHandleChild: function(node) {
15170 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15173 nodeName = node.nodeName.toUpperCase();
15175 nodeName = node.nodeName;
15177 valid = valid && !this.invalidHandleTypes[nodeName];
15178 valid = valid && !this.invalidHandleIds[node.id];
15180 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15181 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15190 * Create the array of horizontal tick marks if an interval was specified
15191 * in setXConstraint().
15192 * @method setXTicks
15195 setXTicks: function(iStartX, iTickSize) {
15197 this.xTickSize = iTickSize;
15201 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15203 this.xTicks[this.xTicks.length] = i;
15208 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15210 this.xTicks[this.xTicks.length] = i;
15215 this.xTicks.sort(this.DDM.numericSort) ;
15219 * Create the array of vertical tick marks if an interval was specified in
15220 * setYConstraint().
15221 * @method setYTicks
15224 setYTicks: function(iStartY, iTickSize) {
15226 this.yTickSize = iTickSize;
15230 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15232 this.yTicks[this.yTicks.length] = i;
15237 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15239 this.yTicks[this.yTicks.length] = i;
15244 this.yTicks.sort(this.DDM.numericSort) ;
15248 * By default, the element can be dragged any place on the screen. Use
15249 * this method to limit the horizontal travel of the element. Pass in
15250 * 0,0 for the parameters if you want to lock the drag to the y axis.
15251 * @method setXConstraint
15252 * @param {int} iLeft the number of pixels the element can move to the left
15253 * @param {int} iRight the number of pixels the element can move to the
15255 * @param {int} iTickSize optional parameter for specifying that the
15257 * should move iTickSize pixels at a time.
15259 setXConstraint: function(iLeft, iRight, iTickSize) {
15260 this.leftConstraint = iLeft;
15261 this.rightConstraint = iRight;
15263 this.minX = this.initPageX - iLeft;
15264 this.maxX = this.initPageX + iRight;
15265 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15267 this.constrainX = true;
15271 * Clears any constraints applied to this instance. Also clears ticks
15272 * since they can't exist independent of a constraint at this time.
15273 * @method clearConstraints
15275 clearConstraints: function() {
15276 this.constrainX = false;
15277 this.constrainY = false;
15282 * Clears any tick interval defined for this instance
15283 * @method clearTicks
15285 clearTicks: function() {
15286 this.xTicks = null;
15287 this.yTicks = null;
15288 this.xTickSize = 0;
15289 this.yTickSize = 0;
15293 * By default, the element can be dragged any place on the screen. Set
15294 * this to limit the vertical travel of the element. Pass in 0,0 for the
15295 * parameters if you want to lock the drag to the x axis.
15296 * @method setYConstraint
15297 * @param {int} iUp the number of pixels the element can move up
15298 * @param {int} iDown the number of pixels the element can move down
15299 * @param {int} iTickSize optional parameter for specifying that the
15300 * element should move iTickSize pixels at a time.
15302 setYConstraint: function(iUp, iDown, iTickSize) {
15303 this.topConstraint = iUp;
15304 this.bottomConstraint = iDown;
15306 this.minY = this.initPageY - iUp;
15307 this.maxY = this.initPageY + iDown;
15308 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15310 this.constrainY = true;
15315 * resetConstraints must be called if you manually reposition a dd element.
15316 * @method resetConstraints
15317 * @param {boolean} maintainOffset
15319 resetConstraints: function() {
15322 // Maintain offsets if necessary
15323 if (this.initPageX || this.initPageX === 0) {
15324 // figure out how much this thing has moved
15325 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15326 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15328 this.setInitPosition(dx, dy);
15330 // This is the first time we have detected the element's position
15332 this.setInitPosition();
15335 if (this.constrainX) {
15336 this.setXConstraint( this.leftConstraint,
15337 this.rightConstraint,
15341 if (this.constrainY) {
15342 this.setYConstraint( this.topConstraint,
15343 this.bottomConstraint,
15349 * Normally the drag element is moved pixel by pixel, but we can specify
15350 * that it move a number of pixels at a time. This method resolves the
15351 * location when we have it set up like this.
15353 * @param {int} val where we want to place the object
15354 * @param {int[]} tickArray sorted array of valid points
15355 * @return {int} the closest tick
15358 getTick: function(val, tickArray) {
15361 // If tick interval is not defined, it is effectively 1 pixel,
15362 // so we return the value passed to us.
15364 } else if (tickArray[0] >= val) {
15365 // The value is lower than the first tick, so we return the first
15367 return tickArray[0];
15369 for (var i=0, len=tickArray.length; i<len; ++i) {
15371 if (tickArray[next] && tickArray[next] >= val) {
15372 var diff1 = val - tickArray[i];
15373 var diff2 = tickArray[next] - val;
15374 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15378 // The value is larger than the last tick, so we return the last
15380 return tickArray[tickArray.length - 1];
15387 * @return {string} string representation of the dd obj
15389 toString: function() {
15390 return ("DragDrop " + this.id);
15398 * Ext JS Library 1.1.1
15399 * Copyright(c) 2006-2007, Ext JS, LLC.
15401 * Originally Released Under LGPL - original licence link has changed is not relivant.
15404 * <script type="text/javascript">
15409 * The drag and drop utility provides a framework for building drag and drop
15410 * applications. In addition to enabling drag and drop for specific elements,
15411 * the drag and drop elements are tracked by the manager class, and the
15412 * interactions between the various elements are tracked during the drag and
15413 * the implementing code is notified about these important moments.
15416 // Only load the library once. Rewriting the manager class would orphan
15417 // existing drag and drop instances.
15418 if (!Roo.dd.DragDropMgr) {
15421 * @class Roo.dd.DragDropMgr
15422 * DragDropMgr is a singleton that tracks the element interaction for
15423 * all DragDrop items in the window. Generally, you will not call
15424 * this class directly, but it does have helper methods that could
15425 * be useful in your DragDrop implementations.
15428 Roo.dd.DragDropMgr = function() {
15430 var Event = Roo.EventManager;
15435 * Two dimensional Array of registered DragDrop objects. The first
15436 * dimension is the DragDrop item group, the second the DragDrop
15439 * @type {string: string}
15446 * Array of element ids defined as drag handles. Used to determine
15447 * if the element that generated the mousedown event is actually the
15448 * handle and not the html element itself.
15449 * @property handleIds
15450 * @type {string: string}
15457 * the DragDrop object that is currently being dragged
15458 * @property dragCurrent
15466 * the DragDrop object(s) that are being hovered over
15467 * @property dragOvers
15475 * the X distance between the cursor and the object being dragged
15484 * the Y distance between the cursor and the object being dragged
15493 * Flag to determine if we should prevent the default behavior of the
15494 * events we define. By default this is true, but this can be set to
15495 * false if you need the default behavior (not recommended)
15496 * @property preventDefault
15500 preventDefault: true,
15503 * Flag to determine if we should stop the propagation of the events
15504 * we generate. This is true by default but you may want to set it to
15505 * false if the html element contains other features that require the
15507 * @property stopPropagation
15511 stopPropagation: true,
15514 * Internal flag that is set to true when drag and drop has been
15516 * @property initialized
15523 * All drag and drop can be disabled.
15531 * Called the first time an element is registered.
15537 this.initialized = true;
15541 * In point mode, drag and drop interaction is defined by the
15542 * location of the cursor during the drag/drop
15550 * In intersect mode, drag and drop interactio nis defined by the
15551 * overlap of two or more drag and drop objects.
15552 * @property INTERSECT
15559 * The current drag and drop mode. Default: POINT
15567 * Runs method on all drag and drop objects
15568 * @method _execOnAll
15572 _execOnAll: function(sMethod, args) {
15573 for (var i in this.ids) {
15574 for (var j in this.ids[i]) {
15575 var oDD = this.ids[i][j];
15576 if (! this.isTypeOfDD(oDD)) {
15579 oDD[sMethod].apply(oDD, args);
15585 * Drag and drop initialization. Sets up the global event handlers
15590 _onLoad: function() {
15595 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15596 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15597 Event.on(window, "unload", this._onUnload, this, true);
15598 Event.on(window, "resize", this._onResize, this, true);
15599 // Event.on(window, "mouseout", this._test);
15604 * Reset constraints on all drag and drop objs
15605 * @method _onResize
15609 _onResize: function(e) {
15610 this._execOnAll("resetConstraints", []);
15614 * Lock all drag and drop functionality
15618 lock: function() { this.locked = true; },
15621 * Unlock all drag and drop functionality
15625 unlock: function() { this.locked = false; },
15628 * Is drag and drop locked?
15630 * @return {boolean} True if drag and drop is locked, false otherwise.
15633 isLocked: function() { return this.locked; },
15636 * Location cache that is set for all drag drop objects when a drag is
15637 * initiated, cleared when the drag is finished.
15638 * @property locationCache
15645 * Set useCache to false if you want to force object the lookup of each
15646 * drag and drop linked element constantly during a drag.
15647 * @property useCache
15654 * The number of pixels that the mouse needs to move after the
15655 * mousedown before the drag is initiated. Default=3;
15656 * @property clickPixelThresh
15660 clickPixelThresh: 3,
15663 * The number of milliseconds after the mousedown event to initiate the
15664 * drag if we don't get a mouseup event. Default=1000
15665 * @property clickTimeThresh
15669 clickTimeThresh: 350,
15672 * Flag that indicates that either the drag pixel threshold or the
15673 * mousdown time threshold has been met
15674 * @property dragThreshMet
15679 dragThreshMet: false,
15682 * Timeout used for the click time threshold
15683 * @property clickTimeout
15688 clickTimeout: null,
15691 * The X position of the mousedown event stored for later use when a
15692 * drag threshold is met.
15701 * The Y position of the mousedown event stored for later use when a
15702 * drag threshold is met.
15711 * Each DragDrop instance must be registered with the DragDropMgr.
15712 * This is executed in DragDrop.init()
15713 * @method regDragDrop
15714 * @param {DragDrop} oDD the DragDrop object to register
15715 * @param {String} sGroup the name of the group this element belongs to
15718 regDragDrop: function(oDD, sGroup) {
15719 if (!this.initialized) { this.init(); }
15721 if (!this.ids[sGroup]) {
15722 this.ids[sGroup] = {};
15724 this.ids[sGroup][oDD.id] = oDD;
15728 * Removes the supplied dd instance from the supplied group. Executed
15729 * by DragDrop.removeFromGroup, so don't call this function directly.
15730 * @method removeDDFromGroup
15734 removeDDFromGroup: function(oDD, sGroup) {
15735 if (!this.ids[sGroup]) {
15736 this.ids[sGroup] = {};
15739 var obj = this.ids[sGroup];
15740 if (obj && obj[oDD.id]) {
15741 delete obj[oDD.id];
15746 * Unregisters a drag and drop item. This is executed in
15747 * DragDrop.unreg, use that method instead of calling this directly.
15752 _remove: function(oDD) {
15753 for (var g in oDD.groups) {
15754 if (g && this.ids[g][oDD.id]) {
15755 delete this.ids[g][oDD.id];
15758 delete this.handleIds[oDD.id];
15762 * Each DragDrop handle element must be registered. This is done
15763 * automatically when executing DragDrop.setHandleElId()
15764 * @method regHandle
15765 * @param {String} sDDId the DragDrop id this element is a handle for
15766 * @param {String} sHandleId the id of the element that is the drag
15770 regHandle: function(sDDId, sHandleId) {
15771 if (!this.handleIds[sDDId]) {
15772 this.handleIds[sDDId] = {};
15774 this.handleIds[sDDId][sHandleId] = sHandleId;
15778 * Utility function to determine if a given element has been
15779 * registered as a drag drop item.
15780 * @method isDragDrop
15781 * @param {String} id the element id to check
15782 * @return {boolean} true if this element is a DragDrop item,
15786 isDragDrop: function(id) {
15787 return ( this.getDDById(id) ) ? true : false;
15791 * Returns the drag and drop instances that are in all groups the
15792 * passed in instance belongs to.
15793 * @method getRelated
15794 * @param {DragDrop} p_oDD the obj to get related data for
15795 * @param {boolean} bTargetsOnly if true, only return targetable objs
15796 * @return {DragDrop[]} the related instances
15799 getRelated: function(p_oDD, bTargetsOnly) {
15801 for (var i in p_oDD.groups) {
15802 for (j in this.ids[i]) {
15803 var dd = this.ids[i][j];
15804 if (! this.isTypeOfDD(dd)) {
15807 if (!bTargetsOnly || dd.isTarget) {
15808 oDDs[oDDs.length] = dd;
15817 * Returns true if the specified dd target is a legal target for
15818 * the specifice drag obj
15819 * @method isLegalTarget
15820 * @param {DragDrop} the drag obj
15821 * @param {DragDrop} the target
15822 * @return {boolean} true if the target is a legal target for the
15826 isLegalTarget: function (oDD, oTargetDD) {
15827 var targets = this.getRelated(oDD, true);
15828 for (var i=0, len=targets.length;i<len;++i) {
15829 if (targets[i].id == oTargetDD.id) {
15838 * My goal is to be able to transparently determine if an object is
15839 * typeof DragDrop, and the exact subclass of DragDrop. typeof
15840 * returns "object", oDD.constructor.toString() always returns
15841 * "DragDrop" and not the name of the subclass. So for now it just
15842 * evaluates a well-known variable in DragDrop.
15843 * @method isTypeOfDD
15844 * @param {Object} the object to evaluate
15845 * @return {boolean} true if typeof oDD = DragDrop
15848 isTypeOfDD: function (oDD) {
15849 return (oDD && oDD.__ygDragDrop);
15853 * Utility function to determine if a given element has been
15854 * registered as a drag drop handle for the given Drag Drop object.
15856 * @param {String} id the element id to check
15857 * @return {boolean} true if this element is a DragDrop handle, false
15861 isHandle: function(sDDId, sHandleId) {
15862 return ( this.handleIds[sDDId] &&
15863 this.handleIds[sDDId][sHandleId] );
15867 * Returns the DragDrop instance for a given id
15868 * @method getDDById
15869 * @param {String} id the id of the DragDrop object
15870 * @return {DragDrop} the drag drop object, null if it is not found
15873 getDDById: function(id) {
15874 for (var i in this.ids) {
15875 if (this.ids[i][id]) {
15876 return this.ids[i][id];
15883 * Fired after a registered DragDrop object gets the mousedown event.
15884 * Sets up the events required to track the object being dragged
15885 * @method handleMouseDown
15886 * @param {Event} e the event
15887 * @param oDD the DragDrop object being dragged
15891 handleMouseDown: function(e, oDD) {
15893 Roo.QuickTips.disable();
15895 this.currentTarget = e.getTarget();
15897 this.dragCurrent = oDD;
15899 var el = oDD.getEl();
15901 // track start position
15902 this.startX = e.getPageX();
15903 this.startY = e.getPageY();
15905 this.deltaX = this.startX - el.offsetLeft;
15906 this.deltaY = this.startY - el.offsetTop;
15908 this.dragThreshMet = false;
15910 this.clickTimeout = setTimeout(
15912 var DDM = Roo.dd.DDM;
15913 DDM.startDrag(DDM.startX, DDM.startY);
15915 this.clickTimeThresh );
15919 * Fired when either the drag pixel threshol or the mousedown hold
15920 * time threshold has been met.
15921 * @method startDrag
15922 * @param x {int} the X position of the original mousedown
15923 * @param y {int} the Y position of the original mousedown
15926 startDrag: function(x, y) {
15927 clearTimeout(this.clickTimeout);
15928 if (this.dragCurrent) {
15929 this.dragCurrent.b4StartDrag(x, y);
15930 this.dragCurrent.startDrag(x, y);
15932 this.dragThreshMet = true;
15936 * Internal function to handle the mouseup event. Will be invoked
15937 * from the context of the document.
15938 * @method handleMouseUp
15939 * @param {Event} e the event
15943 handleMouseUp: function(e) {
15946 Roo.QuickTips.enable();
15948 if (! this.dragCurrent) {
15952 clearTimeout(this.clickTimeout);
15954 if (this.dragThreshMet) {
15955 this.fireEvents(e, true);
15965 * Utility to stop event propagation and event default, if these
15966 * features are turned on.
15967 * @method stopEvent
15968 * @param {Event} e the event as returned by this.getEvent()
15971 stopEvent: function(e){
15972 if(this.stopPropagation) {
15973 e.stopPropagation();
15976 if (this.preventDefault) {
15977 e.preventDefault();
15982 * Internal function to clean up event handlers after the drag
15983 * operation is complete
15985 * @param {Event} e the event
15989 stopDrag: function(e) {
15990 // Fire the drag end event for the item that was dragged
15991 if (this.dragCurrent) {
15992 if (this.dragThreshMet) {
15993 this.dragCurrent.b4EndDrag(e);
15994 this.dragCurrent.endDrag(e);
15997 this.dragCurrent.onMouseUp(e);
16000 this.dragCurrent = null;
16001 this.dragOvers = {};
16005 * Internal function to handle the mousemove event. Will be invoked
16006 * from the context of the html element.
16008 * @TODO figure out what we can do about mouse events lost when the
16009 * user drags objects beyond the window boundary. Currently we can
16010 * detect this in internet explorer by verifying that the mouse is
16011 * down during the mousemove event. Firefox doesn't give us the
16012 * button state on the mousemove event.
16013 * @method handleMouseMove
16014 * @param {Event} e the event
16018 handleMouseMove: function(e) {
16019 if (! this.dragCurrent) {
16023 // var button = e.which || e.button;
16025 // check for IE mouseup outside of page boundary
16026 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16028 return this.handleMouseUp(e);
16031 if (!this.dragThreshMet) {
16032 var diffX = Math.abs(this.startX - e.getPageX());
16033 var diffY = Math.abs(this.startY - e.getPageY());
16034 if (diffX > this.clickPixelThresh ||
16035 diffY > this.clickPixelThresh) {
16036 this.startDrag(this.startX, this.startY);
16040 if (this.dragThreshMet) {
16041 this.dragCurrent.b4Drag(e);
16042 this.dragCurrent.onDrag(e);
16043 if(!this.dragCurrent.moveOnly){
16044 this.fireEvents(e, false);
16054 * Iterates over all of the DragDrop elements to find ones we are
16055 * hovering over or dropping on
16056 * @method fireEvents
16057 * @param {Event} e the event
16058 * @param {boolean} isDrop is this a drop op or a mouseover op?
16062 fireEvents: function(e, isDrop) {
16063 var dc = this.dragCurrent;
16065 // If the user did the mouse up outside of the window, we could
16066 // get here even though we have ended the drag.
16067 if (!dc || dc.isLocked()) {
16071 var pt = e.getPoint();
16073 // cache the previous dragOver array
16079 var enterEvts = [];
16081 // Check to see if the object(s) we were hovering over is no longer
16082 // being hovered over so we can fire the onDragOut event
16083 for (var i in this.dragOvers) {
16085 var ddo = this.dragOvers[i];
16087 if (! this.isTypeOfDD(ddo)) {
16091 if (! this.isOverTarget(pt, ddo, this.mode)) {
16092 outEvts.push( ddo );
16095 oldOvers[i] = true;
16096 delete this.dragOvers[i];
16099 for (var sGroup in dc.groups) {
16101 if ("string" != typeof sGroup) {
16105 for (i in this.ids[sGroup]) {
16106 var oDD = this.ids[sGroup][i];
16107 if (! this.isTypeOfDD(oDD)) {
16111 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16112 if (this.isOverTarget(pt, oDD, this.mode)) {
16113 // look for drop interactions
16115 dropEvts.push( oDD );
16116 // look for drag enter and drag over interactions
16119 // initial drag over: dragEnter fires
16120 if (!oldOvers[oDD.id]) {
16121 enterEvts.push( oDD );
16122 // subsequent drag overs: dragOver fires
16124 overEvts.push( oDD );
16127 this.dragOvers[oDD.id] = oDD;
16135 if (outEvts.length) {
16136 dc.b4DragOut(e, outEvts);
16137 dc.onDragOut(e, outEvts);
16140 if (enterEvts.length) {
16141 dc.onDragEnter(e, enterEvts);
16144 if (overEvts.length) {
16145 dc.b4DragOver(e, overEvts);
16146 dc.onDragOver(e, overEvts);
16149 if (dropEvts.length) {
16150 dc.b4DragDrop(e, dropEvts);
16151 dc.onDragDrop(e, dropEvts);
16155 // fire dragout events
16157 for (i=0, len=outEvts.length; i<len; ++i) {
16158 dc.b4DragOut(e, outEvts[i].id);
16159 dc.onDragOut(e, outEvts[i].id);
16162 // fire enter events
16163 for (i=0,len=enterEvts.length; i<len; ++i) {
16164 // dc.b4DragEnter(e, oDD.id);
16165 dc.onDragEnter(e, enterEvts[i].id);
16168 // fire over events
16169 for (i=0,len=overEvts.length; i<len; ++i) {
16170 dc.b4DragOver(e, overEvts[i].id);
16171 dc.onDragOver(e, overEvts[i].id);
16174 // fire drop events
16175 for (i=0, len=dropEvts.length; i<len; ++i) {
16176 dc.b4DragDrop(e, dropEvts[i].id);
16177 dc.onDragDrop(e, dropEvts[i].id);
16182 // notify about a drop that did not find a target
16183 if (isDrop && !dropEvts.length) {
16184 dc.onInvalidDrop(e);
16190 * Helper function for getting the best match from the list of drag
16191 * and drop objects returned by the drag and drop events when we are
16192 * in INTERSECT mode. It returns either the first object that the
16193 * cursor is over, or the object that has the greatest overlap with
16194 * the dragged element.
16195 * @method getBestMatch
16196 * @param {DragDrop[]} dds The array of drag and drop objects
16198 * @return {DragDrop} The best single match
16201 getBestMatch: function(dds) {
16203 // Return null if the input is not what we expect
16204 //if (!dds || !dds.length || dds.length == 0) {
16206 // If there is only one item, it wins
16207 //} else if (dds.length == 1) {
16209 var len = dds.length;
16214 // Loop through the targeted items
16215 for (var i=0; i<len; ++i) {
16217 // If the cursor is over the object, it wins. If the
16218 // cursor is over multiple matches, the first one we come
16220 if (dd.cursorIsOver) {
16223 // Otherwise the object with the most overlap wins
16226 winner.overlap.getArea() < dd.overlap.getArea()) {
16237 * Refreshes the cache of the top-left and bottom-right points of the
16238 * drag and drop objects in the specified group(s). This is in the
16239 * format that is stored in the drag and drop instance, so typical
16242 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16246 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16248 * @TODO this really should be an indexed array. Alternatively this
16249 * method could accept both.
16250 * @method refreshCache
16251 * @param {Object} groups an associative array of groups to refresh
16254 refreshCache: function(groups) {
16255 for (var sGroup in groups) {
16256 if ("string" != typeof sGroup) {
16259 for (var i in this.ids[sGroup]) {
16260 var oDD = this.ids[sGroup][i];
16262 if (this.isTypeOfDD(oDD)) {
16263 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16264 var loc = this.getLocation(oDD);
16266 this.locationCache[oDD.id] = loc;
16268 delete this.locationCache[oDD.id];
16269 // this will unregister the drag and drop object if
16270 // the element is not in a usable state
16279 * This checks to make sure an element exists and is in the DOM. The
16280 * main purpose is to handle cases where innerHTML is used to remove
16281 * drag and drop objects from the DOM. IE provides an 'unspecified
16282 * error' when trying to access the offsetParent of such an element
16284 * @param {HTMLElement} el the element to check
16285 * @return {boolean} true if the element looks usable
16288 verifyEl: function(el) {
16293 parent = el.offsetParent;
16296 parent = el.offsetParent;
16307 * Returns a Region object containing the drag and drop element's position
16308 * and size, including the padding configured for it
16309 * @method getLocation
16310 * @param {DragDrop} oDD the drag and drop object to get the
16312 * @return {Roo.lib.Region} a Region object representing the total area
16313 * the element occupies, including any padding
16314 * the instance is configured for.
16317 getLocation: function(oDD) {
16318 if (! this.isTypeOfDD(oDD)) {
16322 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16325 pos= Roo.lib.Dom.getXY(el);
16333 x2 = x1 + el.offsetWidth;
16335 y2 = y1 + el.offsetHeight;
16337 t = y1 - oDD.padding[0];
16338 r = x2 + oDD.padding[1];
16339 b = y2 + oDD.padding[2];
16340 l = x1 - oDD.padding[3];
16342 return new Roo.lib.Region( t, r, b, l );
16346 * Checks the cursor location to see if it over the target
16347 * @method isOverTarget
16348 * @param {Roo.lib.Point} pt The point to evaluate
16349 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16350 * @return {boolean} true if the mouse is over the target
16354 isOverTarget: function(pt, oTarget, intersect) {
16355 // use cache if available
16356 var loc = this.locationCache[oTarget.id];
16357 if (!loc || !this.useCache) {
16358 loc = this.getLocation(oTarget);
16359 this.locationCache[oTarget.id] = loc;
16367 oTarget.cursorIsOver = loc.contains( pt );
16369 // DragDrop is using this as a sanity check for the initial mousedown
16370 // in this case we are done. In POINT mode, if the drag obj has no
16371 // contraints, we are also done. Otherwise we need to evaluate the
16372 // location of the target as related to the actual location of the
16373 // dragged element.
16374 var dc = this.dragCurrent;
16375 if (!dc || !dc.getTargetCoord ||
16376 (!intersect && !dc.constrainX && !dc.constrainY)) {
16377 return oTarget.cursorIsOver;
16380 oTarget.overlap = null;
16382 // Get the current location of the drag element, this is the
16383 // location of the mouse event less the delta that represents
16384 // where the original mousedown happened on the element. We
16385 // need to consider constraints and ticks as well.
16386 var pos = dc.getTargetCoord(pt.x, pt.y);
16388 var el = dc.getDragEl();
16389 var curRegion = new Roo.lib.Region( pos.y,
16390 pos.x + el.offsetWidth,
16391 pos.y + el.offsetHeight,
16394 var overlap = curRegion.intersect(loc);
16397 oTarget.overlap = overlap;
16398 return (intersect) ? true : oTarget.cursorIsOver;
16405 * unload event handler
16406 * @method _onUnload
16410 _onUnload: function(e, me) {
16411 Roo.dd.DragDropMgr.unregAll();
16415 * Cleans up the drag and drop events and objects.
16420 unregAll: function() {
16422 if (this.dragCurrent) {
16424 this.dragCurrent = null;
16427 this._execOnAll("unreg", []);
16429 for (i in this.elementCache) {
16430 delete this.elementCache[i];
16433 this.elementCache = {};
16438 * A cache of DOM elements
16439 * @property elementCache
16446 * Get the wrapper for the DOM element specified
16447 * @method getElWrapper
16448 * @param {String} id the id of the element to get
16449 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16451 * @deprecated This wrapper isn't that useful
16454 getElWrapper: function(id) {
16455 var oWrapper = this.elementCache[id];
16456 if (!oWrapper || !oWrapper.el) {
16457 oWrapper = this.elementCache[id] =
16458 new this.ElementWrapper(Roo.getDom(id));
16464 * Returns the actual DOM element
16465 * @method getElement
16466 * @param {String} id the id of the elment to get
16467 * @return {Object} The element
16468 * @deprecated use Roo.getDom instead
16471 getElement: function(id) {
16472 return Roo.getDom(id);
16476 * Returns the style property for the DOM element (i.e.,
16477 * document.getElById(id).style)
16479 * @param {String} id the id of the elment to get
16480 * @return {Object} The style property of the element
16481 * @deprecated use Roo.getDom instead
16484 getCss: function(id) {
16485 var el = Roo.getDom(id);
16486 return (el) ? el.style : null;
16490 * Inner class for cached elements
16491 * @class DragDropMgr.ElementWrapper
16496 ElementWrapper: function(el) {
16501 this.el = el || null;
16506 this.id = this.el && el.id;
16508 * A reference to the style property
16511 this.css = this.el && el.style;
16515 * Returns the X position of an html element
16517 * @param el the element for which to get the position
16518 * @return {int} the X coordinate
16520 * @deprecated use Roo.lib.Dom.getX instead
16523 getPosX: function(el) {
16524 return Roo.lib.Dom.getX(el);
16528 * Returns the Y position of an html element
16530 * @param el the element for which to get the position
16531 * @return {int} the Y coordinate
16532 * @deprecated use Roo.lib.Dom.getY instead
16535 getPosY: function(el) {
16536 return Roo.lib.Dom.getY(el);
16540 * Swap two nodes. In IE, we use the native method, for others we
16541 * emulate the IE behavior
16543 * @param n1 the first node to swap
16544 * @param n2 the other node to swap
16547 swapNode: function(n1, n2) {
16551 var p = n2.parentNode;
16552 var s = n2.nextSibling;
16555 p.insertBefore(n1, n2);
16556 } else if (n2 == n1.nextSibling) {
16557 p.insertBefore(n2, n1);
16559 n1.parentNode.replaceChild(n2, n1);
16560 p.insertBefore(n1, s);
16566 * Returns the current scroll position
16567 * @method getScroll
16571 getScroll: function () {
16572 var t, l, dde=document.documentElement, db=document.body;
16573 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16575 l = dde.scrollLeft;
16582 return { top: t, left: l };
16586 * Returns the specified element style property
16588 * @param {HTMLElement} el the element
16589 * @param {string} styleProp the style property
16590 * @return {string} The value of the style property
16591 * @deprecated use Roo.lib.Dom.getStyle
16594 getStyle: function(el, styleProp) {
16595 return Roo.fly(el).getStyle(styleProp);
16599 * Gets the scrollTop
16600 * @method getScrollTop
16601 * @return {int} the document's scrollTop
16604 getScrollTop: function () { return this.getScroll().top; },
16607 * Gets the scrollLeft
16608 * @method getScrollLeft
16609 * @return {int} the document's scrollTop
16612 getScrollLeft: function () { return this.getScroll().left; },
16615 * Sets the x/y position of an element to the location of the
16618 * @param {HTMLElement} moveEl The element to move
16619 * @param {HTMLElement} targetEl The position reference element
16622 moveToEl: function (moveEl, targetEl) {
16623 var aCoord = Roo.lib.Dom.getXY(targetEl);
16624 Roo.lib.Dom.setXY(moveEl, aCoord);
16628 * Numeric array sort function
16629 * @method numericSort
16632 numericSort: function(a, b) { return (a - b); },
16636 * @property _timeoutCount
16643 * Trying to make the load order less important. Without this we get
16644 * an error if this file is loaded before the Event Utility.
16645 * @method _addListeners
16649 _addListeners: function() {
16650 var DDM = Roo.dd.DDM;
16651 if ( Roo.lib.Event && document ) {
16654 if (DDM._timeoutCount > 2000) {
16656 setTimeout(DDM._addListeners, 10);
16657 if (document && document.body) {
16658 DDM._timeoutCount += 1;
16665 * Recursively searches the immediate parent and all child nodes for
16666 * the handle element in order to determine wheter or not it was
16668 * @method handleWasClicked
16669 * @param node the html element to inspect
16672 handleWasClicked: function(node, id) {
16673 if (this.isHandle(id, node.id)) {
16676 // check to see if this is a text node child of the one we want
16677 var p = node.parentNode;
16680 if (this.isHandle(id, p.id)) {
16695 // shorter alias, save a few bytes
16696 Roo.dd.DDM = Roo.dd.DragDropMgr;
16697 Roo.dd.DDM._addListeners();
16701 * Ext JS Library 1.1.1
16702 * Copyright(c) 2006-2007, Ext JS, LLC.
16704 * Originally Released Under LGPL - original licence link has changed is not relivant.
16707 * <script type="text/javascript">
16712 * A DragDrop implementation where the linked element follows the
16713 * mouse cursor during a drag.
16714 * @extends Roo.dd.DragDrop
16716 * @param {String} id the id of the linked element
16717 * @param {String} sGroup the group of related DragDrop items
16718 * @param {object} config an object containing configurable attributes
16719 * Valid properties for DD:
16722 Roo.dd.DD = function(id, sGroup, config) {
16724 this.init(id, sGroup, config);
16728 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16731 * When set to true, the utility automatically tries to scroll the browser
16732 * window wehn a drag and drop element is dragged near the viewport boundary.
16733 * Defaults to true.
16740 * Sets the pointer offset to the distance between the linked element's top
16741 * left corner and the location the element was clicked
16742 * @method autoOffset
16743 * @param {int} iPageX the X coordinate of the click
16744 * @param {int} iPageY the Y coordinate of the click
16746 autoOffset: function(iPageX, iPageY) {
16747 var x = iPageX - this.startPageX;
16748 var y = iPageY - this.startPageY;
16749 this.setDelta(x, y);
16753 * Sets the pointer offset. You can call this directly to force the
16754 * offset to be in a particular location (e.g., pass in 0,0 to set it
16755 * to the center of the object)
16757 * @param {int} iDeltaX the distance from the left
16758 * @param {int} iDeltaY the distance from the top
16760 setDelta: function(iDeltaX, iDeltaY) {
16761 this.deltaX = iDeltaX;
16762 this.deltaY = iDeltaY;
16766 * Sets the drag element to the location of the mousedown or click event,
16767 * maintaining the cursor location relative to the location on the element
16768 * that was clicked. Override this if you want to place the element in a
16769 * location other than where the cursor is.
16770 * @method setDragElPos
16771 * @param {int} iPageX the X coordinate of the mousedown or drag event
16772 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16774 setDragElPos: function(iPageX, iPageY) {
16775 // the first time we do this, we are going to check to make sure
16776 // the element has css positioning
16778 var el = this.getDragEl();
16779 this.alignElWithMouse(el, iPageX, iPageY);
16783 * Sets the element to the location of the mousedown or click event,
16784 * maintaining the cursor location relative to the location on the element
16785 * that was clicked. Override this if you want to place the element in a
16786 * location other than where the cursor is.
16787 * @method alignElWithMouse
16788 * @param {HTMLElement} el the element to move
16789 * @param {int} iPageX the X coordinate of the mousedown or drag event
16790 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16792 alignElWithMouse: function(el, iPageX, iPageY) {
16793 var oCoord = this.getTargetCoord(iPageX, iPageY);
16794 var fly = el.dom ? el : Roo.fly(el);
16795 if (!this.deltaSetXY) {
16796 var aCoord = [oCoord.x, oCoord.y];
16798 var newLeft = fly.getLeft(true);
16799 var newTop = fly.getTop(true);
16800 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
16802 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
16805 this.cachePosition(oCoord.x, oCoord.y);
16806 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
16811 * Saves the most recent position so that we can reset the constraints and
16812 * tick marks on-demand. We need to know this so that we can calculate the
16813 * number of pixels the element is offset from its original position.
16814 * @method cachePosition
16815 * @param iPageX the current x position (optional, this just makes it so we
16816 * don't have to look it up again)
16817 * @param iPageY the current y position (optional, this just makes it so we
16818 * don't have to look it up again)
16820 cachePosition: function(iPageX, iPageY) {
16822 this.lastPageX = iPageX;
16823 this.lastPageY = iPageY;
16825 var aCoord = Roo.lib.Dom.getXY(this.getEl());
16826 this.lastPageX = aCoord[0];
16827 this.lastPageY = aCoord[1];
16832 * Auto-scroll the window if the dragged object has been moved beyond the
16833 * visible window boundary.
16834 * @method autoScroll
16835 * @param {int} x the drag element's x position
16836 * @param {int} y the drag element's y position
16837 * @param {int} h the height of the drag element
16838 * @param {int} w the width of the drag element
16841 autoScroll: function(x, y, h, w) {
16844 // The client height
16845 var clientH = Roo.lib.Dom.getViewWidth();
16847 // The client width
16848 var clientW = Roo.lib.Dom.getViewHeight();
16850 // The amt scrolled down
16851 var st = this.DDM.getScrollTop();
16853 // The amt scrolled right
16854 var sl = this.DDM.getScrollLeft();
16856 // Location of the bottom of the element
16859 // Location of the right of the element
16862 // The distance from the cursor to the bottom of the visible area,
16863 // adjusted so that we don't scroll if the cursor is beyond the
16864 // element drag constraints
16865 var toBot = (clientH + st - y - this.deltaY);
16867 // The distance from the cursor to the right of the visible area
16868 var toRight = (clientW + sl - x - this.deltaX);
16871 // How close to the edge the cursor must be before we scroll
16872 // var thresh = (document.all) ? 100 : 40;
16875 // How many pixels to scroll per autoscroll op. This helps to reduce
16876 // clunky scrolling. IE is more sensitive about this ... it needs this
16877 // value to be higher.
16878 var scrAmt = (document.all) ? 80 : 30;
16880 // Scroll down if we are near the bottom of the visible page and the
16881 // obj extends below the crease
16882 if ( bot > clientH && toBot < thresh ) {
16883 window.scrollTo(sl, st + scrAmt);
16886 // Scroll up if the window is scrolled down and the top of the object
16887 // goes above the top border
16888 if ( y < st && st > 0 && y - st < thresh ) {
16889 window.scrollTo(sl, st - scrAmt);
16892 // Scroll right if the obj is beyond the right border and the cursor is
16893 // near the border.
16894 if ( right > clientW && toRight < thresh ) {
16895 window.scrollTo(sl + scrAmt, st);
16898 // Scroll left if the window has been scrolled to the right and the obj
16899 // extends past the left border
16900 if ( x < sl && sl > 0 && x - sl < thresh ) {
16901 window.scrollTo(sl - scrAmt, st);
16907 * Finds the location the element should be placed if we want to move
16908 * it to where the mouse location less the click offset would place us.
16909 * @method getTargetCoord
16910 * @param {int} iPageX the X coordinate of the click
16911 * @param {int} iPageY the Y coordinate of the click
16912 * @return an object that contains the coordinates (Object.x and Object.y)
16915 getTargetCoord: function(iPageX, iPageY) {
16918 var x = iPageX - this.deltaX;
16919 var y = iPageY - this.deltaY;
16921 if (this.constrainX) {
16922 if (x < this.minX) { x = this.minX; }
16923 if (x > this.maxX) { x = this.maxX; }
16926 if (this.constrainY) {
16927 if (y < this.minY) { y = this.minY; }
16928 if (y > this.maxY) { y = this.maxY; }
16931 x = this.getTick(x, this.xTicks);
16932 y = this.getTick(y, this.yTicks);
16939 * Sets up config options specific to this class. Overrides
16940 * Roo.dd.DragDrop, but all versions of this method through the
16941 * inheritance chain are called
16943 applyConfig: function() {
16944 Roo.dd.DD.superclass.applyConfig.call(this);
16945 this.scroll = (this.config.scroll !== false);
16949 * Event that fires prior to the onMouseDown event. Overrides
16952 b4MouseDown: function(e) {
16953 // this.resetConstraints();
16954 this.autoOffset(e.getPageX(),
16959 * Event that fires prior to the onDrag event. Overrides
16962 b4Drag: function(e) {
16963 this.setDragElPos(e.getPageX(),
16967 toString: function() {
16968 return ("DD " + this.id);
16971 //////////////////////////////////////////////////////////////////////////
16972 // Debugging ygDragDrop events that can be overridden
16973 //////////////////////////////////////////////////////////////////////////
16975 startDrag: function(x, y) {
16978 onDrag: function(e) {
16981 onDragEnter: function(e, id) {
16984 onDragOver: function(e, id) {
16987 onDragOut: function(e, id) {
16990 onDragDrop: function(e, id) {
16993 endDrag: function(e) {
17000 * Ext JS Library 1.1.1
17001 * Copyright(c) 2006-2007, Ext JS, LLC.
17003 * Originally Released Under LGPL - original licence link has changed is not relivant.
17006 * <script type="text/javascript">
17010 * @class Roo.dd.DDProxy
17011 * A DragDrop implementation that inserts an empty, bordered div into
17012 * the document that follows the cursor during drag operations. At the time of
17013 * the click, the frame div is resized to the dimensions of the linked html
17014 * element, and moved to the exact location of the linked element.
17016 * References to the "frame" element refer to the single proxy element that
17017 * was created to be dragged in place of all DDProxy elements on the
17020 * @extends Roo.dd.DD
17022 * @param {String} id the id of the linked html element
17023 * @param {String} sGroup the group of related DragDrop objects
17024 * @param {object} config an object containing configurable attributes
17025 * Valid properties for DDProxy in addition to those in DragDrop:
17026 * resizeFrame, centerFrame, dragElId
17028 Roo.dd.DDProxy = function(id, sGroup, config) {
17030 this.init(id, sGroup, config);
17036 * The default drag frame div id
17037 * @property Roo.dd.DDProxy.dragElId
17041 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17043 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17046 * By default we resize the drag frame to be the same size as the element
17047 * we want to drag (this is to get the frame effect). We can turn it off
17048 * if we want a different behavior.
17049 * @property resizeFrame
17055 * By default the frame is positioned exactly where the drag element is, so
17056 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17057 * you do not have constraints on the obj is to have the drag frame centered
17058 * around the cursor. Set centerFrame to true for this effect.
17059 * @property centerFrame
17062 centerFrame: false,
17065 * Creates the proxy element if it does not yet exist
17066 * @method createFrame
17068 createFrame: function() {
17070 var body = document.body;
17072 if (!body || !body.firstChild) {
17073 setTimeout( function() { self.createFrame(); }, 50 );
17077 var div = this.getDragEl();
17080 div = document.createElement("div");
17081 div.id = this.dragElId;
17084 s.position = "absolute";
17085 s.visibility = "hidden";
17087 s.border = "2px solid #aaa";
17090 // appendChild can blow up IE if invoked prior to the window load event
17091 // while rendering a table. It is possible there are other scenarios
17092 // that would cause this to happen as well.
17093 body.insertBefore(div, body.firstChild);
17098 * Initialization for the drag frame element. Must be called in the
17099 * constructor of all subclasses
17100 * @method initFrame
17102 initFrame: function() {
17103 this.createFrame();
17106 applyConfig: function() {
17107 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17109 this.resizeFrame = (this.config.resizeFrame !== false);
17110 this.centerFrame = (this.config.centerFrame);
17111 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17115 * Resizes the drag frame to the dimensions of the clicked object, positions
17116 * it over the object, and finally displays it
17117 * @method showFrame
17118 * @param {int} iPageX X click position
17119 * @param {int} iPageY Y click position
17122 showFrame: function(iPageX, iPageY) {
17123 var el = this.getEl();
17124 var dragEl = this.getDragEl();
17125 var s = dragEl.style;
17127 this._resizeProxy();
17129 if (this.centerFrame) {
17130 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17131 Math.round(parseInt(s.height, 10)/2) );
17134 this.setDragElPos(iPageX, iPageY);
17136 Roo.fly(dragEl).show();
17140 * The proxy is automatically resized to the dimensions of the linked
17141 * element when a drag is initiated, unless resizeFrame is set to false
17142 * @method _resizeProxy
17145 _resizeProxy: function() {
17146 if (this.resizeFrame) {
17147 var el = this.getEl();
17148 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17152 // overrides Roo.dd.DragDrop
17153 b4MouseDown: function(e) {
17154 var x = e.getPageX();
17155 var y = e.getPageY();
17156 this.autoOffset(x, y);
17157 this.setDragElPos(x, y);
17160 // overrides Roo.dd.DragDrop
17161 b4StartDrag: function(x, y) {
17162 // show the drag frame
17163 this.showFrame(x, y);
17166 // overrides Roo.dd.DragDrop
17167 b4EndDrag: function(e) {
17168 Roo.fly(this.getDragEl()).hide();
17171 // overrides Roo.dd.DragDrop
17172 // By default we try to move the element to the last location of the frame.
17173 // This is so that the default behavior mirrors that of Roo.dd.DD.
17174 endDrag: function(e) {
17176 var lel = this.getEl();
17177 var del = this.getDragEl();
17179 // Show the drag frame briefly so we can get its position
17180 del.style.visibility = "";
17183 // Hide the linked element before the move to get around a Safari
17185 lel.style.visibility = "hidden";
17186 Roo.dd.DDM.moveToEl(lel, del);
17187 del.style.visibility = "hidden";
17188 lel.style.visibility = "";
17193 beforeMove : function(){
17197 afterDrag : function(){
17201 toString: function() {
17202 return ("DDProxy " + this.id);
17208 * Ext JS Library 1.1.1
17209 * Copyright(c) 2006-2007, Ext JS, LLC.
17211 * Originally Released Under LGPL - original licence link has changed is not relivant.
17214 * <script type="text/javascript">
17218 * @class Roo.dd.DDTarget
17219 * A DragDrop implementation that does not move, but can be a drop
17220 * target. You would get the same result by simply omitting implementation
17221 * for the event callbacks, but this way we reduce the processing cost of the
17222 * event listener and the callbacks.
17223 * @extends Roo.dd.DragDrop
17225 * @param {String} id the id of the element that is a drop target
17226 * @param {String} sGroup the group of related DragDrop objects
17227 * @param {object} config an object containing configurable attributes
17228 * Valid properties for DDTarget in addition to those in
17232 Roo.dd.DDTarget = function(id, sGroup, config) {
17234 this.initTarget(id, sGroup, config);
17238 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17239 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17240 toString: function() {
17241 return ("DDTarget " + this.id);
17246 * Ext JS Library 1.1.1
17247 * Copyright(c) 2006-2007, Ext JS, LLC.
17249 * Originally Released Under LGPL - original licence link has changed is not relivant.
17252 * <script type="text/javascript">
17257 * @class Roo.dd.ScrollManager
17258 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17259 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17262 Roo.dd.ScrollManager = function(){
17263 var ddm = Roo.dd.DragDropMgr;
17268 var onStop = function(e){
17273 var triggerRefresh = function(){
17274 if(ddm.dragCurrent){
17275 ddm.refreshCache(ddm.dragCurrent.groups);
17279 var doScroll = function(){
17280 if(ddm.dragCurrent){
17281 var dds = Roo.dd.ScrollManager;
17283 if(proc.el.scroll(proc.dir, dds.increment)){
17287 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17292 var clearProc = function(){
17294 clearInterval(proc.id);
17301 var startProc = function(el, dir){
17305 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17308 var onFire = function(e, isDrop){
17309 if(isDrop || !ddm.dragCurrent){ return; }
17310 var dds = Roo.dd.ScrollManager;
17311 if(!dragEl || dragEl != ddm.dragCurrent){
17312 dragEl = ddm.dragCurrent;
17313 // refresh regions on drag start
17314 dds.refreshCache();
17317 var xy = Roo.lib.Event.getXY(e);
17318 var pt = new Roo.lib.Point(xy[0], xy[1]);
17319 for(var id in els){
17320 var el = els[id], r = el._region;
17321 if(r && r.contains(pt) && el.isScrollable()){
17322 if(r.bottom - pt.y <= dds.thresh){
17324 startProc(el, "down");
17327 }else if(r.right - pt.x <= dds.thresh){
17329 startProc(el, "left");
17332 }else if(pt.y - r.top <= dds.thresh){
17334 startProc(el, "up");
17337 }else if(pt.x - r.left <= dds.thresh){
17339 startProc(el, "right");
17348 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17349 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17353 * Registers new overflow element(s) to auto scroll
17354 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17356 register : function(el){
17357 if(el instanceof Array){
17358 for(var i = 0, len = el.length; i < len; i++) {
17359 this.register(el[i]);
17368 * Unregisters overflow element(s) so they are no longer scrolled
17369 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17371 unregister : function(el){
17372 if(el instanceof Array){
17373 for(var i = 0, len = el.length; i < len; i++) {
17374 this.unregister(el[i]);
17383 * The number of pixels from the edge of a container the pointer needs to be to
17384 * trigger scrolling (defaults to 25)
17390 * The number of pixels to scroll in each scroll increment (defaults to 50)
17396 * The frequency of scrolls in milliseconds (defaults to 500)
17402 * True to animate the scroll (defaults to true)
17408 * The animation duration in seconds -
17409 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17415 * Manually trigger a cache refresh.
17417 refreshCache : function(){
17418 for(var id in els){
17419 if(typeof els[id] == 'object'){ // for people extending the object prototype
17420 els[id]._region = els[id].getRegion();
17427 * Ext JS Library 1.1.1
17428 * Copyright(c) 2006-2007, Ext JS, LLC.
17430 * Originally Released Under LGPL - original licence link has changed is not relivant.
17433 * <script type="text/javascript">
17438 * @class Roo.dd.Registry
17439 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17440 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17443 Roo.dd.Registry = function(){
17446 var autoIdSeed = 0;
17448 var getId = function(el, autogen){
17449 if(typeof el == "string"){
17453 if(!id && autogen !== false){
17454 id = "roodd-" + (++autoIdSeed);
17462 * Register a drag drop element
17463 * @param {String|HTMLElement} element The id or DOM node to register
17464 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17465 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17466 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17467 * populated in the data object (if applicable):
17469 Value Description<br />
17470 --------- ------------------------------------------<br />
17471 handles Array of DOM nodes that trigger dragging<br />
17472 for the element being registered<br />
17473 isHandle True if the element passed in triggers<br />
17474 dragging itself, else false
17477 register : function(el, data){
17479 if(typeof el == "string"){
17480 el = document.getElementById(el);
17483 elements[getId(el)] = data;
17484 if(data.isHandle !== false){
17485 handles[data.ddel.id] = data;
17488 var hs = data.handles;
17489 for(var i = 0, len = hs.length; i < len; i++){
17490 handles[getId(hs[i])] = data;
17496 * Unregister a drag drop element
17497 * @param {String|HTMLElement} element The id or DOM node to unregister
17499 unregister : function(el){
17500 var id = getId(el, false);
17501 var data = elements[id];
17503 delete elements[id];
17505 var hs = data.handles;
17506 for(var i = 0, len = hs.length; i < len; i++){
17507 delete handles[getId(hs[i], false)];
17514 * Returns the handle registered for a DOM Node by id
17515 * @param {String|HTMLElement} id The DOM node or id to look up
17516 * @return {Object} handle The custom handle data
17518 getHandle : function(id){
17519 if(typeof id != "string"){ // must be element?
17522 return handles[id];
17526 * Returns the handle that is registered for the DOM node that is the target of the event
17527 * @param {Event} e The event
17528 * @return {Object} handle The custom handle data
17530 getHandleFromEvent : function(e){
17531 var t = Roo.lib.Event.getTarget(e);
17532 return t ? handles[t.id] : null;
17536 * Returns a custom data object that is registered for a DOM node by id
17537 * @param {String|HTMLElement} id The DOM node or id to look up
17538 * @return {Object} data The custom data
17540 getTarget : function(id){
17541 if(typeof id != "string"){ // must be element?
17544 return elements[id];
17548 * Returns a custom data object that is registered for the DOM node that is the target of the event
17549 * @param {Event} e The event
17550 * @return {Object} data The custom data
17552 getTargetFromEvent : function(e){
17553 var t = Roo.lib.Event.getTarget(e);
17554 return t ? elements[t.id] || handles[t.id] : null;
17559 * Ext JS Library 1.1.1
17560 * Copyright(c) 2006-2007, Ext JS, LLC.
17562 * Originally Released Under LGPL - original licence link has changed is not relivant.
17565 * <script type="text/javascript">
17570 * @class Roo.dd.StatusProxy
17571 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17572 * default drag proxy used by all Roo.dd components.
17574 * @param {Object} config
17576 Roo.dd.StatusProxy = function(config){
17577 Roo.apply(this, config);
17578 this.id = this.id || Roo.id();
17579 this.el = new Roo.Layer({
17581 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17582 {tag: "div", cls: "x-dd-drop-icon"},
17583 {tag: "div", cls: "x-dd-drag-ghost"}
17586 shadow: !config || config.shadow !== false
17588 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17589 this.dropStatus = this.dropNotAllowed;
17592 Roo.dd.StatusProxy.prototype = {
17594 * @cfg {String} dropAllowed
17595 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17597 dropAllowed : "x-dd-drop-ok",
17599 * @cfg {String} dropNotAllowed
17600 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17602 dropNotAllowed : "x-dd-drop-nodrop",
17605 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17606 * over the current target element.
17607 * @param {String} cssClass The css class for the new drop status indicator image
17609 setStatus : function(cssClass){
17610 cssClass = cssClass || this.dropNotAllowed;
17611 if(this.dropStatus != cssClass){
17612 this.el.replaceClass(this.dropStatus, cssClass);
17613 this.dropStatus = cssClass;
17618 * Resets the status indicator to the default dropNotAllowed value
17619 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17621 reset : function(clearGhost){
17622 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17623 this.dropStatus = this.dropNotAllowed;
17625 this.ghost.update("");
17630 * Updates the contents of the ghost element
17631 * @param {String} html The html that will replace the current innerHTML of the ghost element
17633 update : function(html){
17634 if(typeof html == "string"){
17635 this.ghost.update(html);
17637 this.ghost.update("");
17638 html.style.margin = "0";
17639 this.ghost.dom.appendChild(html);
17641 // ensure float = none set?? cant remember why though.
17642 var el = this.ghost.dom.firstChild;
17644 Roo.fly(el).setStyle('float', 'none');
17649 * Returns the underlying proxy {@link Roo.Layer}
17650 * @return {Roo.Layer} el
17652 getEl : function(){
17657 * Returns the ghost element
17658 * @return {Roo.Element} el
17660 getGhost : function(){
17666 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17668 hide : function(clear){
17676 * Stops the repair animation if it's currently running
17679 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17685 * Displays this proxy
17692 * Force the Layer to sync its shadow and shim positions to the element
17699 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17700 * invalid drop operation by the item being dragged.
17701 * @param {Array} xy The XY position of the element ([x, y])
17702 * @param {Function} callback The function to call after the repair is complete
17703 * @param {Object} scope The scope in which to execute the callback
17705 repair : function(xy, callback, scope){
17706 this.callback = callback;
17707 this.scope = scope;
17708 if(xy && this.animRepair !== false){
17709 this.el.addClass("x-dd-drag-repair");
17710 this.el.hideUnders(true);
17711 this.anim = this.el.shift({
17712 duration: this.repairDuration || .5,
17716 callback: this.afterRepair,
17720 this.afterRepair();
17725 afterRepair : function(){
17727 if(typeof this.callback == "function"){
17728 this.callback.call(this.scope || this);
17730 this.callback = null;
17735 * Ext JS Library 1.1.1
17736 * Copyright(c) 2006-2007, Ext JS, LLC.
17738 * Originally Released Under LGPL - original licence link has changed is not relivant.
17741 * <script type="text/javascript">
17745 * @class Roo.dd.DragSource
17746 * @extends Roo.dd.DDProxy
17747 * A simple class that provides the basic implementation needed to make any element draggable.
17749 * @param {String/HTMLElement/Element} el The container element
17750 * @param {Object} config
17752 Roo.dd.DragSource = function(el, config){
17753 this.el = Roo.get(el);
17754 this.dragData = {};
17756 Roo.apply(this, config);
17759 this.proxy = new Roo.dd.StatusProxy();
17762 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17763 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17765 this.dragging = false;
17768 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17770 * @cfg {String} dropAllowed
17771 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17773 dropAllowed : "x-dd-drop-ok",
17775 * @cfg {String} dropNotAllowed
17776 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17778 dropNotAllowed : "x-dd-drop-nodrop",
17781 * Returns the data object associated with this drag source
17782 * @return {Object} data An object containing arbitrary data
17784 getDragData : function(e){
17785 return this.dragData;
17789 onDragEnter : function(e, id){
17790 var target = Roo.dd.DragDropMgr.getDDById(id);
17791 this.cachedTarget = target;
17792 if(this.beforeDragEnter(target, e, id) !== false){
17793 if(target.isNotifyTarget){
17794 var status = target.notifyEnter(this, e, this.dragData);
17795 this.proxy.setStatus(status);
17797 this.proxy.setStatus(this.dropAllowed);
17800 if(this.afterDragEnter){
17802 * An empty function by default, but provided so that you can perform a custom action
17803 * when the dragged item enters the drop target by providing an implementation.
17804 * @param {Roo.dd.DragDrop} target The drop target
17805 * @param {Event} e The event object
17806 * @param {String} id The id of the dragged element
17807 * @method afterDragEnter
17809 this.afterDragEnter(target, e, id);
17815 * An empty function by default, but provided so that you can perform a custom action
17816 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
17817 * @param {Roo.dd.DragDrop} target The drop target
17818 * @param {Event} e The event object
17819 * @param {String} id The id of the dragged element
17820 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17822 beforeDragEnter : function(target, e, id){
17827 alignElWithMouse: function() {
17828 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
17833 onDragOver : function(e, id){
17834 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17835 if(this.beforeDragOver(target, e, id) !== false){
17836 if(target.isNotifyTarget){
17837 var status = target.notifyOver(this, e, this.dragData);
17838 this.proxy.setStatus(status);
17841 if(this.afterDragOver){
17843 * An empty function by default, but provided so that you can perform a custom action
17844 * while the dragged item is over the drop target by providing an implementation.
17845 * @param {Roo.dd.DragDrop} target The drop target
17846 * @param {Event} e The event object
17847 * @param {String} id The id of the dragged element
17848 * @method afterDragOver
17850 this.afterDragOver(target, e, id);
17856 * An empty function by default, but provided so that you can perform a custom action
17857 * while the dragged item is over the drop target and optionally cancel the onDragOver.
17858 * @param {Roo.dd.DragDrop} target The drop target
17859 * @param {Event} e The event object
17860 * @param {String} id The id of the dragged element
17861 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17863 beforeDragOver : function(target, e, id){
17868 onDragOut : function(e, id){
17869 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17870 if(this.beforeDragOut(target, e, id) !== false){
17871 if(target.isNotifyTarget){
17872 target.notifyOut(this, e, this.dragData);
17874 this.proxy.reset();
17875 if(this.afterDragOut){
17877 * An empty function by default, but provided so that you can perform a custom action
17878 * after the dragged item is dragged out of the target without dropping.
17879 * @param {Roo.dd.DragDrop} target The drop target
17880 * @param {Event} e The event object
17881 * @param {String} id The id of the dragged element
17882 * @method afterDragOut
17884 this.afterDragOut(target, e, id);
17887 this.cachedTarget = null;
17891 * An empty function by default, but provided so that you can perform a custom action before the dragged
17892 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
17893 * @param {Roo.dd.DragDrop} target The drop target
17894 * @param {Event} e The event object
17895 * @param {String} id The id of the dragged element
17896 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17898 beforeDragOut : function(target, e, id){
17903 onDragDrop : function(e, id){
17904 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17905 if(this.beforeDragDrop(target, e, id) !== false){
17906 if(target.isNotifyTarget){
17907 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
17908 this.onValidDrop(target, e, id);
17910 this.onInvalidDrop(target, e, id);
17913 this.onValidDrop(target, e, id);
17916 if(this.afterDragDrop){
17918 * An empty function by default, but provided so that you can perform a custom action
17919 * after a valid drag drop has occurred by providing an implementation.
17920 * @param {Roo.dd.DragDrop} target The drop target
17921 * @param {Event} e The event object
17922 * @param {String} id The id of the dropped element
17923 * @method afterDragDrop
17925 this.afterDragDrop(target, e, id);
17928 delete this.cachedTarget;
17932 * An empty function by default, but provided so that you can perform a custom action before the dragged
17933 * item is dropped onto the target and optionally cancel the onDragDrop.
17934 * @param {Roo.dd.DragDrop} target The drop target
17935 * @param {Event} e The event object
17936 * @param {String} id The id of the dragged element
17937 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
17939 beforeDragDrop : function(target, e, id){
17944 onValidDrop : function(target, e, id){
17946 if(this.afterValidDrop){
17948 * An empty function by default, but provided so that you can perform a custom action
17949 * after a valid drop has occurred by providing an implementation.
17950 * @param {Object} target The target DD
17951 * @param {Event} e The event object
17952 * @param {String} id The id of the dropped element
17953 * @method afterInvalidDrop
17955 this.afterValidDrop(target, e, id);
17960 getRepairXY : function(e, data){
17961 return this.el.getXY();
17965 onInvalidDrop : function(target, e, id){
17966 this.beforeInvalidDrop(target, e, id);
17967 if(this.cachedTarget){
17968 if(this.cachedTarget.isNotifyTarget){
17969 this.cachedTarget.notifyOut(this, e, this.dragData);
17971 this.cacheTarget = null;
17973 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
17975 if(this.afterInvalidDrop){
17977 * An empty function by default, but provided so that you can perform a custom action
17978 * after an invalid drop has occurred by providing an implementation.
17979 * @param {Event} e The event object
17980 * @param {String} id The id of the dropped element
17981 * @method afterInvalidDrop
17983 this.afterInvalidDrop(e, id);
17988 afterRepair : function(){
17990 this.el.highlight(this.hlColor || "c3daf9");
17992 this.dragging = false;
17996 * An empty function by default, but provided so that you can perform a custom action after an invalid
17997 * drop has occurred.
17998 * @param {Roo.dd.DragDrop} target The drop target
17999 * @param {Event} e The event object
18000 * @param {String} id The id of the dragged element
18001 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18003 beforeInvalidDrop : function(target, e, id){
18008 handleMouseDown : function(e){
18009 if(this.dragging) {
18012 var data = this.getDragData(e);
18013 if(data && this.onBeforeDrag(data, e) !== false){
18014 this.dragData = data;
18016 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18021 * An empty function by default, but provided so that you can perform a custom action before the initial
18022 * drag event begins and optionally cancel it.
18023 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18024 * @param {Event} e The event object
18025 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18027 onBeforeDrag : function(data, e){
18032 * An empty function by default, but provided so that you can perform a custom action once the initial
18033 * drag event has begun. The drag cannot be canceled from this function.
18034 * @param {Number} x The x position of the click on the dragged object
18035 * @param {Number} y The y position of the click on the dragged object
18037 onStartDrag : Roo.emptyFn,
18039 // private - YUI override
18040 startDrag : function(x, y){
18041 this.proxy.reset();
18042 this.dragging = true;
18043 this.proxy.update("");
18044 this.onInitDrag(x, y);
18049 onInitDrag : function(x, y){
18050 var clone = this.el.dom.cloneNode(true);
18051 clone.id = Roo.id(); // prevent duplicate ids
18052 this.proxy.update(clone);
18053 this.onStartDrag(x, y);
18058 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18059 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18061 getProxy : function(){
18066 * Hides the drag source's {@link Roo.dd.StatusProxy}
18068 hideProxy : function(){
18070 this.proxy.reset(true);
18071 this.dragging = false;
18075 triggerCacheRefresh : function(){
18076 Roo.dd.DDM.refreshCache(this.groups);
18079 // private - override to prevent hiding
18080 b4EndDrag: function(e) {
18083 // private - override to prevent moving
18084 endDrag : function(e){
18085 this.onEndDrag(this.dragData, e);
18089 onEndDrag : function(data, e){
18092 // private - pin to cursor
18093 autoOffset : function(x, y) {
18094 this.setDelta(-12, -20);
18098 * Ext JS Library 1.1.1
18099 * Copyright(c) 2006-2007, Ext JS, LLC.
18101 * Originally Released Under LGPL - original licence link has changed is not relivant.
18104 * <script type="text/javascript">
18109 * @class Roo.dd.DropTarget
18110 * @extends Roo.dd.DDTarget
18111 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18112 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18114 * @param {String/HTMLElement/Element} el The container element
18115 * @param {Object} config
18117 Roo.dd.DropTarget = function(el, config){
18118 this.el = Roo.get(el);
18120 Roo.apply(this, config);
18122 if(this.containerScroll){
18123 Roo.dd.ScrollManager.register(this.el);
18126 Roo.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18131 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18133 * @cfg {String} overClass
18134 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18137 * @cfg {String} dropAllowed
18138 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18140 dropAllowed : "x-dd-drop-ok",
18142 * @cfg {String} dropNotAllowed
18143 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18145 dropNotAllowed : "x-dd-drop-nodrop",
18151 isNotifyTarget : true,
18154 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18155 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18156 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18157 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18158 * @param {Event} e The event
18159 * @param {Object} data An object containing arbitrary data supplied by the drag source
18160 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18161 * underlying {@link Roo.dd.StatusProxy} can be updated
18163 notifyEnter : function(dd, e, data){
18164 if(this.overClass){
18165 this.el.addClass(this.overClass);
18167 return this.dropAllowed;
18171 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18172 * This method will be called on every mouse movement while the drag source is over the drop target.
18173 * This default implementation simply returns the dropAllowed config value.
18174 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18175 * @param {Event} e The event
18176 * @param {Object} data An object containing arbitrary data supplied by the drag source
18177 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18178 * underlying {@link Roo.dd.StatusProxy} can be updated
18180 notifyOver : function(dd, e, data){
18181 return this.dropAllowed;
18185 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18186 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18187 * overClass (if any) from the drop element.
18188 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18189 * @param {Event} e The event
18190 * @param {Object} data An object containing arbitrary data supplied by the drag source
18192 notifyOut : function(dd, e, data){
18193 if(this.overClass){
18194 this.el.removeClass(this.overClass);
18199 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18200 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18201 * implementation that does something to process the drop event and returns true so that the drag source's
18202 * repair action does not run.
18203 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18204 * @param {Event} e The event
18205 * @param {Object} data An object containing arbitrary data supplied by the drag source
18206 * @return {Boolean} True if the drop was valid, else false
18208 notifyDrop : function(dd, e, data){
18213 * Ext JS Library 1.1.1
18214 * Copyright(c) 2006-2007, Ext JS, LLC.
18216 * Originally Released Under LGPL - original licence link has changed is not relivant.
18219 * <script type="text/javascript">
18224 * @class Roo.dd.DragZone
18225 * @extends Roo.dd.DragSource
18226 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18227 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18229 * @param {String/HTMLElement/Element} el The container element
18230 * @param {Object} config
18232 Roo.dd.DragZone = function(el, config){
18233 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18234 if(this.containerScroll){
18235 Roo.dd.ScrollManager.register(this.el);
18239 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18241 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18242 * for auto scrolling during drag operations.
18245 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18246 * method after a failed drop (defaults to "c3daf9" - light blue)
18250 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18251 * for a valid target to drag based on the mouse down. Override this method
18252 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18253 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18254 * @param {EventObject} e The mouse down event
18255 * @return {Object} The dragData
18257 getDragData : function(e){
18258 return Roo.dd.Registry.getHandleFromEvent(e);
18262 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18263 * this.dragData.ddel
18264 * @param {Number} x The x position of the click on the dragged object
18265 * @param {Number} y The y position of the click on the dragged object
18266 * @return {Boolean} true to continue the drag, false to cancel
18268 onInitDrag : function(x, y){
18269 this.proxy.update(this.dragData.ddel.cloneNode(true));
18270 this.onStartDrag(x, y);
18275 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18277 afterRepair : function(){
18279 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18281 this.dragging = false;
18285 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18286 * the XY of this.dragData.ddel
18287 * @param {EventObject} e The mouse up event
18288 * @return {Array} The xy location (e.g. [100, 200])
18290 getRepairXY : function(e){
18291 return Roo.Element.fly(this.dragData.ddel).getXY();
18295 * Ext JS Library 1.1.1
18296 * Copyright(c) 2006-2007, Ext JS, LLC.
18298 * Originally Released Under LGPL - original licence link has changed is not relivant.
18301 * <script type="text/javascript">
18304 * @class Roo.dd.DropZone
18305 * @extends Roo.dd.DropTarget
18306 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18307 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18309 * @param {String/HTMLElement/Element} el The container element
18310 * @param {Object} config
18312 Roo.dd.DropZone = function(el, config){
18313 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18316 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18318 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18319 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18320 * provide your own custom lookup.
18321 * @param {Event} e The event
18322 * @return {Object} data The custom data
18324 getTargetFromEvent : function(e){
18325 return Roo.dd.Registry.getTargetFromEvent(e);
18329 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18330 * that it has registered. This method has no default implementation and should be overridden to provide
18331 * node-specific processing if necessary.
18332 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18333 * {@link #getTargetFromEvent} for this node)
18334 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18335 * @param {Event} e The event
18336 * @param {Object} data An object containing arbitrary data supplied by the drag source
18338 onNodeEnter : function(n, dd, e, data){
18343 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18344 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18345 * overridden to provide the proper feedback.
18346 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18347 * {@link #getTargetFromEvent} for this node)
18348 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18349 * @param {Event} e The event
18350 * @param {Object} data An object containing arbitrary data supplied by the drag source
18351 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18352 * underlying {@link Roo.dd.StatusProxy} can be updated
18354 onNodeOver : function(n, dd, e, data){
18355 return this.dropAllowed;
18359 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18360 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18361 * node-specific processing if necessary.
18362 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18363 * {@link #getTargetFromEvent} for this node)
18364 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18365 * @param {Event} e The event
18366 * @param {Object} data An object containing arbitrary data supplied by the drag source
18368 onNodeOut : function(n, dd, e, data){
18373 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18374 * the drop node. The default implementation returns false, so it should be overridden to provide the
18375 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18376 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18377 * {@link #getTargetFromEvent} for this node)
18378 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18379 * @param {Event} e The event
18380 * @param {Object} data An object containing arbitrary data supplied by the drag source
18381 * @return {Boolean} True if the drop was valid, else false
18383 onNodeDrop : function(n, dd, e, data){
18388 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18389 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18390 * it should be overridden to provide the proper feedback if necessary.
18391 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18392 * @param {Event} e The event
18393 * @param {Object} data An object containing arbitrary data supplied by the drag source
18394 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18395 * underlying {@link Roo.dd.StatusProxy} can be updated
18397 onContainerOver : function(dd, e, data){
18398 return this.dropNotAllowed;
18402 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18403 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18404 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18405 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18406 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18407 * @param {Event} e The event
18408 * @param {Object} data An object containing arbitrary data supplied by the drag source
18409 * @return {Boolean} True if the drop was valid, else false
18411 onContainerDrop : function(dd, e, data){
18416 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18417 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18418 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18419 * you should override this method and provide a custom implementation.
18420 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18421 * @param {Event} e The event
18422 * @param {Object} data An object containing arbitrary data supplied by the drag source
18423 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18424 * underlying {@link Roo.dd.StatusProxy} can be updated
18426 notifyEnter : function(dd, e, data){
18427 return this.dropNotAllowed;
18431 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18432 * This method will be called on every mouse movement while the drag source is over the drop zone.
18433 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18434 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18435 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18436 * registered node, it will call {@link #onContainerOver}.
18437 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18438 * @param {Event} e The event
18439 * @param {Object} data An object containing arbitrary data supplied by the drag source
18440 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18441 * underlying {@link Roo.dd.StatusProxy} can be updated
18443 notifyOver : function(dd, e, data){
18444 var n = this.getTargetFromEvent(e);
18445 if(!n){ // not over valid drop target
18446 if(this.lastOverNode){
18447 this.onNodeOut(this.lastOverNode, dd, e, data);
18448 this.lastOverNode = null;
18450 return this.onContainerOver(dd, e, data);
18452 if(this.lastOverNode != n){
18453 if(this.lastOverNode){
18454 this.onNodeOut(this.lastOverNode, dd, e, data);
18456 this.onNodeEnter(n, dd, e, data);
18457 this.lastOverNode = n;
18459 return this.onNodeOver(n, dd, e, data);
18463 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18464 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18465 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18466 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18467 * @param {Event} e The event
18468 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18470 notifyOut : function(dd, e, data){
18471 if(this.lastOverNode){
18472 this.onNodeOut(this.lastOverNode, dd, e, data);
18473 this.lastOverNode = null;
18478 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18479 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18480 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18481 * otherwise it will call {@link #onContainerDrop}.
18482 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18483 * @param {Event} e The event
18484 * @param {Object} data An object containing arbitrary data supplied by the drag source
18485 * @return {Boolean} True if the drop was valid, else false
18487 notifyDrop : function(dd, e, data){
18488 if(this.lastOverNode){
18489 this.onNodeOut(this.lastOverNode, dd, e, data);
18490 this.lastOverNode = null;
18492 var n = this.getTargetFromEvent(e);
18494 this.onNodeDrop(n, dd, e, data) :
18495 this.onContainerDrop(dd, e, data);
18499 triggerCacheRefresh : function(){
18500 Roo.dd.DDM.refreshCache(this.groups);
18504 * Ext JS Library 1.1.1
18505 * Copyright(c) 2006-2007, Ext JS, LLC.
18507 * Originally Released Under LGPL - original licence link has changed is not relivant.
18510 * <script type="text/javascript">
18515 * @class Roo.data.SortTypes
18517 * Defines the default sorting (casting?) comparison functions used when sorting data.
18519 Roo.data.SortTypes = {
18521 * Default sort that does nothing
18522 * @param {Mixed} s The value being converted
18523 * @return {Mixed} The comparison value
18525 none : function(s){
18530 * The regular expression used to strip tags
18534 stripTagsRE : /<\/?[^>]+>/gi,
18537 * Strips all HTML tags to sort on text only
18538 * @param {Mixed} s The value being converted
18539 * @return {String} The comparison value
18541 asText : function(s){
18542 return String(s).replace(this.stripTagsRE, "");
18546 * Strips all HTML tags to sort on text only - Case insensitive
18547 * @param {Mixed} s The value being converted
18548 * @return {String} The comparison value
18550 asUCText : function(s){
18551 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18555 * Case insensitive string
18556 * @param {Mixed} s The value being converted
18557 * @return {String} The comparison value
18559 asUCString : function(s) {
18560 return String(s).toUpperCase();
18565 * @param {Mixed} s The value being converted
18566 * @return {Number} The comparison value
18568 asDate : function(s) {
18572 if(s instanceof Date){
18573 return s.getTime();
18575 return Date.parse(String(s));
18580 * @param {Mixed} s The value being converted
18581 * @return {Float} The comparison value
18583 asFloat : function(s) {
18584 var val = parseFloat(String(s).replace(/,/g, ""));
18585 if(isNaN(val)) val = 0;
18591 * @param {Mixed} s The value being converted
18592 * @return {Number} The comparison value
18594 asInt : function(s) {
18595 var val = parseInt(String(s).replace(/,/g, ""));
18596 if(isNaN(val)) val = 0;
18601 * Ext JS Library 1.1.1
18602 * Copyright(c) 2006-2007, Ext JS, LLC.
18604 * Originally Released Under LGPL - original licence link has changed is not relivant.
18607 * <script type="text/javascript">
18611 * @class Roo.data.Record
18612 * Instances of this class encapsulate both record <em>definition</em> information, and record
18613 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18614 * to access Records cached in an {@link Roo.data.Store} object.<br>
18616 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18617 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18620 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18622 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18623 * {@link #create}. The parameters are the same.
18624 * @param {Array} data An associative Array of data values keyed by the field name.
18625 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18626 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18627 * not specified an integer id is generated.
18629 Roo.data.Record = function(data, id){
18630 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18635 * Generate a constructor for a specific record layout.
18636 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18637 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18638 * Each field definition object may contain the following properties: <ul>
18639 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
18640 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18641 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18642 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18643 * is being used, then this is a string containing the javascript expression to reference the data relative to
18644 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18645 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18646 * this may be omitted.</p></li>
18647 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18648 * <ul><li>auto (Default, implies no conversion)</li>
18653 * <li>date</li></ul></p></li>
18654 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18655 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18656 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18657 * by the Reader into an object that will be stored in the Record. It is passed the
18658 * following parameters:<ul>
18659 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18661 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18663 * <br>usage:<br><pre><code>
18664 var TopicRecord = Roo.data.Record.create(
18665 {name: 'title', mapping: 'topic_title'},
18666 {name: 'author', mapping: 'username'},
18667 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18668 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18669 {name: 'lastPoster', mapping: 'user2'},
18670 {name: 'excerpt', mapping: 'post_text'}
18673 var myNewRecord = new TopicRecord({
18674 title: 'Do my job please',
18677 lastPost: new Date(),
18678 lastPoster: 'Animal',
18679 excerpt: 'No way dude!'
18681 myStore.add(myNewRecord);
18686 Roo.data.Record.create = function(o){
18687 var f = function(){
18688 f.superclass.constructor.apply(this, arguments);
18690 Roo.extend(f, Roo.data.Record);
18691 var p = f.prototype;
18692 p.fields = new Roo.util.MixedCollection(false, function(field){
18695 for(var i = 0, len = o.length; i < len; i++){
18696 p.fields.add(new Roo.data.Field(o[i]));
18698 f.getField = function(name){
18699 return p.fields.get(name);
18704 Roo.data.Record.AUTO_ID = 1000;
18705 Roo.data.Record.EDIT = 'edit';
18706 Roo.data.Record.REJECT = 'reject';
18707 Roo.data.Record.COMMIT = 'commit';
18709 Roo.data.Record.prototype = {
18711 * Readonly flag - true if this record has been modified.
18720 join : function(store){
18721 this.store = store;
18725 * Set the named field to the specified value.
18726 * @param {String} name The name of the field to set.
18727 * @param {Object} value The value to set the field to.
18729 set : function(name, value){
18730 if(this.data[name] == value){
18734 if(!this.modified){
18735 this.modified = {};
18737 if(typeof this.modified[name] == 'undefined'){
18738 this.modified[name] = this.data[name];
18740 this.data[name] = value;
18742 this.store.afterEdit(this);
18747 * Get the value of the named field.
18748 * @param {String} name The name of the field to get the value of.
18749 * @return {Object} The value of the field.
18751 get : function(name){
18752 return this.data[name];
18756 beginEdit : function(){
18757 this.editing = true;
18758 this.modified = {};
18762 cancelEdit : function(){
18763 this.editing = false;
18764 delete this.modified;
18768 endEdit : function(){
18769 this.editing = false;
18770 if(this.dirty && this.store){
18771 this.store.afterEdit(this);
18776 * Usually called by the {@link Roo.data.Store} which owns the Record.
18777 * Rejects all changes made to the Record since either creation, or the last commit operation.
18778 * Modified fields are reverted to their original values.
18780 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18781 * of reject operations.
18783 reject : function(){
18784 var m = this.modified;
18786 if(typeof m[n] != "function"){
18787 this.data[n] = m[n];
18790 this.dirty = false;
18791 delete this.modified;
18792 this.editing = false;
18794 this.store.afterReject(this);
18799 * Usually called by the {@link Roo.data.Store} which owns the Record.
18800 * Commits all changes made to the Record since either creation, or the last commit operation.
18802 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18803 * of commit operations.
18805 commit : function(){
18806 this.dirty = false;
18807 delete this.modified;
18808 this.editing = false;
18810 this.store.afterCommit(this);
18815 hasError : function(){
18816 return this.error != null;
18820 clearError : function(){
18825 * Creates a copy of this record.
18826 * @param {String} id (optional) A new record id if you don't want to use this record's id
18829 copy : function(newId) {
18830 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
18834 * Ext JS Library 1.1.1
18835 * Copyright(c) 2006-2007, Ext JS, LLC.
18837 * Originally Released Under LGPL - original licence link has changed is not relivant.
18840 * <script type="text/javascript">
18846 * @class Roo.data.Store
18847 * @extends Roo.util.Observable
18848 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
18849 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
18851 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
18852 * has no knowledge of the format of the data returned by the Proxy.<br>
18854 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
18855 * instances from the data object. These records are cached and made available through accessor functions.
18857 * Creates a new Store.
18858 * @param {Object} config A config object containing the objects needed for the Store to access data,
18859 * and read the data into Records.
18861 Roo.data.Store = function(config){
18862 this.data = new Roo.util.MixedCollection(false);
18863 this.data.getKey = function(o){
18866 this.baseParams = {};
18868 this.paramNames = {
18875 if(config && config.data){
18876 this.inlineData = config.data;
18877 delete config.data;
18880 Roo.apply(this, config);
18882 if(this.reader){ // reader passed
18883 this.reader = Roo.factory(this.reader, Roo.data);
18884 this.reader.xmodule = this.xmodule || false;
18885 if(!this.recordType){
18886 this.recordType = this.reader.recordType;
18888 if(this.reader.onMetaChange){
18889 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
18893 if(this.recordType){
18894 this.fields = this.recordType.prototype.fields;
18896 this.modified = [];
18900 * @event datachanged
18901 * Fires when the data cache has changed, and a widget which is using this Store
18902 * as a Record cache should refresh its view.
18903 * @param {Store} this
18905 datachanged : true,
18907 * @event metachange
18908 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
18909 * @param {Store} this
18910 * @param {Object} meta The JSON metadata
18915 * Fires when Records have been added to the Store
18916 * @param {Store} this
18917 * @param {Roo.data.Record[]} records The array of Records added
18918 * @param {Number} index The index at which the record(s) were added
18923 * Fires when a Record has been removed from the Store
18924 * @param {Store} this
18925 * @param {Roo.data.Record} record The Record that was removed
18926 * @param {Number} index The index at which the record was removed
18931 * Fires when a Record has been updated
18932 * @param {Store} this
18933 * @param {Roo.data.Record} record The Record that was updated
18934 * @param {String} operation The update operation being performed. Value may be one of:
18936 Roo.data.Record.EDIT
18937 Roo.data.Record.REJECT
18938 Roo.data.Record.COMMIT
18944 * Fires when the data cache has been cleared.
18945 * @param {Store} this
18949 * @event beforeload
18950 * Fires before a request is made for a new data object. If the beforeload handler returns false
18951 * the load action will be canceled.
18952 * @param {Store} this
18953 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18958 * Fires after a new set of Records has been loaded.
18959 * @param {Store} this
18960 * @param {Roo.data.Record[]} records The Records that were loaded
18961 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18965 * @event loadexception
18966 * Fires if an exception occurs in the Proxy during loading.
18967 * Called with the signature of the Proxy's "loadexception" event.
18968 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
18971 * @param {Object} return from JsonData.reader() - success, totalRecords, records
18972 * @param {Object} load options
18973 * @param {Object} jsonData from your request (normally this contains the Exception)
18975 loadexception : true
18979 this.proxy = Roo.factory(this.proxy, Roo.data);
18980 this.proxy.xmodule = this.xmodule || false;
18981 this.relayEvents(this.proxy, ["loadexception"]);
18983 this.sortToggle = {};
18985 Roo.data.Store.superclass.constructor.call(this);
18987 if(this.inlineData){
18988 this.loadData(this.inlineData);
18989 delete this.inlineData;
18992 Roo.extend(Roo.data.Store, Roo.util.Observable, {
18994 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
18995 * without a remote query - used by combo/forms at present.
18999 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19002 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19005 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19006 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19009 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19010 * on any HTTP request
19013 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19016 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19017 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19019 remoteSort : false,
19022 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19023 * loaded or when a record is removed. (defaults to false).
19025 pruneModifiedRecords : false,
19028 lastOptions : null,
19031 * Add Records to the Store and fires the add event.
19032 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19034 add : function(records){
19035 records = [].concat(records);
19036 for(var i = 0, len = records.length; i < len; i++){
19037 records[i].join(this);
19039 var index = this.data.length;
19040 this.data.addAll(records);
19041 this.fireEvent("add", this, records, index);
19045 * Remove a Record from the Store and fires the remove event.
19046 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19048 remove : function(record){
19049 var index = this.data.indexOf(record);
19050 this.data.removeAt(index);
19051 if(this.pruneModifiedRecords){
19052 this.modified.remove(record);
19054 this.fireEvent("remove", this, record, index);
19058 * Remove all Records from the Store and fires the clear event.
19060 removeAll : function(){
19062 if(this.pruneModifiedRecords){
19063 this.modified = [];
19065 this.fireEvent("clear", this);
19069 * Inserts Records to the Store at the given index and fires the add event.
19070 * @param {Number} index The start index at which to insert the passed Records.
19071 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19073 insert : function(index, records){
19074 records = [].concat(records);
19075 for(var i = 0, len = records.length; i < len; i++){
19076 this.data.insert(index, records[i]);
19077 records[i].join(this);
19079 this.fireEvent("add", this, records, index);
19083 * Get the index within the cache of the passed Record.
19084 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19085 * @return {Number} The index of the passed Record. Returns -1 if not found.
19087 indexOf : function(record){
19088 return this.data.indexOf(record);
19092 * Get the index within the cache of the Record with the passed id.
19093 * @param {String} id The id of the Record to find.
19094 * @return {Number} The index of the Record. Returns -1 if not found.
19096 indexOfId : function(id){
19097 return this.data.indexOfKey(id);
19101 * Get the Record with the specified id.
19102 * @param {String} id The id of the Record to find.
19103 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19105 getById : function(id){
19106 return this.data.key(id);
19110 * Get the Record at the specified index.
19111 * @param {Number} index The index of the Record to find.
19112 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19114 getAt : function(index){
19115 return this.data.itemAt(index);
19119 * Returns a range of Records between specified indices.
19120 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19121 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19122 * @return {Roo.data.Record[]} An array of Records
19124 getRange : function(start, end){
19125 return this.data.getRange(start, end);
19129 storeOptions : function(o){
19130 o = Roo.apply({}, o);
19133 this.lastOptions = o;
19137 * Loads the Record cache from the configured Proxy using the configured Reader.
19139 * If using remote paging, then the first load call must specify the <em>start</em>
19140 * and <em>limit</em> properties in the options.params property to establish the initial
19141 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19143 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19144 * and this call will return before the new data has been loaded. Perform any post-processing
19145 * in a callback function, or in a "load" event handler.</strong>
19147 * @param {Object} options An object containing properties which control loading options:<ul>
19148 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19149 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19150 * passed the following arguments:<ul>
19151 * <li>r : Roo.data.Record[]</li>
19152 * <li>options: Options object from the load call</li>
19153 * <li>success: Boolean success indicator</li></ul></li>
19154 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19155 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19158 load : function(options){
19159 options = options || {};
19160 if(this.fireEvent("beforeload", this, options) !== false){
19161 this.storeOptions(options);
19162 var p = Roo.apply(options.params || {}, this.baseParams);
19163 if(this.sortInfo && this.remoteSort){
19164 var pn = this.paramNames;
19165 p[pn["sort"]] = this.sortInfo.field;
19166 p[pn["dir"]] = this.sortInfo.direction;
19168 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19173 * Reloads the Record cache from the configured Proxy using the configured Reader and
19174 * the options from the last load operation performed.
19175 * @param {Object} options (optional) An object containing properties which may override the options
19176 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19177 * the most recently used options are reused).
19179 reload : function(options){
19180 this.load(Roo.applyIf(options||{}, this.lastOptions));
19184 // Called as a callback by the Reader during a load operation.
19185 loadRecords : function(o, options, success){
19186 if(!o || success === false){
19187 if(success !== false){
19188 this.fireEvent("load", this, [], options);
19190 if(options.callback){
19191 options.callback.call(options.scope || this, [], options, false);
19195 // if data returned failure - throw an exception.
19196 if (o.success === false) {
19197 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19200 var r = o.records, t = o.totalRecords || r.length;
19201 if(!options || options.add !== true){
19202 if(this.pruneModifiedRecords){
19203 this.modified = [];
19205 for(var i = 0, len = r.length; i < len; i++){
19209 this.data = this.snapshot;
19210 delete this.snapshot;
19213 this.data.addAll(r);
19214 this.totalLength = t;
19216 this.fireEvent("datachanged", this);
19218 this.totalLength = Math.max(t, this.data.length+r.length);
19221 this.fireEvent("load", this, r, options);
19222 if(options.callback){
19223 options.callback.call(options.scope || this, r, options, true);
19228 * Loads data from a passed data block. A Reader which understands the format of the data
19229 * must have been configured in the constructor.
19230 * @param {Object} data The data block from which to read the Records. The format of the data expected
19231 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19232 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19234 loadData : function(o, append){
19235 var r = this.reader.readRecords(o);
19236 this.loadRecords(r, {add: append}, true);
19240 * Gets the number of cached records.
19242 * <em>If using paging, this may not be the total size of the dataset. If the data object
19243 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19244 * the data set size</em>
19246 getCount : function(){
19247 return this.data.length || 0;
19251 * Gets the total number of records in the dataset as returned by the server.
19253 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19254 * the dataset size</em>
19256 getTotalCount : function(){
19257 return this.totalLength || 0;
19261 * Returns the sort state of the Store as an object with two properties:
19263 field {String} The name of the field by which the Records are sorted
19264 direction {String} The sort order, "ASC" or "DESC"
19267 getSortState : function(){
19268 return this.sortInfo;
19272 applySort : function(){
19273 if(this.sortInfo && !this.remoteSort){
19274 var s = this.sortInfo, f = s.field;
19275 var st = this.fields.get(f).sortType;
19276 var fn = function(r1, r2){
19277 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19278 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19280 this.data.sort(s.direction, fn);
19281 if(this.snapshot && this.snapshot != this.data){
19282 this.snapshot.sort(s.direction, fn);
19288 * Sets the default sort column and order to be used by the next load operation.
19289 * @param {String} fieldName The name of the field to sort by.
19290 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19292 setDefaultSort : function(field, dir){
19293 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19297 * Sort the Records.
19298 * If remote sorting is used, the sort is performed on the server, and the cache is
19299 * reloaded. If local sorting is used, the cache is sorted internally.
19300 * @param {String} fieldName The name of the field to sort by.
19301 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19303 sort : function(fieldName, dir){
19304 var f = this.fields.get(fieldName);
19306 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19307 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19312 this.sortToggle[f.name] = dir;
19313 this.sortInfo = {field: f.name, direction: dir};
19314 if(!this.remoteSort){
19316 this.fireEvent("datachanged", this);
19318 this.load(this.lastOptions);
19323 * Calls the specified function for each of the Records in the cache.
19324 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19325 * Returning <em>false</em> aborts and exits the iteration.
19326 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19328 each : function(fn, scope){
19329 this.data.each(fn, scope);
19333 * Gets all records modified since the last commit. Modified records are persisted across load operations
19334 * (e.g., during paging).
19335 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19337 getModifiedRecords : function(){
19338 return this.modified;
19342 createFilterFn : function(property, value, anyMatch){
19343 if(!value.exec){ // not a regex
19344 value = String(value);
19345 if(value.length == 0){
19348 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19350 return function(r){
19351 return value.test(r.data[property]);
19356 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19357 * @param {String} property A field on your records
19358 * @param {Number} start The record index to start at (defaults to 0)
19359 * @param {Number} end The last record index to include (defaults to length - 1)
19360 * @return {Number} The sum
19362 sum : function(property, start, end){
19363 var rs = this.data.items, v = 0;
19364 start = start || 0;
19365 end = (end || end === 0) ? end : rs.length-1;
19367 for(var i = start; i <= end; i++){
19368 v += (rs[i].data[property] || 0);
19374 * Filter the records by a specified property.
19375 * @param {String} field A field on your records
19376 * @param {String/RegExp} value Either a string that the field
19377 * should start with or a RegExp to test against the field
19378 * @param {Boolean} anyMatch True to match any part not just the beginning
19380 filter : function(property, value, anyMatch){
19381 var fn = this.createFilterFn(property, value, anyMatch);
19382 return fn ? this.filterBy(fn) : this.clearFilter();
19386 * Filter by a function. The specified function will be called with each
19387 * record in this data source. If the function returns true the record is included,
19388 * otherwise it is filtered.
19389 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19390 * @param {Object} scope (optional) The scope of the function (defaults to this)
19392 filterBy : function(fn, scope){
19393 this.snapshot = this.snapshot || this.data;
19394 this.data = this.queryBy(fn, scope||this);
19395 this.fireEvent("datachanged", this);
19399 * Query the records by a specified property.
19400 * @param {String} field A field on your records
19401 * @param {String/RegExp} value Either a string that the field
19402 * should start with or a RegExp to test against the field
19403 * @param {Boolean} anyMatch True to match any part not just the beginning
19404 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19406 query : function(property, value, anyMatch){
19407 var fn = this.createFilterFn(property, value, anyMatch);
19408 return fn ? this.queryBy(fn) : this.data.clone();
19412 * Query by a function. The specified function will be called with each
19413 * record in this data source. If the function returns true the record is included
19415 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19416 * @param {Object} scope (optional) The scope of the function (defaults to this)
19417 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19419 queryBy : function(fn, scope){
19420 var data = this.snapshot || this.data;
19421 return data.filterBy(fn, scope||this);
19425 * Collects unique values for a particular dataIndex from this store.
19426 * @param {String} dataIndex The property to collect
19427 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19428 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19429 * @return {Array} An array of the unique values
19431 collect : function(dataIndex, allowNull, bypassFilter){
19432 var d = (bypassFilter === true && this.snapshot) ?
19433 this.snapshot.items : this.data.items;
19434 var v, sv, r = [], l = {};
19435 for(var i = 0, len = d.length; i < len; i++){
19436 v = d[i].data[dataIndex];
19438 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19447 * Revert to a view of the Record cache with no filtering applied.
19448 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19450 clearFilter : function(suppressEvent){
19451 if(this.snapshot && this.snapshot != this.data){
19452 this.data = this.snapshot;
19453 delete this.snapshot;
19454 if(suppressEvent !== true){
19455 this.fireEvent("datachanged", this);
19461 afterEdit : function(record){
19462 if(this.modified.indexOf(record) == -1){
19463 this.modified.push(record);
19465 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19469 afterReject : function(record){
19470 this.modified.remove(record);
19471 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19475 afterCommit : function(record){
19476 this.modified.remove(record);
19477 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19481 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19482 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19484 commitChanges : function(){
19485 var m = this.modified.slice(0);
19486 this.modified = [];
19487 for(var i = 0, len = m.length; i < len; i++){
19493 * Cancel outstanding changes on all changed records.
19495 rejectChanges : function(){
19496 var m = this.modified.slice(0);
19497 this.modified = [];
19498 for(var i = 0, len = m.length; i < len; i++){
19503 onMetaChange : function(meta, rtype, o){
19504 this.recordType = rtype;
19505 this.fields = rtype.prototype.fields;
19506 delete this.snapshot;
19507 this.sortInfo = meta.sortInfo;
19508 this.modified = [];
19509 this.fireEvent('metachange', this, this.reader.meta);
19513 * Ext JS Library 1.1.1
19514 * Copyright(c) 2006-2007, Ext JS, LLC.
19516 * Originally Released Under LGPL - original licence link has changed is not relivant.
19519 * <script type="text/javascript">
19523 * @class Roo.data.SimpleStore
19524 * @extends Roo.data.Store
19525 * Small helper class to make creating Stores from Array data easier.
19526 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19527 * @cfg {Array} fields An array of field definition objects, or field name strings.
19528 * @cfg {Array} data The multi-dimensional array of data
19530 * @param {Object} config
19532 Roo.data.SimpleStore = function(config){
19533 Roo.data.SimpleStore.superclass.constructor.call(this, {
19535 reader: new Roo.data.ArrayReader({
19538 Roo.data.Record.create(config.fields)
19540 proxy : new Roo.data.MemoryProxy(config.data)
19544 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19546 * Ext JS Library 1.1.1
19547 * Copyright(c) 2006-2007, Ext JS, LLC.
19549 * Originally Released Under LGPL - original licence link has changed is not relivant.
19552 * <script type="text/javascript">
19557 * @extends Roo.data.Store
19558 * @class Roo.data.JsonStore
19559 * Small helper class to make creating Stores for JSON data easier. <br/>
19561 var store = new Roo.data.JsonStore({
19562 url: 'get-images.php',
19564 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19567 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19568 * JsonReader and HttpProxy (unless inline data is provided).</b>
19569 * @cfg {Array} fields An array of field definition objects, or field name strings.
19571 * @param {Object} config
19573 Roo.data.JsonStore = function(c){
19574 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19575 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19576 reader: new Roo.data.JsonReader(c, c.fields)
19579 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19581 * Ext JS Library 1.1.1
19582 * Copyright(c) 2006-2007, Ext JS, LLC.
19584 * Originally Released Under LGPL - original licence link has changed is not relivant.
19587 * <script type="text/javascript">
19591 Roo.data.Field = function(config){
19592 if(typeof config == "string"){
19593 config = {name: config};
19595 Roo.apply(this, config);
19598 this.type = "auto";
19601 var st = Roo.data.SortTypes;
19602 // named sortTypes are supported, here we look them up
19603 if(typeof this.sortType == "string"){
19604 this.sortType = st[this.sortType];
19607 // set default sortType for strings and dates
19608 if(!this.sortType){
19611 this.sortType = st.asUCString;
19614 this.sortType = st.asDate;
19617 this.sortType = st.none;
19622 var stripRe = /[\$,%]/g;
19624 // prebuilt conversion function for this field, instead of
19625 // switching every time we're reading a value
19627 var cv, dateFormat = this.dateFormat;
19632 cv = function(v){ return v; };
19635 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19639 return v !== undefined && v !== null && v !== '' ?
19640 parseInt(String(v).replace(stripRe, ""), 10) : '';
19645 return v !== undefined && v !== null && v !== '' ?
19646 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19651 cv = function(v){ return v === true || v === "true" || v == 1; };
19658 if(v instanceof Date){
19662 if(dateFormat == "timestamp"){
19663 return new Date(v*1000);
19665 return Date.parseDate(v, dateFormat);
19667 var parsed = Date.parse(v);
19668 return parsed ? new Date(parsed) : null;
19677 Roo.data.Field.prototype = {
19685 * Ext JS Library 1.1.1
19686 * Copyright(c) 2006-2007, Ext JS, LLC.
19688 * Originally Released Under LGPL - original licence link has changed is not relivant.
19691 * <script type="text/javascript">
19694 // Base class for reading structured data from a data source. This class is intended to be
19695 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19698 * @class Roo.data.DataReader
19699 * Base class for reading structured data from a data source. This class is intended to be
19700 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19703 Roo.data.DataReader = function(meta, recordType){
19707 this.recordType = recordType instanceof Array ?
19708 Roo.data.Record.create(recordType) : recordType;
19711 Roo.data.DataReader.prototype = {
19713 * Create an empty record
19714 * @param {Object} data (optional) - overlay some values
19715 * @return {Roo.data.Record} record created.
19717 newRow : function(d) {
19719 this.recordType.prototype.fields.each(function(c) {
19721 case 'int' : da[c.name] = 0; break;
19722 case 'date' : da[c.name] = new Date(); break;
19723 case 'float' : da[c.name] = 0.0; break;
19724 case 'boolean' : da[c.name] = false; break;
19725 default : da[c.name] = ""; break;
19729 return new this.recordType(Roo.apply(da, d));
19734 * Ext JS Library 1.1.1
19735 * Copyright(c) 2006-2007, Ext JS, LLC.
19737 * Originally Released Under LGPL - original licence link has changed is not relivant.
19740 * <script type="text/javascript">
19744 * @class Roo.data.DataProxy
19745 * @extends Roo.data.Observable
19746 * This class is an abstract base class for implementations which provide retrieval of
19747 * unformatted data objects.<br>
19749 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19750 * (of the appropriate type which knows how to parse the data object) to provide a block of
19751 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19753 * Custom implementations must implement the load method as described in
19754 * {@link Roo.data.HttpProxy#load}.
19756 Roo.data.DataProxy = function(){
19759 * @event beforeload
19760 * Fires before a network request is made to retrieve a data object.
19761 * @param {Object} This DataProxy object.
19762 * @param {Object} params The params parameter to the load function.
19767 * Fires before the load method's callback is called.
19768 * @param {Object} This DataProxy object.
19769 * @param {Object} o The data object.
19770 * @param {Object} arg The callback argument object passed to the load function.
19774 * @event loadexception
19775 * Fires if an Exception occurs during data retrieval.
19776 * @param {Object} This DataProxy object.
19777 * @param {Object} o The data object.
19778 * @param {Object} arg The callback argument object passed to the load function.
19779 * @param {Object} e The Exception.
19781 loadexception : true
19783 Roo.data.DataProxy.superclass.constructor.call(this);
19786 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
19789 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
19793 * Ext JS Library 1.1.1
19794 * Copyright(c) 2006-2007, Ext JS, LLC.
19796 * Originally Released Under LGPL - original licence link has changed is not relivant.
19799 * <script type="text/javascript">
19802 * @class Roo.data.MemoryProxy
19803 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
19804 * to the Reader when its load method is called.
19806 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
19808 Roo.data.MemoryProxy = function(data){
19812 Roo.data.MemoryProxy.superclass.constructor.call(this);
19816 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
19818 * Load data from the requested source (in this case an in-memory
19819 * data object passed to the constructor), read the data object into
19820 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
19821 * process that block using the passed callback.
19822 * @param {Object} params This parameter is not used by the MemoryProxy class.
19823 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19824 * object into a block of Roo.data.Records.
19825 * @param {Function} callback The function into which to pass the block of Roo.data.records.
19826 * The function must be passed <ul>
19827 * <li>The Record block object</li>
19828 * <li>The "arg" argument from the load function</li>
19829 * <li>A boolean success indicator</li>
19831 * @param {Object} scope The scope in which to call the callback
19832 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19834 load : function(params, reader, callback, scope, arg){
19835 params = params || {};
19838 result = reader.readRecords(this.data);
19840 this.fireEvent("loadexception", this, arg, null, e);
19841 callback.call(scope, null, arg, false);
19844 callback.call(scope, result, arg, true);
19848 update : function(params, records){
19853 * Ext JS Library 1.1.1
19854 * Copyright(c) 2006-2007, Ext JS, LLC.
19856 * Originally Released Under LGPL - original licence link has changed is not relivant.
19859 * <script type="text/javascript">
19862 * @class Roo.data.HttpProxy
19863 * @extends Roo.data.DataProxy
19864 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
19865 * configured to reference a certain URL.<br><br>
19867 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
19868 * from which the running page was served.<br><br>
19870 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
19872 * Be aware that to enable the browser to parse an XML document, the server must set
19873 * the Content-Type header in the HTTP response to "text/xml".
19875 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
19876 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
19877 * will be used to make the request.
19879 Roo.data.HttpProxy = function(conn){
19880 Roo.data.HttpProxy.superclass.constructor.call(this);
19881 // is conn a conn config or a real conn?
19883 this.useAjax = !conn || !conn.events;
19887 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
19888 // thse are take from connection...
19891 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
19894 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
19895 * extra parameters to each request made by this object. (defaults to undefined)
19898 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
19899 * to each request made by this object. (defaults to undefined)
19902 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
19905 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
19908 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
19914 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
19918 * Return the {@link Roo.data.Connection} object being used by this Proxy.
19919 * @return {Connection} The Connection object. This object may be used to subscribe to events on
19920 * a finer-grained basis than the DataProxy events.
19922 getConnection : function(){
19923 return this.useAjax ? Roo.Ajax : this.conn;
19927 * Load data from the configured {@link Roo.data.Connection}, read the data object into
19928 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
19929 * process that block using the passed callback.
19930 * @param {Object} params An object containing properties which are to be used as HTTP parameters
19931 * for the request to the remote server.
19932 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19933 * object into a block of Roo.data.Records.
19934 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
19935 * The function must be passed <ul>
19936 * <li>The Record block object</li>
19937 * <li>The "arg" argument from the load function</li>
19938 * <li>A boolean success indicator</li>
19940 * @param {Object} scope The scope in which to call the callback
19941 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19943 load : function(params, reader, callback, scope, arg){
19944 if(this.fireEvent("beforeload", this, params) !== false){
19946 params : params || {},
19948 callback : callback,
19953 callback : this.loadResponse,
19957 Roo.applyIf(o, this.conn);
19958 if(this.activeRequest){
19959 Roo.Ajax.abort(this.activeRequest);
19961 this.activeRequest = Roo.Ajax.request(o);
19963 this.conn.request(o);
19966 callback.call(scope||this, null, arg, false);
19971 loadResponse : function(o, success, response){
19972 delete this.activeRequest;
19974 this.fireEvent("loadexception", this, o, response);
19975 o.request.callback.call(o.request.scope, null, o.request.arg, false);
19980 result = o.reader.read(response);
19982 this.fireEvent("loadexception", this, o, response, e);
19983 o.request.callback.call(o.request.scope, null, o.request.arg, false);
19987 this.fireEvent("load", this, o, o.request.arg);
19988 o.request.callback.call(o.request.scope, result, o.request.arg, true);
19992 update : function(dataSet){
19997 updateResponse : function(dataSet){
20002 * Ext JS Library 1.1.1
20003 * Copyright(c) 2006-2007, Ext JS, LLC.
20005 * Originally Released Under LGPL - original licence link has changed is not relivant.
20008 * <script type="text/javascript">
20012 * @class Roo.data.ScriptTagProxy
20013 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20014 * other than the originating domain of the running page.<br><br>
20016 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
20017 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20019 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20020 * source code that is used as the source inside a <script> tag.<br><br>
20022 * In order for the browser to process the returned data, the server must wrap the data object
20023 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20024 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20025 * depending on whether the callback name was passed:
20028 boolean scriptTag = false;
20029 String cb = request.getParameter("callback");
20032 response.setContentType("text/javascript");
20034 response.setContentType("application/x-json");
20036 Writer out = response.getWriter();
20038 out.write(cb + "(");
20040 out.print(dataBlock.toJsonString());
20047 * @param {Object} config A configuration object.
20049 Roo.data.ScriptTagProxy = function(config){
20050 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20051 Roo.apply(this, config);
20052 this.head = document.getElementsByTagName("head")[0];
20055 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20057 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20059 * @cfg {String} url The URL from which to request the data object.
20062 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20066 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20067 * the server the name of the callback function set up by the load call to process the returned data object.
20068 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20069 * javascript output which calls this named function passing the data object as its only parameter.
20071 callbackParam : "callback",
20073 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20074 * name to the request.
20079 * Load data from the configured URL, read the data object into
20080 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20081 * process that block using the passed callback.
20082 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20083 * for the request to the remote server.
20084 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20085 * object into a block of Roo.data.Records.
20086 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20087 * The function must be passed <ul>
20088 * <li>The Record block object</li>
20089 * <li>The "arg" argument from the load function</li>
20090 * <li>A boolean success indicator</li>
20092 * @param {Object} scope The scope in which to call the callback
20093 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20095 load : function(params, reader, callback, scope, arg){
20096 if(this.fireEvent("beforeload", this, params) !== false){
20098 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20100 var url = this.url;
20101 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20103 url += "&_dc=" + (new Date().getTime());
20105 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20108 cb : "stcCallback"+transId,
20109 scriptId : "stcScript"+transId,
20113 callback : callback,
20119 window[trans.cb] = function(o){
20120 conn.handleResponse(o, trans);
20123 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20125 if(this.autoAbort !== false){
20129 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20131 var script = document.createElement("script");
20132 script.setAttribute("src", url);
20133 script.setAttribute("type", "text/javascript");
20134 script.setAttribute("id", trans.scriptId);
20135 this.head.appendChild(script);
20137 this.trans = trans;
20139 callback.call(scope||this, null, arg, false);
20144 isLoading : function(){
20145 return this.trans ? true : false;
20149 * Abort the current server request.
20151 abort : function(){
20152 if(this.isLoading()){
20153 this.destroyTrans(this.trans);
20158 destroyTrans : function(trans, isLoaded){
20159 this.head.removeChild(document.getElementById(trans.scriptId));
20160 clearTimeout(trans.timeoutId);
20162 window[trans.cb] = undefined;
20164 delete window[trans.cb];
20167 // if hasn't been loaded, wait for load to remove it to prevent script error
20168 window[trans.cb] = function(){
20169 window[trans.cb] = undefined;
20171 delete window[trans.cb];
20178 handleResponse : function(o, trans){
20179 this.trans = false;
20180 this.destroyTrans(trans, true);
20183 result = trans.reader.readRecords(o);
20185 this.fireEvent("loadexception", this, o, trans.arg, e);
20186 trans.callback.call(trans.scope||window, null, trans.arg, false);
20189 this.fireEvent("load", this, o, trans.arg);
20190 trans.callback.call(trans.scope||window, result, trans.arg, true);
20194 handleFailure : function(trans){
20195 this.trans = false;
20196 this.destroyTrans(trans, false);
20197 this.fireEvent("loadexception", this, null, trans.arg);
20198 trans.callback.call(trans.scope||window, null, trans.arg, false);
20202 * Ext JS Library 1.1.1
20203 * Copyright(c) 2006-2007, Ext JS, LLC.
20205 * Originally Released Under LGPL - original licence link has changed is not relivant.
20208 * <script type="text/javascript">
20212 * @class Roo.data.JsonReader
20213 * @extends Roo.data.DataReader
20214 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20215 * based on mappings in a provided Roo.data.Record constructor.
20219 var RecordDef = Roo.data.Record.create([
20220 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20221 {name: 'occupation'} // This field will use "occupation" as the mapping.
20223 var myReader = new Roo.data.JsonReader({
20224 totalProperty: "results", // The property which contains the total dataset size (optional)
20225 root: "rows", // The property which contains an Array of row objects
20226 id: "id" // The property within each row object that provides an ID for the record (optional)
20230 * This would consume a JSON file like this:
20232 { 'results': 2, 'rows': [
20233 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20234 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20237 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20238 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20239 * paged from the remote server.
20240 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20241 * @cfg {String} root name of the property which contains the Array of row objects.
20242 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20244 * Create a new JsonReader
20245 * @param {Object} meta Metadata configuration options
20246 * @param {Object} recordType Either an Array of field definition objects,
20247 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20249 Roo.data.JsonReader = function(meta, recordType){
20252 // set some defaults:
20253 Roo.applyIf(meta, {
20254 totalProperty: 'total',
20255 successProperty : 'success',
20260 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20262 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20264 * This method is only used by a DataProxy which has retrieved data from a remote server.
20265 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20266 * @return {Object} data A data block which is used by an Roo.data.Store object as
20267 * a cache of Roo.data.Records.
20269 read : function(response){
20270 var json = response.responseText;
20272 var o = eval("("+json+")");
20274 throw {message: "JsonReader.read: Json object not found"};
20279 this.meta = o.metaData;
20280 this.recordType = Roo.data.Record.create(o.metaData.fields);
20281 this.onMetaChange(this.meta, this.recordType, o);
20283 return this.readRecords(o);
20286 // private function a store will implement
20287 onMetaChange : function(meta, recordType, o){
20294 simpleAccess: function(obj, subsc) {
20301 getJsonAccessor: function(){
20303 return function(expr) {
20305 return(re.test(expr))
20306 ? new Function("obj", "return obj." + expr)
20311 return Roo.emptyFn;
20316 * Create a data block containing Roo.data.Records from an XML document.
20317 * @param {Object} o An object which contains an Array of row objects in the property specified
20318 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20319 * which contains the total size of the dataset.
20320 * @return {Object} data A data block which is used by an Roo.data.Store object as
20321 * a cache of Roo.data.Records.
20323 readRecords : function(o){
20325 * After any data loads, the raw JSON data is available for further custom processing.
20329 var s = this.meta, Record = this.recordType,
20330 f = Record.prototype.fields, fi = f.items, fl = f.length;
20332 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20334 if(s.totalProperty) {
20335 this.getTotal = this.getJsonAccessor(s.totalProperty);
20337 if(s.successProperty) {
20338 this.getSuccess = this.getJsonAccessor(s.successProperty);
20340 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20342 var g = this.getJsonAccessor(s.id);
20343 this.getId = function(rec) {
20345 return (r === undefined || r === "") ? null : r;
20348 this.getId = function(){return null;};
20351 for(var i = 0; i < fl; i++){
20353 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20354 this.ef[i] = this.getJsonAccessor(map);
20358 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20359 if(s.totalProperty){
20360 var v = parseInt(this.getTotal(o), 10);
20365 if(s.successProperty){
20366 var v = this.getSuccess(o);
20367 if(v === false || v === 'false'){
20372 for(var i = 0; i < c; i++){
20375 var id = this.getId(n);
20376 for(var j = 0; j < fl; j++){
20378 var v = this.ef[j](n);
20379 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20381 var record = new Record(values, id);
20383 records[i] = record;
20388 totalRecords : totalRecords
20393 * Ext JS Library 1.1.1
20394 * Copyright(c) 2006-2007, Ext JS, LLC.
20396 * Originally Released Under LGPL - original licence link has changed is not relivant.
20399 * <script type="text/javascript">
20403 * @class Roo.data.XmlReader
20404 * @extends Roo.data.DataReader
20405 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20406 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20408 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20409 * header in the HTTP response must be set to "text/xml".</em>
20413 var RecordDef = Roo.data.Record.create([
20414 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20415 {name: 'occupation'} // This field will use "occupation" as the mapping.
20417 var myReader = new Roo.data.XmlReader({
20418 totalRecords: "results", // The element which contains the total dataset size (optional)
20419 record: "row", // The repeated element which contains row information
20420 id: "id" // The element within the row that provides an ID for the record (optional)
20424 * This would consume an XML file like this:
20428 <results>2</results>
20431 <name>Bill</name>
20432 <occupation>Gardener</occupation>
20436 <name>Ben</name>
20437 <occupation>Horticulturalist</occupation>
20441 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20442 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20443 * paged from the remote server.
20444 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20445 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20446 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20447 * a record identifier value.
20449 * Create a new XmlReader
20450 * @param {Object} meta Metadata configuration options
20451 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20452 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20453 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20455 Roo.data.XmlReader = function(meta, recordType){
20457 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20459 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20461 * This method is only used by a DataProxy which has retrieved data from a remote server.
20462 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20463 * to contain a method called 'responseXML' that returns an XML document object.
20464 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20465 * a cache of Roo.data.Records.
20467 read : function(response){
20468 var doc = response.responseXML;
20470 throw {message: "XmlReader.read: XML Document not available"};
20472 return this.readRecords(doc);
20476 * Create a data block containing Roo.data.Records from an XML document.
20477 * @param {Object} doc A parsed XML document.
20478 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20479 * a cache of Roo.data.Records.
20481 readRecords : function(doc){
20483 * After any data loads/reads, the raw XML Document is available for further custom processing.
20484 * @type XMLDocument
20486 this.xmlData = doc;
20487 var root = doc.documentElement || doc;
20488 var q = Roo.DomQuery;
20489 var recordType = this.recordType, fields = recordType.prototype.fields;
20490 var sid = this.meta.id;
20491 var totalRecords = 0, success = true;
20492 if(this.meta.totalRecords){
20493 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20496 if(this.meta.success){
20497 var sv = q.selectValue(this.meta.success, root, true);
20498 success = sv !== false && sv !== 'false';
20501 var ns = q.select(this.meta.record, root);
20502 for(var i = 0, len = ns.length; i < len; i++) {
20505 var id = sid ? q.selectValue(sid, n) : undefined;
20506 for(var j = 0, jlen = fields.length; j < jlen; j++){
20507 var f = fields.items[j];
20508 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20510 values[f.name] = v;
20512 var record = new recordType(values, id);
20514 records[records.length] = record;
20520 totalRecords : totalRecords || records.length
20525 * Ext JS Library 1.1.1
20526 * Copyright(c) 2006-2007, Ext JS, LLC.
20528 * Originally Released Under LGPL - original licence link has changed is not relivant.
20531 * <script type="text/javascript">
20535 * @class Roo.data.ArrayReader
20536 * @extends Roo.data.DataReader
20537 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20538 * Each element of that Array represents a row of data fields. The
20539 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20540 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20544 var RecordDef = Roo.data.Record.create([
20545 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20546 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20548 var myReader = new Roo.data.ArrayReader({
20549 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20553 * This would consume an Array like this:
20555 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20557 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20559 * Create a new JsonReader
20560 * @param {Object} meta Metadata configuration options.
20561 * @param {Object} recordType Either an Array of field definition objects
20562 * as specified to {@link Roo.data.Record#create},
20563 * or an {@link Roo.data.Record} object
20564 * created using {@link Roo.data.Record#create}.
20566 Roo.data.ArrayReader = function(meta, recordType){
20567 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20570 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20572 * Create a data block containing Roo.data.Records from an XML document.
20573 * @param {Object} o An Array of row objects which represents the dataset.
20574 * @return {Object} data A data block which is used by an Roo.data.Store object as
20575 * a cache of Roo.data.Records.
20577 readRecords : function(o){
20578 var sid = this.meta ? this.meta.id : null;
20579 var recordType = this.recordType, fields = recordType.prototype.fields;
20582 for(var i = 0; i < root.length; i++){
20585 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20586 for(var j = 0, jlen = fields.length; j < jlen; j++){
20587 var f = fields.items[j];
20588 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20589 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20591 values[f.name] = v;
20593 var record = new recordType(values, id);
20595 records[records.length] = record;
20599 totalRecords : records.length
20604 * Ext JS Library 1.1.1
20605 * Copyright(c) 2006-2007, Ext JS, LLC.
20607 * Originally Released Under LGPL - original licence link has changed is not relivant.
20610 * <script type="text/javascript">
20615 * @class Roo.data.Tree
20616 * @extends Roo.util.Observable
20617 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20618 * in the tree have most standard DOM functionality.
20620 * @param {Node} root (optional) The root node
20622 Roo.data.Tree = function(root){
20623 this.nodeHash = {};
20625 * The root node for this tree
20630 this.setRootNode(root);
20635 * Fires when a new child node is appended to a node in this tree.
20636 * @param {Tree} tree The owner tree
20637 * @param {Node} parent The parent node
20638 * @param {Node} node The newly appended node
20639 * @param {Number} index The index of the newly appended node
20644 * Fires when a child node is removed from a node in this tree.
20645 * @param {Tree} tree The owner tree
20646 * @param {Node} parent The parent node
20647 * @param {Node} node The child node removed
20652 * Fires when a node is moved to a new location in the tree
20653 * @param {Tree} tree The owner tree
20654 * @param {Node} node The node moved
20655 * @param {Node} oldParent The old parent of this node
20656 * @param {Node} newParent The new parent of this node
20657 * @param {Number} index The index it was moved to
20662 * Fires when a new child node is inserted in a node in this tree.
20663 * @param {Tree} tree The owner tree
20664 * @param {Node} parent The parent node
20665 * @param {Node} node The child node inserted
20666 * @param {Node} refNode The child node the node was inserted before
20670 * @event beforeappend
20671 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20672 * @param {Tree} tree The owner tree
20673 * @param {Node} parent The parent node
20674 * @param {Node} node The child node to be appended
20676 "beforeappend" : true,
20678 * @event beforeremove
20679 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20680 * @param {Tree} tree The owner tree
20681 * @param {Node} parent The parent node
20682 * @param {Node} node The child node to be removed
20684 "beforeremove" : true,
20686 * @event beforemove
20687 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20688 * @param {Tree} tree The owner tree
20689 * @param {Node} node The node being moved
20690 * @param {Node} oldParent The parent of the node
20691 * @param {Node} newParent The new parent the node is moving to
20692 * @param {Number} index The index it is being moved to
20694 "beforemove" : true,
20696 * @event beforeinsert
20697 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20698 * @param {Tree} tree The owner tree
20699 * @param {Node} parent The parent node
20700 * @param {Node} node The child node to be inserted
20701 * @param {Node} refNode The child node the node is being inserted before
20703 "beforeinsert" : true
20706 Roo.data.Tree.superclass.constructor.call(this);
20709 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20710 pathSeparator: "/",
20712 proxyNodeEvent : function(){
20713 return this.fireEvent.apply(this, arguments);
20717 * Returns the root node for this tree.
20720 getRootNode : function(){
20725 * Sets the root node for this tree.
20726 * @param {Node} node
20729 setRootNode : function(node){
20731 node.ownerTree = this;
20732 node.isRoot = true;
20733 this.registerNode(node);
20738 * Gets a node in this tree by its id.
20739 * @param {String} id
20742 getNodeById : function(id){
20743 return this.nodeHash[id];
20746 registerNode : function(node){
20747 this.nodeHash[node.id] = node;
20750 unregisterNode : function(node){
20751 delete this.nodeHash[node.id];
20754 toString : function(){
20755 return "[Tree"+(this.id?" "+this.id:"")+"]";
20760 * @class Roo.data.Node
20761 * @extends Roo.util.Observable
20762 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
20763 * @cfg {String} id The id for this node. If one is not specified, one is generated.
20765 * @param {Object} attributes The attributes/config for the node
20767 Roo.data.Node = function(attributes){
20769 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
20772 this.attributes = attributes || {};
20773 this.leaf = this.attributes.leaf;
20775 * The node id. @type String
20777 this.id = this.attributes.id;
20779 this.id = Roo.id(null, "ynode-");
20780 this.attributes.id = this.id;
20783 * All child nodes of this node. @type Array
20785 this.childNodes = [];
20786 if(!this.childNodes.indexOf){ // indexOf is a must
20787 this.childNodes.indexOf = function(o){
20788 for(var i = 0, len = this.length; i < len; i++){
20789 if(this[i] == o) return i;
20795 * The parent node for this node. @type Node
20797 this.parentNode = null;
20799 * The first direct child node of this node, or null if this node has no child nodes. @type Node
20801 this.firstChild = null;
20803 * The last direct child node of this node, or null if this node has no child nodes. @type Node
20805 this.lastChild = null;
20807 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
20809 this.previousSibling = null;
20811 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
20813 this.nextSibling = null;
20818 * Fires when a new child node is appended
20819 * @param {Tree} tree The owner tree
20820 * @param {Node} this This node
20821 * @param {Node} node The newly appended node
20822 * @param {Number} index The index of the newly appended node
20827 * Fires when a child node is removed
20828 * @param {Tree} tree The owner tree
20829 * @param {Node} this This node
20830 * @param {Node} node The removed node
20835 * Fires when this node is moved to a new location in the tree
20836 * @param {Tree} tree The owner tree
20837 * @param {Node} this This node
20838 * @param {Node} oldParent The old parent of this node
20839 * @param {Node} newParent The new parent of this node
20840 * @param {Number} index The index it was moved to
20845 * Fires when a new child node is inserted.
20846 * @param {Tree} tree The owner tree
20847 * @param {Node} this This node
20848 * @param {Node} node The child node inserted
20849 * @param {Node} refNode The child node the node was inserted before
20853 * @event beforeappend
20854 * Fires before a new child is appended, return false to cancel the append.
20855 * @param {Tree} tree The owner tree
20856 * @param {Node} this This node
20857 * @param {Node} node The child node to be appended
20859 "beforeappend" : true,
20861 * @event beforeremove
20862 * Fires before a child is removed, return false to cancel the remove.
20863 * @param {Tree} tree The owner tree
20864 * @param {Node} this This node
20865 * @param {Node} node The child node to be removed
20867 "beforeremove" : true,
20869 * @event beforemove
20870 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
20871 * @param {Tree} tree The owner tree
20872 * @param {Node} this This node
20873 * @param {Node} oldParent The parent of this node
20874 * @param {Node} newParent The new parent this node is moving to
20875 * @param {Number} index The index it is being moved to
20877 "beforemove" : true,
20879 * @event beforeinsert
20880 * Fires before a new child is inserted, return false to cancel the insert.
20881 * @param {Tree} tree The owner tree
20882 * @param {Node} this This node
20883 * @param {Node} node The child node to be inserted
20884 * @param {Node} refNode The child node the node is being inserted before
20886 "beforeinsert" : true
20888 this.listeners = this.attributes.listeners;
20889 Roo.data.Node.superclass.constructor.call(this);
20892 Roo.extend(Roo.data.Node, Roo.util.Observable, {
20893 fireEvent : function(evtName){
20894 // first do standard event for this node
20895 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
20898 // then bubble it up to the tree if the event wasn't cancelled
20899 var ot = this.getOwnerTree();
20901 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
20909 * Returns true if this node is a leaf
20910 * @return {Boolean}
20912 isLeaf : function(){
20913 return this.leaf === true;
20917 setFirstChild : function(node){
20918 this.firstChild = node;
20922 setLastChild : function(node){
20923 this.lastChild = node;
20928 * Returns true if this node is the last child of its parent
20929 * @return {Boolean}
20931 isLast : function(){
20932 return (!this.parentNode ? true : this.parentNode.lastChild == this);
20936 * Returns true if this node is the first child of its parent
20937 * @return {Boolean}
20939 isFirst : function(){
20940 return (!this.parentNode ? true : this.parentNode.firstChild == this);
20943 hasChildNodes : function(){
20944 return !this.isLeaf() && this.childNodes.length > 0;
20948 * Insert node(s) as the last child node of this node.
20949 * @param {Node/Array} node The node or Array of nodes to append
20950 * @return {Node} The appended node if single append, or null if an array was passed
20952 appendChild : function(node){
20954 if(node instanceof Array){
20956 }else if(arguments.length > 1){
20959 // if passed an array or multiple args do them one by one
20961 for(var i = 0, len = multi.length; i < len; i++) {
20962 this.appendChild(multi[i]);
20965 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
20968 var index = this.childNodes.length;
20969 var oldParent = node.parentNode;
20970 // it's a move, make sure we move it cleanly
20972 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
20975 oldParent.removeChild(node);
20977 index = this.childNodes.length;
20979 this.setFirstChild(node);
20981 this.childNodes.push(node);
20982 node.parentNode = this;
20983 var ps = this.childNodes[index-1];
20985 node.previousSibling = ps;
20986 ps.nextSibling = node;
20988 node.previousSibling = null;
20990 node.nextSibling = null;
20991 this.setLastChild(node);
20992 node.setOwnerTree(this.getOwnerTree());
20993 this.fireEvent("append", this.ownerTree, this, node, index);
20995 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21002 * Removes a child node from this node.
21003 * @param {Node} node The node to remove
21004 * @return {Node} The removed node
21006 removeChild : function(node){
21007 var index = this.childNodes.indexOf(node);
21011 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21015 // remove it from childNodes collection
21016 this.childNodes.splice(index, 1);
21019 if(node.previousSibling){
21020 node.previousSibling.nextSibling = node.nextSibling;
21022 if(node.nextSibling){
21023 node.nextSibling.previousSibling = node.previousSibling;
21026 // update child refs
21027 if(this.firstChild == node){
21028 this.setFirstChild(node.nextSibling);
21030 if(this.lastChild == node){
21031 this.setLastChild(node.previousSibling);
21034 node.setOwnerTree(null);
21035 // clear any references from the node
21036 node.parentNode = null;
21037 node.previousSibling = null;
21038 node.nextSibling = null;
21039 this.fireEvent("remove", this.ownerTree, this, node);
21044 * Inserts the first node before the second node in this nodes childNodes collection.
21045 * @param {Node} node The node to insert
21046 * @param {Node} refNode The node to insert before (if null the node is appended)
21047 * @return {Node} The inserted node
21049 insertBefore : function(node, refNode){
21050 if(!refNode){ // like standard Dom, refNode can be null for append
21051 return this.appendChild(node);
21054 if(node == refNode){
21058 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21061 var index = this.childNodes.indexOf(refNode);
21062 var oldParent = node.parentNode;
21063 var refIndex = index;
21065 // when moving internally, indexes will change after remove
21066 if(oldParent == this && this.childNodes.indexOf(node) < index){
21070 // it's a move, make sure we move it cleanly
21072 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21075 oldParent.removeChild(node);
21078 this.setFirstChild(node);
21080 this.childNodes.splice(refIndex, 0, node);
21081 node.parentNode = this;
21082 var ps = this.childNodes[refIndex-1];
21084 node.previousSibling = ps;
21085 ps.nextSibling = node;
21087 node.previousSibling = null;
21089 node.nextSibling = refNode;
21090 refNode.previousSibling = node;
21091 node.setOwnerTree(this.getOwnerTree());
21092 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21094 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21100 * Returns the child node at the specified index.
21101 * @param {Number} index
21104 item : function(index){
21105 return this.childNodes[index];
21109 * Replaces one child node in this node with another.
21110 * @param {Node} newChild The replacement node
21111 * @param {Node} oldChild The node to replace
21112 * @return {Node} The replaced node
21114 replaceChild : function(newChild, oldChild){
21115 this.insertBefore(newChild, oldChild);
21116 this.removeChild(oldChild);
21121 * Returns the index of a child node
21122 * @param {Node} node
21123 * @return {Number} The index of the node or -1 if it was not found
21125 indexOf : function(child){
21126 return this.childNodes.indexOf(child);
21130 * Returns the tree this node is in.
21133 getOwnerTree : function(){
21134 // if it doesn't have one, look for one
21135 if(!this.ownerTree){
21139 this.ownerTree = p.ownerTree;
21145 return this.ownerTree;
21149 * Returns depth of this node (the root node has a depth of 0)
21152 getDepth : function(){
21155 while(p.parentNode){
21163 setOwnerTree : function(tree){
21164 // if it's move, we need to update everyone
21165 if(tree != this.ownerTree){
21166 if(this.ownerTree){
21167 this.ownerTree.unregisterNode(this);
21169 this.ownerTree = tree;
21170 var cs = this.childNodes;
21171 for(var i = 0, len = cs.length; i < len; i++) {
21172 cs[i].setOwnerTree(tree);
21175 tree.registerNode(this);
21181 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21182 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21183 * @return {String} The path
21185 getPath : function(attr){
21186 attr = attr || "id";
21187 var p = this.parentNode;
21188 var b = [this.attributes[attr]];
21190 b.unshift(p.attributes[attr]);
21193 var sep = this.getOwnerTree().pathSeparator;
21194 return sep + b.join(sep);
21198 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21199 * function call will be the scope provided or the current node. The arguments to the function
21200 * will be the args provided or the current node. If the function returns false at any point,
21201 * the bubble is stopped.
21202 * @param {Function} fn The function to call
21203 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21204 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21206 bubble : function(fn, scope, args){
21209 if(fn.call(scope || p, args || p) === false){
21217 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21218 * function call will be the scope provided or the current node. The arguments to the function
21219 * will be the args provided or the current node. If the function returns false at any point,
21220 * the cascade is stopped on that branch.
21221 * @param {Function} fn The function to call
21222 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21223 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21225 cascade : function(fn, scope, args){
21226 if(fn.call(scope || this, args || this) !== false){
21227 var cs = this.childNodes;
21228 for(var i = 0, len = cs.length; i < len; i++) {
21229 cs[i].cascade(fn, scope, args);
21235 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21236 * function call will be the scope provided or the current node. The arguments to the function
21237 * will be the args provided or the current node. If the function returns false at any point,
21238 * the iteration stops.
21239 * @param {Function} fn The function to call
21240 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21241 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21243 eachChild : function(fn, scope, args){
21244 var cs = this.childNodes;
21245 for(var i = 0, len = cs.length; i < len; i++) {
21246 if(fn.call(scope || this, args || cs[i]) === false){
21253 * Finds the first child that has the attribute with the specified value.
21254 * @param {String} attribute The attribute name
21255 * @param {Mixed} value The value to search for
21256 * @return {Node} The found child or null if none was found
21258 findChild : function(attribute, value){
21259 var cs = this.childNodes;
21260 for(var i = 0, len = cs.length; i < len; i++) {
21261 if(cs[i].attributes[attribute] == value){
21269 * Finds the first child by a custom function. The child matches if the function passed
21271 * @param {Function} fn
21272 * @param {Object} scope (optional)
21273 * @return {Node} The found child or null if none was found
21275 findChildBy : function(fn, scope){
21276 var cs = this.childNodes;
21277 for(var i = 0, len = cs.length; i < len; i++) {
21278 if(fn.call(scope||cs[i], cs[i]) === true){
21286 * Sorts this nodes children using the supplied sort function
21287 * @param {Function} fn
21288 * @param {Object} scope (optional)
21290 sort : function(fn, scope){
21291 var cs = this.childNodes;
21292 var len = cs.length;
21294 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21296 for(var i = 0; i < len; i++){
21298 n.previousSibling = cs[i-1];
21299 n.nextSibling = cs[i+1];
21301 this.setFirstChild(n);
21304 this.setLastChild(n);
21311 * Returns true if this node is an ancestor (at any point) of the passed node.
21312 * @param {Node} node
21313 * @return {Boolean}
21315 contains : function(node){
21316 return node.isAncestor(this);
21320 * Returns true if the passed node is an ancestor (at any point) of this node.
21321 * @param {Node} node
21322 * @return {Boolean}
21324 isAncestor : function(node){
21325 var p = this.parentNode;
21335 toString : function(){
21336 return "[Node"+(this.id?" "+this.id:"")+"]";
21340 * Ext JS Library 1.1.1
21341 * Copyright(c) 2006-2007, Ext JS, LLC.
21343 * Originally Released Under LGPL - original licence link has changed is not relivant.
21346 * <script type="text/javascript">
21351 * @class Roo.ComponentMgr
21352 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21355 Roo.ComponentMgr = function(){
21356 var all = new Roo.util.MixedCollection();
21360 * Registers a component.
21361 * @param {Roo.Component} c The component
21363 register : function(c){
21368 * Unregisters a component.
21369 * @param {Roo.Component} c The component
21371 unregister : function(c){
21376 * Returns a component by id
21377 * @param {String} id The component id
21379 get : function(id){
21380 return all.get(id);
21384 * Registers a function that will be called when a specified component is added to ComponentMgr
21385 * @param {String} id The component id
21386 * @param {Funtction} fn The callback function
21387 * @param {Object} scope The scope of the callback
21389 onAvailable : function(id, fn, scope){
21390 all.on("add", function(index, o){
21392 fn.call(scope || o, o);
21393 all.un("add", fn, scope);
21400 * Ext JS Library 1.1.1
21401 * Copyright(c) 2006-2007, Ext JS, LLC.
21403 * Originally Released Under LGPL - original licence link has changed is not relivant.
21406 * <script type="text/javascript">
21410 * @class Roo.Component
21411 * @extends Roo.util.Observable
21412 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21413 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21414 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21415 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21416 * All visual components (widgets) that require rendering into a layout should subclass Component.
21418 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21419 * 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
21420 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21422 Roo.Component = function(config){
21423 config = config || {};
21424 if(config.tagName || config.dom || typeof config == "string"){ // element object
21425 config = {el: config, id: config.id || config};
21427 this.initialConfig = config;
21429 Roo.apply(this, config);
21433 * Fires after the component is disabled.
21434 * @param {Roo.Component} this
21439 * Fires after the component is enabled.
21440 * @param {Roo.Component} this
21444 * @event beforeshow
21445 * Fires before the component is shown. Return false to stop the show.
21446 * @param {Roo.Component} this
21451 * Fires after the component is shown.
21452 * @param {Roo.Component} this
21456 * @event beforehide
21457 * Fires before the component is hidden. Return false to stop the hide.
21458 * @param {Roo.Component} this
21463 * Fires after the component is hidden.
21464 * @param {Roo.Component} this
21468 * @event beforerender
21469 * Fires before the component is rendered. Return false to stop the render.
21470 * @param {Roo.Component} this
21472 beforerender : true,
21475 * Fires after the component is rendered.
21476 * @param {Roo.Component} this
21480 * @event beforedestroy
21481 * Fires before the component is destroyed. Return false to stop the destroy.
21482 * @param {Roo.Component} this
21484 beforedestroy : true,
21487 * Fires after the component is destroyed.
21488 * @param {Roo.Component} this
21493 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21495 Roo.ComponentMgr.register(this);
21496 Roo.Component.superclass.constructor.call(this);
21497 this.initComponent();
21498 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21499 this.render(this.renderTo);
21500 delete this.renderTo;
21505 Roo.Component.AUTO_ID = 1000;
21507 Roo.extend(Roo.Component, Roo.util.Observable, {
21509 * @property {Boolean} hidden
21510 * true if this component is hidden. Read-only.
21514 * true if this component is disabled. Read-only.
21518 * true if this component has been rendered. Read-only.
21522 /** @cfg {String} disableClass
21523 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21525 disabledClass : "x-item-disabled",
21526 /** @cfg {Boolean} allowDomMove
21527 * Whether the component can move the Dom node when rendering (defaults to true).
21529 allowDomMove : true,
21530 /** @cfg {String} hideMode
21531 * How this component should hidden. Supported values are
21532 * "visibility" (css visibility), "offsets" (negative offset position) and
21533 * "display" (css display) - defaults to "display".
21535 hideMode: 'display',
21538 ctype : "Roo.Component",
21540 /** @cfg {String} actionMode
21541 * which property holds the element that used for hide() / show() / disable() / enable()
21547 getActionEl : function(){
21548 return this[this.actionMode];
21551 initComponent : Roo.emptyFn,
21553 * If this is a lazy rendering component, render it to its container element.
21554 * @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.
21556 render : function(container, position){
21557 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21558 if(!container && this.el){
21559 this.el = Roo.get(this.el);
21560 container = this.el.dom.parentNode;
21561 this.allowDomMove = false;
21563 this.container = Roo.get(container);
21564 this.rendered = true;
21565 if(position !== undefined){
21566 if(typeof position == 'number'){
21567 position = this.container.dom.childNodes[position];
21569 position = Roo.getDom(position);
21572 this.onRender(this.container, position || null);
21574 this.el.addClass(this.cls);
21578 this.el.applyStyles(this.style);
21581 this.fireEvent("render", this);
21582 this.afterRender(this.container);
21594 // default function is not really useful
21595 onRender : function(ct, position){
21597 this.el = Roo.get(this.el);
21598 if(this.allowDomMove !== false){
21599 ct.dom.insertBefore(this.el.dom, position);
21605 getAutoCreate : function(){
21606 var cfg = typeof this.autoCreate == "object" ?
21607 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21608 if(this.id && !cfg.id){
21615 afterRender : Roo.emptyFn,
21618 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21619 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21621 destroy : function(){
21622 if(this.fireEvent("beforedestroy", this) !== false){
21623 this.purgeListeners();
21624 this.beforeDestroy();
21626 this.el.removeAllListeners();
21628 if(this.actionMode == "container"){
21629 this.container.remove();
21633 Roo.ComponentMgr.unregister(this);
21634 this.fireEvent("destroy", this);
21639 beforeDestroy : function(){
21644 onDestroy : function(){
21649 * Returns the underlying {@link Roo.Element}.
21650 * @return {Roo.Element} The element
21652 getEl : function(){
21657 * Returns the id of this component.
21660 getId : function(){
21665 * Try to focus this component.
21666 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21667 * @return {Roo.Component} this
21669 focus : function(selectText){
21672 if(selectText === true){
21673 this.el.dom.select();
21688 * Disable this component.
21689 * @return {Roo.Component} this
21691 disable : function(){
21695 this.disabled = true;
21696 this.fireEvent("disable", this);
21701 onDisable : function(){
21702 this.getActionEl().addClass(this.disabledClass);
21703 this.el.dom.disabled = true;
21707 * Enable this component.
21708 * @return {Roo.Component} this
21710 enable : function(){
21714 this.disabled = false;
21715 this.fireEvent("enable", this);
21720 onEnable : function(){
21721 this.getActionEl().removeClass(this.disabledClass);
21722 this.el.dom.disabled = false;
21726 * Convenience function for setting disabled/enabled by boolean.
21727 * @param {Boolean} disabled
21729 setDisabled : function(disabled){
21730 this[disabled ? "disable" : "enable"]();
21734 * Show this component.
21735 * @return {Roo.Component} this
21738 if(this.fireEvent("beforeshow", this) !== false){
21739 this.hidden = false;
21743 this.fireEvent("show", this);
21749 onShow : function(){
21750 var ae = this.getActionEl();
21751 if(this.hideMode == 'visibility'){
21752 ae.dom.style.visibility = "visible";
21753 }else if(this.hideMode == 'offsets'){
21754 ae.removeClass('x-hidden');
21756 ae.dom.style.display = "";
21761 * Hide this component.
21762 * @return {Roo.Component} this
21765 if(this.fireEvent("beforehide", this) !== false){
21766 this.hidden = true;
21770 this.fireEvent("hide", this);
21776 onHide : function(){
21777 var ae = this.getActionEl();
21778 if(this.hideMode == 'visibility'){
21779 ae.dom.style.visibility = "hidden";
21780 }else if(this.hideMode == 'offsets'){
21781 ae.addClass('x-hidden');
21783 ae.dom.style.display = "none";
21788 * Convenience function to hide or show this component by boolean.
21789 * @param {Boolean} visible True to show, false to hide
21790 * @return {Roo.Component} this
21792 setVisible: function(visible){
21802 * Returns true if this component is visible.
21804 isVisible : function(){
21805 return this.getActionEl().isVisible();
21808 cloneConfig : function(overrides){
21809 overrides = overrides || {};
21810 var id = overrides.id || Roo.id();
21811 var cfg = Roo.applyIf(overrides, this.initialConfig);
21812 cfg.id = id; // prevent dup id
21813 return new this.constructor(cfg);
21817 * Ext JS Library 1.1.1
21818 * Copyright(c) 2006-2007, Ext JS, LLC.
21820 * Originally Released Under LGPL - original licence link has changed is not relivant.
21823 * <script type="text/javascript">
21828 * @extends Roo.Element
21829 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
21830 * automatic maintaining of shadow/shim positions.
21831 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
21832 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
21833 * you can pass a string with a CSS class name. False turns off the shadow.
21834 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
21835 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
21836 * @cfg {String} cls CSS class to add to the element
21837 * @cfg {Number} zindex Starting z-index (defaults to 11000)
21838 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
21840 * @param {Object} config An object with config options.
21841 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
21844 Roo.Layer = function(config, existingEl){
21845 config = config || {};
21846 var dh = Roo.DomHelper;
21847 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
21849 this.dom = Roo.getDom(existingEl);
21852 var o = config.dh || {tag: "div", cls: "x-layer"};
21853 this.dom = dh.append(pel, o);
21856 this.addClass(config.cls);
21858 this.constrain = config.constrain !== false;
21859 this.visibilityMode = Roo.Element.VISIBILITY;
21861 this.id = this.dom.id = config.id;
21863 this.id = Roo.id(this.dom);
21865 this.zindex = config.zindex || this.getZIndex();
21866 this.position("absolute", this.zindex);
21868 this.shadowOffset = config.shadowOffset || 4;
21869 this.shadow = new Roo.Shadow({
21870 offset : this.shadowOffset,
21871 mode : config.shadow
21874 this.shadowOffset = 0;
21876 this.useShim = config.shim !== false && Roo.useShims;
21877 this.useDisplay = config.useDisplay;
21881 var supr = Roo.Element.prototype;
21883 // shims are shared among layer to keep from having 100 iframes
21886 Roo.extend(Roo.Layer, Roo.Element, {
21888 getZIndex : function(){
21889 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
21892 getShim : function(){
21899 var shim = shims.shift();
21901 shim = this.createShim();
21902 shim.enableDisplayMode('block');
21903 shim.dom.style.display = 'none';
21904 shim.dom.style.visibility = 'visible';
21906 var pn = this.dom.parentNode;
21907 if(shim.dom.parentNode != pn){
21908 pn.insertBefore(shim.dom, this.dom);
21910 shim.setStyle('z-index', this.getZIndex()-2);
21915 hideShim : function(){
21917 this.shim.setDisplayed(false);
21918 shims.push(this.shim);
21923 disableShadow : function(){
21925 this.shadowDisabled = true;
21926 this.shadow.hide();
21927 this.lastShadowOffset = this.shadowOffset;
21928 this.shadowOffset = 0;
21932 enableShadow : function(show){
21934 this.shadowDisabled = false;
21935 this.shadowOffset = this.lastShadowOffset;
21936 delete this.lastShadowOffset;
21944 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
21945 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
21946 sync : function(doShow){
21947 var sw = this.shadow;
21948 if(!this.updating && this.isVisible() && (sw || this.useShim)){
21949 var sh = this.getShim();
21951 var w = this.getWidth(),
21952 h = this.getHeight();
21954 var l = this.getLeft(true),
21955 t = this.getTop(true);
21957 if(sw && !this.shadowDisabled){
21958 if(doShow && !sw.isVisible()){
21961 sw.realign(l, t, w, h);
21967 // fit the shim behind the shadow, so it is shimmed too
21968 var a = sw.adjusts, s = sh.dom.style;
21969 s.left = (Math.min(l, l+a.l))+"px";
21970 s.top = (Math.min(t, t+a.t))+"px";
21971 s.width = (w+a.w)+"px";
21972 s.height = (h+a.h)+"px";
21979 sh.setLeftTop(l, t);
21986 destroy : function(){
21989 this.shadow.hide();
21991 this.removeAllListeners();
21992 var pn = this.dom.parentNode;
21994 pn.removeChild(this.dom);
21996 Roo.Element.uncache(this.id);
21999 remove : function(){
22004 beginUpdate : function(){
22005 this.updating = true;
22009 endUpdate : function(){
22010 this.updating = false;
22015 hideUnders : function(negOffset){
22017 this.shadow.hide();
22023 constrainXY : function(){
22024 if(this.constrain){
22025 var vw = Roo.lib.Dom.getViewWidth(),
22026 vh = Roo.lib.Dom.getViewHeight();
22027 var s = Roo.get(document).getScroll();
22029 var xy = this.getXY();
22030 var x = xy[0], y = xy[1];
22031 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22032 // only move it if it needs it
22034 // first validate right/bottom
22035 if((x + w) > vw+s.left){
22036 x = vw - w - this.shadowOffset;
22039 if((y + h) > vh+s.top){
22040 y = vh - h - this.shadowOffset;
22043 // then make sure top/left isn't negative
22054 var ay = this.avoidY;
22055 if(y <= ay && (y+h) >= ay){
22061 supr.setXY.call(this, xy);
22067 isVisible : function(){
22068 return this.visible;
22072 showAction : function(){
22073 this.visible = true; // track visibility to prevent getStyle calls
22074 if(this.useDisplay === true){
22075 this.setDisplayed("");
22076 }else if(this.lastXY){
22077 supr.setXY.call(this, this.lastXY);
22078 }else if(this.lastLT){
22079 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22084 hideAction : function(){
22085 this.visible = false;
22086 if(this.useDisplay === true){
22087 this.setDisplayed(false);
22089 this.setLeftTop(-10000,-10000);
22093 // overridden Element method
22094 setVisible : function(v, a, d, c, e){
22099 var cb = function(){
22104 }.createDelegate(this);
22105 supr.setVisible.call(this, true, true, d, cb, e);
22108 this.hideUnders(true);
22117 }.createDelegate(this);
22119 supr.setVisible.call(this, v, a, d, cb, e);
22128 storeXY : function(xy){
22129 delete this.lastLT;
22133 storeLeftTop : function(left, top){
22134 delete this.lastXY;
22135 this.lastLT = [left, top];
22139 beforeFx : function(){
22140 this.beforeAction();
22141 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22145 afterFx : function(){
22146 Roo.Layer.superclass.afterFx.apply(this, arguments);
22147 this.sync(this.isVisible());
22151 beforeAction : function(){
22152 if(!this.updating && this.shadow){
22153 this.shadow.hide();
22157 // overridden Element method
22158 setLeft : function(left){
22159 this.storeLeftTop(left, this.getTop(true));
22160 supr.setLeft.apply(this, arguments);
22164 setTop : function(top){
22165 this.storeLeftTop(this.getLeft(true), top);
22166 supr.setTop.apply(this, arguments);
22170 setLeftTop : function(left, top){
22171 this.storeLeftTop(left, top);
22172 supr.setLeftTop.apply(this, arguments);
22176 setXY : function(xy, a, d, c, e){
22178 this.beforeAction();
22180 var cb = this.createCB(c);
22181 supr.setXY.call(this, xy, a, d, cb, e);
22188 createCB : function(c){
22199 // overridden Element method
22200 setX : function(x, a, d, c, e){
22201 this.setXY([x, this.getY()], a, d, c, e);
22204 // overridden Element method
22205 setY : function(y, a, d, c, e){
22206 this.setXY([this.getX(), y], a, d, c, e);
22209 // overridden Element method
22210 setSize : function(w, h, a, d, c, e){
22211 this.beforeAction();
22212 var cb = this.createCB(c);
22213 supr.setSize.call(this, w, h, a, d, cb, e);
22219 // overridden Element method
22220 setWidth : function(w, a, d, c, e){
22221 this.beforeAction();
22222 var cb = this.createCB(c);
22223 supr.setWidth.call(this, w, a, d, cb, e);
22229 // overridden Element method
22230 setHeight : function(h, a, d, c, e){
22231 this.beforeAction();
22232 var cb = this.createCB(c);
22233 supr.setHeight.call(this, h, a, d, cb, e);
22239 // overridden Element method
22240 setBounds : function(x, y, w, h, a, d, c, e){
22241 this.beforeAction();
22242 var cb = this.createCB(c);
22244 this.storeXY([x, y]);
22245 supr.setXY.call(this, [x, y]);
22246 supr.setSize.call(this, w, h, a, d, cb, e);
22249 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22255 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22256 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22257 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22258 * @param {Number} zindex The new z-index to set
22259 * @return {this} The Layer
22261 setZIndex : function(zindex){
22262 this.zindex = zindex;
22263 this.setStyle("z-index", zindex + 2);
22265 this.shadow.setZIndex(zindex + 1);
22268 this.shim.setStyle("z-index", zindex);
22274 * Ext JS Library 1.1.1
22275 * Copyright(c) 2006-2007, Ext JS, LLC.
22277 * Originally Released Under LGPL - original licence link has changed is not relivant.
22280 * <script type="text/javascript">
22285 * @class Roo.Shadow
22286 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22287 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22288 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22290 * Create a new Shadow
22291 * @param {Object} config The config object
22293 Roo.Shadow = function(config){
22294 Roo.apply(this, config);
22295 if(typeof this.mode != "string"){
22296 this.mode = this.defaultMode;
22298 var o = this.offset, a = {h: 0};
22299 var rad = Math.floor(this.offset/2);
22300 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22306 a.l -= this.offset + rad;
22307 a.t -= this.offset + rad;
22318 a.l -= (this.offset - rad);
22319 a.t -= this.offset + rad;
22321 a.w -= (this.offset - rad)*2;
22332 a.l -= (this.offset - rad);
22333 a.t -= (this.offset - rad);
22335 a.w -= (this.offset + rad + 1);
22336 a.h -= (this.offset + rad);
22345 Roo.Shadow.prototype = {
22347 * @cfg {String} mode
22348 * The shadow display mode. Supports the following options:<br />
22349 * sides: Shadow displays on both sides and bottom only<br />
22350 * frame: Shadow displays equally on all four sides<br />
22351 * drop: Traditional bottom-right drop shadow (default)
22354 * @cfg {String} offset
22355 * The number of pixels to offset the shadow from the element (defaults to 4)
22360 defaultMode: "drop",
22363 * Displays the shadow under the target element
22364 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22366 show : function(target){
22367 target = Roo.get(target);
22369 this.el = Roo.Shadow.Pool.pull();
22370 if(this.el.dom.nextSibling != target.dom){
22371 this.el.insertBefore(target);
22374 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22376 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22379 target.getLeft(true),
22380 target.getTop(true),
22384 this.el.dom.style.display = "block";
22388 * Returns true if the shadow is visible, else false
22390 isVisible : function(){
22391 return this.el ? true : false;
22395 * Direct alignment when values are already available. Show must be called at least once before
22396 * calling this method to ensure it is initialized.
22397 * @param {Number} left The target element left position
22398 * @param {Number} top The target element top position
22399 * @param {Number} width The target element width
22400 * @param {Number} height The target element height
22402 realign : function(l, t, w, h){
22406 var a = this.adjusts, d = this.el.dom, s = d.style;
22408 s.left = (l+a.l)+"px";
22409 s.top = (t+a.t)+"px";
22410 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22411 if(s.width != sws || s.height != shs){
22415 var cn = d.childNodes;
22416 var sww = Math.max(0, (sw-12))+"px";
22417 cn[0].childNodes[1].style.width = sww;
22418 cn[1].childNodes[1].style.width = sww;
22419 cn[2].childNodes[1].style.width = sww;
22420 cn[1].style.height = Math.max(0, (sh-12))+"px";
22426 * Hides this shadow
22430 this.el.dom.style.display = "none";
22431 Roo.Shadow.Pool.push(this.el);
22437 * Adjust the z-index of this shadow
22438 * @param {Number} zindex The new z-index
22440 setZIndex : function(z){
22443 this.el.setStyle("z-index", z);
22448 // Private utility class that manages the internal Shadow cache
22449 Roo.Shadow.Pool = function(){
22451 var markup = Roo.isIE ?
22452 '<div class="x-ie-shadow"></div>' :
22453 '<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>';
22456 var sh = p.shift();
22458 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22459 sh.autoBoxAdjust = false;
22464 push : function(sh){
22470 * Ext JS Library 1.1.1
22471 * Copyright(c) 2006-2007, Ext JS, LLC.
22473 * Originally Released Under LGPL - original licence link has changed is not relivant.
22476 * <script type="text/javascript">
22480 * @class Roo.BoxComponent
22481 * @extends Roo.Component
22482 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22483 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22484 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22485 * layout containers.
22487 * @param {Roo.Element/String/Object} config The configuration options.
22489 Roo.BoxComponent = function(config){
22490 Roo.Component.call(this, config);
22494 * Fires after the component is resized.
22495 * @param {Roo.Component} this
22496 * @param {Number} adjWidth The box-adjusted width that was set
22497 * @param {Number} adjHeight The box-adjusted height that was set
22498 * @param {Number} rawWidth The width that was originally specified
22499 * @param {Number} rawHeight The height that was originally specified
22504 * Fires after the component is moved.
22505 * @param {Roo.Component} this
22506 * @param {Number} x The new x position
22507 * @param {Number} y The new y position
22513 Roo.extend(Roo.BoxComponent, Roo.Component, {
22514 // private, set in afterRender to signify that the component has been rendered
22516 // private, used to defer height settings to subclasses
22517 deferHeight: false,
22518 /** @cfg {Number} width
22519 * width (optional) size of component
22521 /** @cfg {Number} height
22522 * height (optional) size of component
22526 * Sets the width and height of the component. This method fires the resize event. This method can accept
22527 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22528 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22529 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22530 * @return {Roo.BoxComponent} this
22532 setSize : function(w, h){
22533 // support for standard size objects
22534 if(typeof w == 'object'){
22539 if(!this.boxReady){
22545 // prevent recalcs when not needed
22546 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22549 this.lastSize = {width: w, height: h};
22551 var adj = this.adjustSize(w, h);
22552 var aw = adj.width, ah = adj.height;
22553 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22554 var rz = this.getResizeEl();
22555 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22556 rz.setSize(aw, ah);
22557 }else if(!this.deferHeight && ah !== undefined){
22559 }else if(aw !== undefined){
22562 this.onResize(aw, ah, w, h);
22563 this.fireEvent('resize', this, aw, ah, w, h);
22569 * Gets the current size of the component's underlying element.
22570 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22572 getSize : function(){
22573 return this.el.getSize();
22577 * Gets the current XY position of the component's underlying element.
22578 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22579 * @return {Array} The XY position of the element (e.g., [100, 200])
22581 getPosition : function(local){
22582 if(local === true){
22583 return [this.el.getLeft(true), this.el.getTop(true)];
22585 return this.xy || this.el.getXY();
22589 * Gets the current box measurements of the component's underlying element.
22590 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22591 * @returns {Object} box An object in the format {x, y, width, height}
22593 getBox : function(local){
22594 var s = this.el.getSize();
22596 s.x = this.el.getLeft(true);
22597 s.y = this.el.getTop(true);
22599 var xy = this.xy || this.el.getXY();
22607 * Sets the current box measurements of the component's underlying element.
22608 * @param {Object} box An object in the format {x, y, width, height}
22609 * @returns {Roo.BoxComponent} this
22611 updateBox : function(box){
22612 this.setSize(box.width, box.height);
22613 this.setPagePosition(box.x, box.y);
22618 getResizeEl : function(){
22619 return this.resizeEl || this.el;
22623 getPositionEl : function(){
22624 return this.positionEl || this.el;
22628 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22629 * This method fires the move event.
22630 * @param {Number} left The new left
22631 * @param {Number} top The new top
22632 * @returns {Roo.BoxComponent} this
22634 setPosition : function(x, y){
22637 if(!this.boxReady){
22640 var adj = this.adjustPosition(x, y);
22641 var ax = adj.x, ay = adj.y;
22643 var el = this.getPositionEl();
22644 if(ax !== undefined || ay !== undefined){
22645 if(ax !== undefined && ay !== undefined){
22646 el.setLeftTop(ax, ay);
22647 }else if(ax !== undefined){
22649 }else if(ay !== undefined){
22652 this.onPosition(ax, ay);
22653 this.fireEvent('move', this, ax, ay);
22659 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22660 * This method fires the move event.
22661 * @param {Number} x The new x position
22662 * @param {Number} y The new y position
22663 * @returns {Roo.BoxComponent} this
22665 setPagePosition : function(x, y){
22668 if(!this.boxReady){
22671 if(x === undefined || y === undefined){ // cannot translate undefined points
22674 var p = this.el.translatePoints(x, y);
22675 this.setPosition(p.left, p.top);
22680 onRender : function(ct, position){
22681 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22683 this.resizeEl = Roo.get(this.resizeEl);
22685 if(this.positionEl){
22686 this.positionEl = Roo.get(this.positionEl);
22691 afterRender : function(){
22692 Roo.BoxComponent.superclass.afterRender.call(this);
22693 this.boxReady = true;
22694 this.setSize(this.width, this.height);
22695 if(this.x || this.y){
22696 this.setPosition(this.x, this.y);
22698 if(this.pageX || this.pageY){
22699 this.setPagePosition(this.pageX, this.pageY);
22704 * Force the component's size to recalculate based on the underlying element's current height and width.
22705 * @returns {Roo.BoxComponent} this
22707 syncSize : function(){
22708 delete this.lastSize;
22709 this.setSize(this.el.getWidth(), this.el.getHeight());
22714 * Called after the component is resized, this method is empty by default but can be implemented by any
22715 * subclass that needs to perform custom logic after a resize occurs.
22716 * @param {Number} adjWidth The box-adjusted width that was set
22717 * @param {Number} adjHeight The box-adjusted height that was set
22718 * @param {Number} rawWidth The width that was originally specified
22719 * @param {Number} rawHeight The height that was originally specified
22721 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22726 * Called after the component is moved, this method is empty by default but can be implemented by any
22727 * subclass that needs to perform custom logic after a move occurs.
22728 * @param {Number} x The new x position
22729 * @param {Number} y The new y position
22731 onPosition : function(x, y){
22736 adjustSize : function(w, h){
22737 if(this.autoWidth){
22740 if(this.autoHeight){
22743 return {width : w, height: h};
22747 adjustPosition : function(x, y){
22748 return {x : x, y: y};
22752 * Ext JS Library 1.1.1
22753 * Copyright(c) 2006-2007, Ext JS, LLC.
22755 * Originally Released Under LGPL - original licence link has changed is not relivant.
22758 * <script type="text/javascript">
22763 * @class Roo.SplitBar
22764 * @extends Roo.util.Observable
22765 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
22769 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
22770 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
22771 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
22772 split.minSize = 100;
22773 split.maxSize = 600;
22774 split.animate = true;
22775 split.on('moved', splitterMoved);
22778 * Create a new SplitBar
22779 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
22780 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
22781 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22782 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
22783 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
22784 position of the SplitBar).
22786 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
22789 this.el = Roo.get(dragElement, true);
22790 this.el.dom.unselectable = "on";
22792 this.resizingEl = Roo.get(resizingElement, true);
22796 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22797 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
22800 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
22803 * The minimum size of the resizing element. (Defaults to 0)
22809 * The maximum size of the resizing element. (Defaults to 2000)
22812 this.maxSize = 2000;
22815 * Whether to animate the transition to the new size
22818 this.animate = false;
22821 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
22824 this.useShim = false;
22829 if(!existingProxy){
22831 this.proxy = Roo.SplitBar.createProxy(this.orientation);
22833 this.proxy = Roo.get(existingProxy).dom;
22836 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
22839 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
22842 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
22845 this.dragSpecs = {};
22848 * @private The adapter to use to positon and resize elements
22850 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
22851 this.adapter.init(this);
22853 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22855 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
22856 this.el.addClass("x-splitbar-h");
22859 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
22860 this.el.addClass("x-splitbar-v");
22866 * Fires when the splitter is moved (alias for {@link #event-moved})
22867 * @param {Roo.SplitBar} this
22868 * @param {Number} newSize the new width or height
22873 * Fires when the splitter is moved
22874 * @param {Roo.SplitBar} this
22875 * @param {Number} newSize the new width or height
22879 * @event beforeresize
22880 * Fires before the splitter is dragged
22881 * @param {Roo.SplitBar} this
22883 "beforeresize" : true,
22885 "beforeapply" : true
22888 Roo.util.Observable.call(this);
22891 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
22892 onStartProxyDrag : function(x, y){
22893 this.fireEvent("beforeresize", this);
22895 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
22897 o.enableDisplayMode("block");
22898 // all splitbars share the same overlay
22899 Roo.SplitBar.prototype.overlay = o;
22901 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
22902 this.overlay.show();
22903 Roo.get(this.proxy).setDisplayed("block");
22904 var size = this.adapter.getElementSize(this);
22905 this.activeMinSize = this.getMinimumSize();;
22906 this.activeMaxSize = this.getMaximumSize();;
22907 var c1 = size - this.activeMinSize;
22908 var c2 = Math.max(this.activeMaxSize - size, 0);
22909 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22910 this.dd.resetConstraints();
22911 this.dd.setXConstraint(
22912 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
22913 this.placement == Roo.SplitBar.LEFT ? c2 : c1
22915 this.dd.setYConstraint(0, 0);
22917 this.dd.resetConstraints();
22918 this.dd.setXConstraint(0, 0);
22919 this.dd.setYConstraint(
22920 this.placement == Roo.SplitBar.TOP ? c1 : c2,
22921 this.placement == Roo.SplitBar.TOP ? c2 : c1
22924 this.dragSpecs.startSize = size;
22925 this.dragSpecs.startPoint = [x, y];
22926 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
22930 * @private Called after the drag operation by the DDProxy
22932 onEndProxyDrag : function(e){
22933 Roo.get(this.proxy).setDisplayed(false);
22934 var endPoint = Roo.lib.Event.getXY(e);
22936 this.overlay.hide();
22939 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22940 newSize = this.dragSpecs.startSize +
22941 (this.placement == Roo.SplitBar.LEFT ?
22942 endPoint[0] - this.dragSpecs.startPoint[0] :
22943 this.dragSpecs.startPoint[0] - endPoint[0]
22946 newSize = this.dragSpecs.startSize +
22947 (this.placement == Roo.SplitBar.TOP ?
22948 endPoint[1] - this.dragSpecs.startPoint[1] :
22949 this.dragSpecs.startPoint[1] - endPoint[1]
22952 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
22953 if(newSize != this.dragSpecs.startSize){
22954 if(this.fireEvent('beforeapply', this, newSize) !== false){
22955 this.adapter.setElementSize(this, newSize);
22956 this.fireEvent("moved", this, newSize);
22957 this.fireEvent("resize", this, newSize);
22963 * Get the adapter this SplitBar uses
22964 * @return The adapter object
22966 getAdapter : function(){
22967 return this.adapter;
22971 * Set the adapter this SplitBar uses
22972 * @param {Object} adapter A SplitBar adapter object
22974 setAdapter : function(adapter){
22975 this.adapter = adapter;
22976 this.adapter.init(this);
22980 * Gets the minimum size for the resizing element
22981 * @return {Number} The minimum size
22983 getMinimumSize : function(){
22984 return this.minSize;
22988 * Sets the minimum size for the resizing element
22989 * @param {Number} minSize The minimum size
22991 setMinimumSize : function(minSize){
22992 this.minSize = minSize;
22996 * Gets the maximum size for the resizing element
22997 * @return {Number} The maximum size
22999 getMaximumSize : function(){
23000 return this.maxSize;
23004 * Sets the maximum size for the resizing element
23005 * @param {Number} maxSize The maximum size
23007 setMaximumSize : function(maxSize){
23008 this.maxSize = maxSize;
23012 * Sets the initialize size for the resizing element
23013 * @param {Number} size The initial size
23015 setCurrentSize : function(size){
23016 var oldAnimate = this.animate;
23017 this.animate = false;
23018 this.adapter.setElementSize(this, size);
23019 this.animate = oldAnimate;
23023 * Destroy this splitbar.
23024 * @param {Boolean} removeEl True to remove the element
23026 destroy : function(removeEl){
23028 this.shim.remove();
23031 this.proxy.parentNode.removeChild(this.proxy);
23039 * @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.
23041 Roo.SplitBar.createProxy = function(dir){
23042 var proxy = new Roo.Element(document.createElement("div"));
23043 proxy.unselectable();
23044 var cls = 'x-splitbar-proxy';
23045 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23046 document.body.appendChild(proxy.dom);
23051 * @class Roo.SplitBar.BasicLayoutAdapter
23052 * Default Adapter. It assumes the splitter and resizing element are not positioned
23053 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23055 Roo.SplitBar.BasicLayoutAdapter = function(){
23058 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23059 // do nothing for now
23060 init : function(s){
23064 * Called before drag operations to get the current size of the resizing element.
23065 * @param {Roo.SplitBar} s The SplitBar using this adapter
23067 getElementSize : function(s){
23068 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23069 return s.resizingEl.getWidth();
23071 return s.resizingEl.getHeight();
23076 * Called after drag operations to set the size of the resizing element.
23077 * @param {Roo.SplitBar} s The SplitBar using this adapter
23078 * @param {Number} newSize The new size to set
23079 * @param {Function} onComplete A function to be invoked when resizing is complete
23081 setElementSize : function(s, newSize, onComplete){
23082 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23084 s.resizingEl.setWidth(newSize);
23086 onComplete(s, newSize);
23089 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23094 s.resizingEl.setHeight(newSize);
23096 onComplete(s, newSize);
23099 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23106 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23107 * @extends Roo.SplitBar.BasicLayoutAdapter
23108 * Adapter that moves the splitter element to align with the resized sizing element.
23109 * Used with an absolute positioned SplitBar.
23110 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23111 * document.body, make sure you assign an id to the body element.
23113 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23114 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23115 this.container = Roo.get(container);
23118 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23119 init : function(s){
23120 this.basic.init(s);
23123 getElementSize : function(s){
23124 return this.basic.getElementSize(s);
23127 setElementSize : function(s, newSize, onComplete){
23128 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23131 moveSplitter : function(s){
23132 var yes = Roo.SplitBar;
23133 switch(s.placement){
23135 s.el.setX(s.resizingEl.getRight());
23138 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23141 s.el.setY(s.resizingEl.getBottom());
23144 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23151 * Orientation constant - Create a vertical SplitBar
23155 Roo.SplitBar.VERTICAL = 1;
23158 * Orientation constant - Create a horizontal SplitBar
23162 Roo.SplitBar.HORIZONTAL = 2;
23165 * Placement constant - The resizing element is to the left of the splitter element
23169 Roo.SplitBar.LEFT = 1;
23172 * Placement constant - The resizing element is to the right of the splitter element
23176 Roo.SplitBar.RIGHT = 2;
23179 * Placement constant - The resizing element is positioned above the splitter element
23183 Roo.SplitBar.TOP = 3;
23186 * Placement constant - The resizing element is positioned under splitter element
23190 Roo.SplitBar.BOTTOM = 4;
23193 * Ext JS Library 1.1.1
23194 * Copyright(c) 2006-2007, Ext JS, LLC.
23196 * Originally Released Under LGPL - original licence link has changed is not relivant.
23199 * <script type="text/javascript">
23204 * @extends Roo.util.Observable
23205 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23206 * This class also supports single and multi selection modes. <br>
23207 * Create a data model bound view:
23209 var store = new Roo.data.Store(...);
23211 var view = new Roo.View("my-element",
23212 '<div id="{0}">{2} - {1}</div>', // auto create template
23214 singleSelect: true,
23215 selectedClass: "ydataview-selected",
23219 // listen for node click?
23220 view.on("click", function(vw, index, node, e){
23221 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23225 dataModel.load("foobar.xml");
23227 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23229 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23230 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23232 * Create a new View
23233 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
23234 * @param {String/DomHelper.Template} tpl The rendering template or a string to create a template with
23235 * @param {Object} config The config object
23237 Roo.View = function(container, tpl, config){
23238 this.el = Roo.get(container);
23239 if(typeof tpl == "string"){
23240 tpl = new Roo.Template(tpl);
23244 * The template used by this View
23245 * @type {Roo.DomHelper.Template}
23249 Roo.apply(this, config);
23254 * @event beforeclick
23255 * Fires before a click is processed. Returns false to cancel the default action.
23256 * @param {Roo.View} this
23257 * @param {Number} index The index of the target node
23258 * @param {HTMLElement} node The target node
23259 * @param {Roo.EventObject} e The raw event object
23261 "beforeclick" : true,
23264 * Fires when a template node is clicked.
23265 * @param {Roo.View} this
23266 * @param {Number} index The index of the target node
23267 * @param {HTMLElement} node The target node
23268 * @param {Roo.EventObject} e The raw event object
23273 * Fires when a template node is double clicked.
23274 * @param {Roo.View} this
23275 * @param {Number} index The index of the target node
23276 * @param {HTMLElement} node The target node
23277 * @param {Roo.EventObject} e The raw event object
23281 * @event contextmenu
23282 * Fires when a template node is right clicked.
23283 * @param {Roo.View} this
23284 * @param {Number} index The index of the target node
23285 * @param {HTMLElement} node The target node
23286 * @param {Roo.EventObject} e The raw event object
23288 "contextmenu" : true,
23290 * @event selectionchange
23291 * Fires when the selected nodes change.
23292 * @param {Roo.View} this
23293 * @param {Array} selections Array of the selected nodes
23295 "selectionchange" : true,
23298 * @event beforeselect
23299 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23300 * @param {Roo.View} this
23301 * @param {HTMLElement} node The node to be selected
23302 * @param {Array} selections Array of currently selected nodes
23304 "beforeselect" : true
23308 "click": this.onClick,
23309 "dblclick": this.onDblClick,
23310 "contextmenu": this.onContextMenu,
23314 this.selections = [];
23316 this.cmp = new Roo.CompositeElementLite([]);
23318 this.store = Roo.factory(this.store, Roo.data);
23319 this.setStore(this.store, true);
23321 Roo.View.superclass.constructor.call(this);
23324 Roo.extend(Roo.View, Roo.util.Observable, {
23326 * The css class to add to selected nodes
23327 * @type {Roo.DomHelper.Template}
23329 selectedClass : "x-view-selected",
23333 * Returns the element this view is bound to.
23334 * @return {Roo.Element}
23336 getEl : function(){
23341 * Refreshes the view.
23343 refresh : function(){
23345 this.clearSelections();
23346 this.el.update("");
23348 var records = this.store.getRange();
23349 if(records.length < 1){
23350 this.el.update(this.emptyText);
23353 for(var i = 0, len = records.length; i < len; i++){
23354 var data = this.prepareData(records[i].data, i, records[i]);
23355 html[html.length] = t.apply(data);
23357 this.el.update(html.join(""));
23358 this.nodes = this.el.dom.childNodes;
23359 this.updateIndexes(0);
23363 * Function to override to reformat the data that is sent to
23364 * the template for each node.
23365 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23366 * a JSON object for an UpdateManager bound view).
23368 prepareData : function(data){
23372 onUpdate : function(ds, record){
23373 this.clearSelections();
23374 var index = this.store.indexOf(record);
23375 var n = this.nodes[index];
23376 this.tpl.insertBefore(n, this.prepareData(record.data));
23377 n.parentNode.removeChild(n);
23378 this.updateIndexes(index, index);
23381 onAdd : function(ds, records, index){
23382 this.clearSelections();
23383 if(this.nodes.length == 0){
23387 var n = this.nodes[index];
23388 for(var i = 0, len = records.length; i < len; i++){
23389 var d = this.prepareData(records[i].data);
23391 this.tpl.insertBefore(n, d);
23393 this.tpl.append(this.el, d);
23396 this.updateIndexes(index);
23399 onRemove : function(ds, record, index){
23400 this.clearSelections();
23401 this.el.dom.removeChild(this.nodes[index]);
23402 this.updateIndexes(index);
23406 * Refresh an individual node.
23407 * @param {Number} index
23409 refreshNode : function(index){
23410 this.onUpdate(this.store, this.store.getAt(index));
23413 updateIndexes : function(startIndex, endIndex){
23414 var ns = this.nodes;
23415 startIndex = startIndex || 0;
23416 endIndex = endIndex || ns.length - 1;
23417 for(var i = startIndex; i <= endIndex; i++){
23418 ns[i].nodeIndex = i;
23423 * Changes the data store this view uses and refresh the view.
23424 * @param {Store} store
23426 setStore : function(store, initial){
23427 if(!initial && this.store){
23428 this.store.un("datachanged", this.refresh);
23429 this.store.un("add", this.onAdd);
23430 this.store.un("remove", this.onRemove);
23431 this.store.un("update", this.onUpdate);
23432 this.store.un("clear", this.refresh);
23436 store.on("datachanged", this.refresh, this);
23437 store.on("add", this.onAdd, this);
23438 store.on("remove", this.onRemove, this);
23439 store.on("update", this.onUpdate, this);
23440 store.on("clear", this.refresh, this);
23449 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23450 * @param {HTMLElement} node
23451 * @return {HTMLElement} The template node
23453 findItemFromChild : function(node){
23454 var el = this.el.dom;
23455 if(!node || node.parentNode == el){
23458 var p = node.parentNode;
23459 while(p && p != el){
23460 if(p.parentNode == el){
23469 onClick : function(e){
23470 var item = this.findItemFromChild(e.getTarget());
23472 var index = this.indexOf(item);
23473 if(this.onItemClick(item, index, e) !== false){
23474 this.fireEvent("click", this, index, item, e);
23477 this.clearSelections();
23482 onContextMenu : function(e){
23483 var item = this.findItemFromChild(e.getTarget());
23485 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23490 onDblClick : function(e){
23491 var item = this.findItemFromChild(e.getTarget());
23493 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23497 onItemClick : function(item, index, e){
23498 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23501 if(this.multiSelect || this.singleSelect){
23502 if(this.multiSelect && e.shiftKey && this.lastSelection){
23503 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23505 this.select(item, this.multiSelect && e.ctrlKey);
23506 this.lastSelection = item;
23508 e.preventDefault();
23514 * Get the number of selected nodes.
23517 getSelectionCount : function(){
23518 return this.selections.length;
23522 * Get the currently selected nodes.
23523 * @return {Array} An array of HTMLElements
23525 getSelectedNodes : function(){
23526 return this.selections;
23530 * Get the indexes of the selected nodes.
23533 getSelectedIndexes : function(){
23534 var indexes = [], s = this.selections;
23535 for(var i = 0, len = s.length; i < len; i++){
23536 indexes.push(s[i].nodeIndex);
23542 * Clear all selections
23543 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23545 clearSelections : function(suppressEvent){
23546 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23547 this.cmp.elements = this.selections;
23548 this.cmp.removeClass(this.selectedClass);
23549 this.selections = [];
23550 if(!suppressEvent){
23551 this.fireEvent("selectionchange", this, this.selections);
23557 * Returns true if the passed node is selected
23558 * @param {HTMLElement/Number} node The node or node index
23559 * @return {Boolean}
23561 isSelected : function(node){
23562 var s = this.selections;
23566 node = this.getNode(node);
23567 return s.indexOf(node) !== -1;
23572 * @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
23573 * @param {Boolean} keepExisting (optional) true to keep existing selections
23574 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23576 select : function(nodeInfo, keepExisting, suppressEvent){
23577 if(nodeInfo instanceof Array){
23579 this.clearSelections(true);
23581 for(var i = 0, len = nodeInfo.length; i < len; i++){
23582 this.select(nodeInfo[i], true, true);
23585 var node = this.getNode(nodeInfo);
23586 if(node && !this.isSelected(node)){
23588 this.clearSelections(true);
23590 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23591 Roo.fly(node).addClass(this.selectedClass);
23592 this.selections.push(node);
23593 if(!suppressEvent){
23594 this.fireEvent("selectionchange", this, this.selections);
23602 * Gets a template node.
23603 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23604 * @return {HTMLElement} The node or null if it wasn't found
23606 getNode : function(nodeInfo){
23607 if(typeof nodeInfo == "string"){
23608 return document.getElementById(nodeInfo);
23609 }else if(typeof nodeInfo == "number"){
23610 return this.nodes[nodeInfo];
23616 * Gets a range template nodes.
23617 * @param {Number} startIndex
23618 * @param {Number} endIndex
23619 * @return {Array} An array of nodes
23621 getNodes : function(start, end){
23622 var ns = this.nodes;
23623 start = start || 0;
23624 end = typeof end == "undefined" ? ns.length - 1 : end;
23627 for(var i = start; i <= end; i++){
23631 for(var i = start; i >= end; i--){
23639 * Finds the index of the passed node
23640 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23641 * @return {Number} The index of the node or -1
23643 indexOf : function(node){
23644 node = this.getNode(node);
23645 if(typeof node.nodeIndex == "number"){
23646 return node.nodeIndex;
23648 var ns = this.nodes;
23649 for(var i = 0, len = ns.length; i < len; i++){
23659 * Ext JS Library 1.1.1
23660 * Copyright(c) 2006-2007, Ext JS, LLC.
23662 * Originally Released Under LGPL - original licence link has changed is not relivant.
23665 * <script type="text/javascript">
23669 * @class Roo.JsonView
23670 * @extends Roo.View
23671 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23673 var view = new Roo.JsonView("my-element",
23674 '<div id="{id}">{foo} - {bar}</div>', // auto create template
23675 { multiSelect: true, jsonRoot: "data" }
23678 // listen for node click?
23679 view.on("click", function(vw, index, node, e){
23680 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23683 // direct load of JSON data
23684 view.load("foobar.php");
23686 // Example from my blog list
23687 var tpl = new Roo.Template(
23688 '<div class="entry">' +
23689 '<a class="entry-title" href="{link}">{title}</a>' +
23690 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23691 "</div><hr />"
23694 var moreView = new Roo.JsonView("entry-list", tpl, {
23697 moreView.on("beforerender", this.sortEntries, this);
23699 url: "/blog/get-posts.php",
23700 params: "allposts=true",
23701 text: "Loading Blog Entries..."
23705 * Create a new JsonView
23706 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
23707 * @param {Template} tpl The rendering template
23708 * @param {Object} config The config object
23710 Roo.JsonView = function(container, tpl, config){
23711 Roo.JsonView.superclass.constructor.call(this, container, tpl, config);
23713 var um = this.el.getUpdateManager();
23714 um.setRenderer(this);
23715 um.on("update", this.onLoad, this);
23716 um.on("failure", this.onLoadException, this);
23719 * @event beforerender
23720 * Fires before rendering of the downloaded JSON data.
23721 * @param {Roo.JsonView} this
23722 * @param {Object} data The JSON data loaded
23726 * Fires when data is loaded.
23727 * @param {Roo.JsonView} this
23728 * @param {Object} data The JSON data loaded
23729 * @param {Object} response The raw Connect response object
23732 * @event loadexception
23733 * Fires when loading fails.
23734 * @param {Roo.JsonView} this
23735 * @param {Object} response The raw Connect response object
23738 'beforerender' : true,
23740 'loadexception' : true
23743 Roo.extend(Roo.JsonView, Roo.View, {
23745 * The root property in the loaded JSON object that contains the data
23751 * Refreshes the view.
23753 refresh : function(){
23754 this.clearSelections();
23755 this.el.update("");
23757 var o = this.jsonData;
23758 if(o && o.length > 0){
23759 for(var i = 0, len = o.length; i < len; i++){
23760 var data = this.prepareData(o[i], i, o);
23761 html[html.length] = this.tpl.apply(data);
23764 html.push(this.emptyText);
23766 this.el.update(html.join(""));
23767 this.nodes = this.el.dom.childNodes;
23768 this.updateIndexes(0);
23772 * 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.
23773 * @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:
23776 url: "your-url.php",
23777 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
23778 callback: yourFunction,
23779 scope: yourObject, //(optional scope)
23782 text: "Loading...",
23787 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
23788 * 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.
23789 * @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}
23790 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
23791 * @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.
23794 var um = this.el.getUpdateManager();
23795 um.update.apply(um, arguments);
23798 render : function(el, response){
23799 this.clearSelections();
23800 this.el.update("");
23803 o = Roo.util.JSON.decode(response.responseText);
23806 o = /** eval:var:o */ eval("o." + this.jsonRoot);
23811 * The current JSON data or null
23814 this.beforeRender();
23819 * Get the number of records in the current JSON dataset
23822 getCount : function(){
23823 return this.jsonData ? this.jsonData.length : 0;
23827 * Returns the JSON object for the specified node(s)
23828 * @param {HTMLElement/Array} node The node or an array of nodes
23829 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
23830 * you get the JSON object for the node
23832 getNodeData : function(node){
23833 if(node instanceof Array){
23835 for(var i = 0, len = node.length; i < len; i++){
23836 data.push(this.getNodeData(node[i]));
23840 return this.jsonData[this.indexOf(node)] || null;
23843 beforeRender : function(){
23844 this.snapshot = this.jsonData;
23846 this.sort.apply(this, this.sortInfo);
23848 this.fireEvent("beforerender", this, this.jsonData);
23851 onLoad : function(el, o){
23852 this.fireEvent("load", this, this.jsonData, o);
23855 onLoadException : function(el, o){
23856 this.fireEvent("loadexception", this, o);
23860 * Filter the data by a specific property.
23861 * @param {String} property A property on your JSON objects
23862 * @param {String/RegExp} value Either string that the property values
23863 * should start with, or a RegExp to test against the property
23865 filter : function(property, value){
23868 var ss = this.snapshot;
23869 if(typeof value == "string"){
23870 var vlen = value.length;
23872 this.clearFilter();
23875 value = value.toLowerCase();
23876 for(var i = 0, len = ss.length; i < len; i++){
23878 if(o[property].substr(0, vlen).toLowerCase() == value){
23882 } else if(value.exec){ // regex?
23883 for(var i = 0, len = ss.length; i < len; i++){
23885 if(value.test(o[property])){
23892 this.jsonData = data;
23898 * Filter by a function. The passed function will be called with each
23899 * object in the current dataset. If the function returns true the value is kept,
23900 * otherwise it is filtered.
23901 * @param {Function} fn
23902 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
23904 filterBy : function(fn, scope){
23907 var ss = this.snapshot;
23908 for(var i = 0, len = ss.length; i < len; i++){
23910 if(fn.call(scope || this, o)){
23914 this.jsonData = data;
23920 * Clears the current filter.
23922 clearFilter : function(){
23923 if(this.snapshot && this.jsonData != this.snapshot){
23924 this.jsonData = this.snapshot;
23931 * Sorts the data for this view and refreshes it.
23932 * @param {String} property A property on your JSON objects to sort on
23933 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
23934 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
23936 sort : function(property, dir, sortType){
23937 this.sortInfo = Array.prototype.slice.call(arguments, 0);
23940 var dsc = dir && dir.toLowerCase() == "desc";
23941 var f = function(o1, o2){
23942 var v1 = sortType ? sortType(o1[p]) : o1[p];
23943 var v2 = sortType ? sortType(o2[p]) : o2[p];
23946 return dsc ? +1 : -1;
23947 } else if(v1 > v2){
23948 return dsc ? -1 : +1;
23953 this.jsonData.sort(f);
23955 if(this.jsonData != this.snapshot){
23956 this.snapshot.sort(f);
23962 * Ext JS Library 1.1.1
23963 * Copyright(c) 2006-2007, Ext JS, LLC.
23965 * Originally Released Under LGPL - original licence link has changed is not relivant.
23968 * <script type="text/javascript">
23973 * @class Roo.ColorPalette
23974 * @extends Roo.Component
23975 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
23976 * Here's an example of typical usage:
23978 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
23979 cp.render('my-div');
23981 cp.on('select', function(palette, selColor){
23982 // do something with selColor
23986 * Create a new ColorPalette
23987 * @param {Object} config The config object
23989 Roo.ColorPalette = function(config){
23990 Roo.ColorPalette.superclass.constructor.call(this, config);
23994 * Fires when a color is selected
23995 * @param {ColorPalette} this
23996 * @param {String} color The 6-digit color hex code (without the # symbol)
24002 this.on("select", this.handler, this.scope, true);
24005 Roo.extend(Roo.ColorPalette, Roo.Component, {
24007 * @cfg {String} itemCls
24008 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24010 itemCls : "x-color-palette",
24012 * @cfg {String} value
24013 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24014 * the hex codes are case-sensitive.
24017 clickEvent:'click',
24019 ctype: "Roo.ColorPalette",
24022 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24024 allowReselect : false,
24027 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24028 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24029 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24030 * of colors with the width setting until the box is symmetrical.</p>
24031 * <p>You can override individual colors if needed:</p>
24033 var cp = new Roo.ColorPalette();
24034 cp.colors[0] = "FF0000"; // change the first box to red
24037 Or you can provide a custom array of your own for complete control:
24039 var cp = new Roo.ColorPalette();
24040 cp.colors = ["000000", "993300", "333300"];
24045 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24046 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24047 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24048 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24049 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24053 onRender : function(container, position){
24054 var t = new Roo.MasterTemplate(
24055 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24057 var c = this.colors;
24058 for(var i = 0, len = c.length; i < len; i++){
24061 var el = document.createElement("div");
24062 el.className = this.itemCls;
24064 container.dom.insertBefore(el, position);
24065 this.el = Roo.get(el);
24066 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24067 if(this.clickEvent != 'click'){
24068 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24073 afterRender : function(){
24074 Roo.ColorPalette.superclass.afterRender.call(this);
24076 var s = this.value;
24083 handleClick : function(e, t){
24084 e.preventDefault();
24085 if(!this.disabled){
24086 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24087 this.select(c.toUpperCase());
24092 * Selects the specified color in the palette (fires the select event)
24093 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24095 select : function(color){
24096 color = color.replace("#", "");
24097 if(color != this.value || this.allowReselect){
24100 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24102 el.child("a.color-"+color).addClass("x-color-palette-sel");
24103 this.value = color;
24104 this.fireEvent("select", this, color);
24109 * Ext JS Library 1.1.1
24110 * Copyright(c) 2006-2007, Ext JS, LLC.
24112 * Originally Released Under LGPL - original licence link has changed is not relivant.
24115 * <script type="text/javascript">
24119 * @class Roo.DatePicker
24120 * @extends Roo.Component
24121 * Simple date picker class.
24123 * Create a new DatePicker
24124 * @param {Object} config The config object
24126 Roo.DatePicker = function(config){
24127 Roo.DatePicker.superclass.constructor.call(this, config);
24129 this.value = config && config.value ?
24130 config.value.clearTime() : new Date().clearTime();
24135 * Fires when a date is selected
24136 * @param {DatePicker} this
24137 * @param {Date} date The selected date
24143 this.on("select", this.handler, this.scope || this);
24145 // build the disabledDatesRE
24146 if(!this.disabledDatesRE && this.disabledDates){
24147 var dd = this.disabledDates;
24149 for(var i = 0; i < dd.length; i++){
24151 if(i != dd.length-1) re += "|";
24153 this.disabledDatesRE = new RegExp(re + ")");
24157 Roo.extend(Roo.DatePicker, Roo.Component, {
24159 * @cfg {String} todayText
24160 * The text to display on the button that selects the current date (defaults to "Today")
24162 todayText : "Today",
24164 * @cfg {String} okText
24165 * The text to display on the ok button
24167 okText : " OK ", //   to give the user extra clicking room
24169 * @cfg {String} cancelText
24170 * The text to display on the cancel button
24172 cancelText : "Cancel",
24174 * @cfg {String} todayTip
24175 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24177 todayTip : "{0} (Spacebar)",
24179 * @cfg {Date} minDate
24180 * Minimum allowable date (JavaScript date object, defaults to null)
24184 * @cfg {Date} maxDate
24185 * Maximum allowable date (JavaScript date object, defaults to null)
24189 * @cfg {String} minText
24190 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24192 minText : "This date is before the minimum date",
24194 * @cfg {String} maxText
24195 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24197 maxText : "This date is after the maximum date",
24199 * @cfg {String} format
24200 * The default date format string which can be overriden for localization support. The format must be
24201 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24205 * @cfg {Array} disabledDays
24206 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24208 disabledDays : null,
24210 * @cfg {String} disabledDaysText
24211 * The tooltip to display when the date falls on a disabled day (defaults to "")
24213 disabledDaysText : "",
24215 * @cfg {RegExp} disabledDatesRE
24216 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24218 disabledDatesRE : null,
24220 * @cfg {String} disabledDatesText
24221 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24223 disabledDatesText : "",
24225 * @cfg {Boolean} constrainToViewport
24226 * True to constrain the date picker to the viewport (defaults to true)
24228 constrainToViewport : true,
24230 * @cfg {Array} monthNames
24231 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24233 monthNames : Date.monthNames,
24235 * @cfg {Array} dayNames
24236 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24238 dayNames : Date.dayNames,
24240 * @cfg {String} nextText
24241 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24243 nextText: 'Next Month (Control+Right)',
24245 * @cfg {String} prevText
24246 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24248 prevText: 'Previous Month (Control+Left)',
24250 * @cfg {String} monthYearText
24251 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24253 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24255 * @cfg {Number} startDay
24256 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24260 * @cfg {Bool} showClear
24261 * Show a clear button (usefull for date form elements that can be blank.)
24267 * Sets the value of the date field
24268 * @param {Date} value The date to set
24270 setValue : function(value){
24271 var old = this.value;
24272 this.value = value.clearTime(true);
24274 this.update(this.value);
24279 * Gets the current selected value of the date field
24280 * @return {Date} The selected date
24282 getValue : function(){
24287 focus : function(){
24289 this.update(this.activeDate);
24294 onRender : function(container, position){
24296 '<table cellspacing="0">',
24297 '<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>',
24298 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24299 var dn = this.dayNames;
24300 for(var i = 0; i < 7; i++){
24301 var d = this.startDay+i;
24305 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24307 m[m.length] = "</tr></thead><tbody><tr>";
24308 for(var i = 0; i < 42; i++) {
24309 if(i % 7 == 0 && i != 0){
24310 m[m.length] = "</tr><tr>";
24312 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24314 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24315 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24317 var el = document.createElement("div");
24318 el.className = "x-date-picker";
24319 el.innerHTML = m.join("");
24321 container.dom.insertBefore(el, position);
24323 this.el = Roo.get(el);
24324 this.eventEl = Roo.get(el.firstChild);
24326 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24327 handler: this.showPrevMonth,
24329 preventDefault:true,
24333 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24334 handler: this.showNextMonth,
24336 preventDefault:true,
24340 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24342 this.monthPicker = this.el.down('div.x-date-mp');
24343 this.monthPicker.enableDisplayMode('block');
24345 var kn = new Roo.KeyNav(this.eventEl, {
24346 "left" : function(e){
24348 this.showPrevMonth() :
24349 this.update(this.activeDate.add("d", -1));
24352 "right" : function(e){
24354 this.showNextMonth() :
24355 this.update(this.activeDate.add("d", 1));
24358 "up" : function(e){
24360 this.showNextYear() :
24361 this.update(this.activeDate.add("d", -7));
24364 "down" : function(e){
24366 this.showPrevYear() :
24367 this.update(this.activeDate.add("d", 7));
24370 "pageUp" : function(e){
24371 this.showNextMonth();
24374 "pageDown" : function(e){
24375 this.showPrevMonth();
24378 "enter" : function(e){
24379 e.stopPropagation();
24386 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24388 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24390 this.el.unselectable();
24392 this.cells = this.el.select("table.x-date-inner tbody td");
24393 this.textNodes = this.el.query("table.x-date-inner tbody span");
24395 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24397 tooltip: this.monthYearText
24400 this.mbtn.on('click', this.showMonthPicker, this);
24401 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24404 var today = (new Date()).dateFormat(this.format);
24406 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24408 text: String.format(this.todayText, today),
24409 tooltip: String.format(this.todayTip, today),
24410 handler: this.selectToday,
24414 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24417 if (this.showClear) {
24419 baseTb.add( new Roo.Toolbar.Fill());
24422 cls: 'x-btn-icon x-btn-clear',
24423 handler: function() {
24425 this.fireEvent("select", this, '');
24435 this.update(this.value);
24438 createMonthPicker : function(){
24439 if(!this.monthPicker.dom.firstChild){
24440 var buf = ['<table border="0" cellspacing="0">'];
24441 for(var i = 0; i < 6; i++){
24443 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24444 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24446 '<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>' :
24447 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24451 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24453 '</button><button type="button" class="x-date-mp-cancel">',
24455 '</button></td></tr>',
24458 this.monthPicker.update(buf.join(''));
24459 this.monthPicker.on('click', this.onMonthClick, this);
24460 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24462 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24463 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24465 this.mpMonths.each(function(m, a, i){
24468 m.dom.xmonth = 5 + Math.round(i * .5);
24470 m.dom.xmonth = Math.round((i-1) * .5);
24476 showMonthPicker : function(){
24477 this.createMonthPicker();
24478 var size = this.el.getSize();
24479 this.monthPicker.setSize(size);
24480 this.monthPicker.child('table').setSize(size);
24482 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24483 this.updateMPMonth(this.mpSelMonth);
24484 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24485 this.updateMPYear(this.mpSelYear);
24487 this.monthPicker.slideIn('t', {duration:.2});
24490 updateMPYear : function(y){
24492 var ys = this.mpYears.elements;
24493 for(var i = 1; i <= 10; i++){
24494 var td = ys[i-1], y2;
24496 y2 = y + Math.round(i * .5);
24497 td.firstChild.innerHTML = y2;
24500 y2 = y - (5-Math.round(i * .5));
24501 td.firstChild.innerHTML = y2;
24504 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24508 updateMPMonth : function(sm){
24509 this.mpMonths.each(function(m, a, i){
24510 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24514 selectMPMonth: function(m){
24518 onMonthClick : function(e, t){
24520 var el = new Roo.Element(t), pn;
24521 if(el.is('button.x-date-mp-cancel')){
24522 this.hideMonthPicker();
24524 else if(el.is('button.x-date-mp-ok')){
24525 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24526 this.hideMonthPicker();
24528 else if(pn = el.up('td.x-date-mp-month', 2)){
24529 this.mpMonths.removeClass('x-date-mp-sel');
24530 pn.addClass('x-date-mp-sel');
24531 this.mpSelMonth = pn.dom.xmonth;
24533 else if(pn = el.up('td.x-date-mp-year', 2)){
24534 this.mpYears.removeClass('x-date-mp-sel');
24535 pn.addClass('x-date-mp-sel');
24536 this.mpSelYear = pn.dom.xyear;
24538 else if(el.is('a.x-date-mp-prev')){
24539 this.updateMPYear(this.mpyear-10);
24541 else if(el.is('a.x-date-mp-next')){
24542 this.updateMPYear(this.mpyear+10);
24546 onMonthDblClick : function(e, t){
24548 var el = new Roo.Element(t), pn;
24549 if(pn = el.up('td.x-date-mp-month', 2)){
24550 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24551 this.hideMonthPicker();
24553 else if(pn = el.up('td.x-date-mp-year', 2)){
24554 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24555 this.hideMonthPicker();
24559 hideMonthPicker : function(disableAnim){
24560 if(this.monthPicker){
24561 if(disableAnim === true){
24562 this.monthPicker.hide();
24564 this.monthPicker.slideOut('t', {duration:.2});
24570 showPrevMonth : function(e){
24571 this.update(this.activeDate.add("mo", -1));
24575 showNextMonth : function(e){
24576 this.update(this.activeDate.add("mo", 1));
24580 showPrevYear : function(){
24581 this.update(this.activeDate.add("y", -1));
24585 showNextYear : function(){
24586 this.update(this.activeDate.add("y", 1));
24590 handleMouseWheel : function(e){
24591 var delta = e.getWheelDelta();
24593 this.showPrevMonth();
24595 } else if(delta < 0){
24596 this.showNextMonth();
24602 handleDateClick : function(e, t){
24604 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24605 this.setValue(new Date(t.dateValue));
24606 this.fireEvent("select", this, this.value);
24611 selectToday : function(){
24612 this.setValue(new Date().clearTime());
24613 this.fireEvent("select", this, this.value);
24617 update : function(date){
24618 var vd = this.activeDate;
24619 this.activeDate = date;
24621 var t = date.getTime();
24622 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24623 this.cells.removeClass("x-date-selected");
24624 this.cells.each(function(c){
24625 if(c.dom.firstChild.dateValue == t){
24626 c.addClass("x-date-selected");
24627 setTimeout(function(){
24628 try{c.dom.firstChild.focus();}catch(e){}
24636 var days = date.getDaysInMonth();
24637 var firstOfMonth = date.getFirstDateOfMonth();
24638 var startingPos = firstOfMonth.getDay()-this.startDay;
24640 if(startingPos <= this.startDay){
24644 var pm = date.add("mo", -1);
24645 var prevStart = pm.getDaysInMonth()-startingPos;
24647 var cells = this.cells.elements;
24648 var textEls = this.textNodes;
24649 days += startingPos;
24651 // convert everything to numbers so it's fast
24652 var day = 86400000;
24653 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24654 var today = new Date().clearTime().getTime();
24655 var sel = date.clearTime().getTime();
24656 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24657 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24658 var ddMatch = this.disabledDatesRE;
24659 var ddText = this.disabledDatesText;
24660 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24661 var ddaysText = this.disabledDaysText;
24662 var format = this.format;
24664 var setCellClass = function(cal, cell){
24666 var t = d.getTime();
24667 cell.firstChild.dateValue = t;
24669 cell.className += " x-date-today";
24670 cell.title = cal.todayText;
24673 cell.className += " x-date-selected";
24674 setTimeout(function(){
24675 try{cell.firstChild.focus();}catch(e){}
24680 cell.className = " x-date-disabled";
24681 cell.title = cal.minText;
24685 cell.className = " x-date-disabled";
24686 cell.title = cal.maxText;
24690 if(ddays.indexOf(d.getDay()) != -1){
24691 cell.title = ddaysText;
24692 cell.className = " x-date-disabled";
24695 if(ddMatch && format){
24696 var fvalue = d.dateFormat(format);
24697 if(ddMatch.test(fvalue)){
24698 cell.title = ddText.replace("%0", fvalue);
24699 cell.className = " x-date-disabled";
24705 for(; i < startingPos; i++) {
24706 textEls[i].innerHTML = (++prevStart);
24707 d.setDate(d.getDate()+1);
24708 cells[i].className = "x-date-prevday";
24709 setCellClass(this, cells[i]);
24711 for(; i < days; i++){
24712 intDay = i - startingPos + 1;
24713 textEls[i].innerHTML = (intDay);
24714 d.setDate(d.getDate()+1);
24715 cells[i].className = "x-date-active";
24716 setCellClass(this, cells[i]);
24719 for(; i < 42; i++) {
24720 textEls[i].innerHTML = (++extraDays);
24721 d.setDate(d.getDate()+1);
24722 cells[i].className = "x-date-nextday";
24723 setCellClass(this, cells[i]);
24726 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
24728 if(!this.internalRender){
24729 var main = this.el.dom.firstChild;
24730 var w = main.offsetWidth;
24731 this.el.setWidth(w + this.el.getBorderWidth("lr"));
24732 Roo.fly(main).setWidth(w);
24733 this.internalRender = true;
24734 // opera does not respect the auto grow header center column
24735 // then, after it gets a width opera refuses to recalculate
24736 // without a second pass
24737 if(Roo.isOpera && !this.secondPass){
24738 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
24739 this.secondPass = true;
24740 this.update.defer(10, this, [date]);
24746 * Ext JS Library 1.1.1
24747 * Copyright(c) 2006-2007, Ext JS, LLC.
24749 * Originally Released Under LGPL - original licence link has changed is not relivant.
24752 * <script type="text/javascript">
24755 * @class Roo.TabPanel
24756 * @extends Roo.util.Observable
24757 * A lightweight tab container.
24761 // basic tabs 1, built from existing content
24762 var tabs = new Roo.TabPanel("tabs1");
24763 tabs.addTab("script", "View Script");
24764 tabs.addTab("markup", "View Markup");
24765 tabs.activate("script");
24767 // more advanced tabs, built from javascript
24768 var jtabs = new Roo.TabPanel("jtabs");
24769 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
24771 // set up the UpdateManager
24772 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
24773 var updater = tab2.getUpdateManager();
24774 updater.setDefaultUrl("ajax1.htm");
24775 tab2.on('activate', updater.refresh, updater, true);
24777 // Use setUrl for Ajax loading
24778 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
24779 tab3.setUrl("ajax2.htm", null, true);
24782 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
24785 jtabs.activate("jtabs-1");
24788 * Create a new TabPanel.
24789 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
24790 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
24792 Roo.TabPanel = function(container, config){
24794 * The container element for this TabPanel.
24795 * @type Roo.Element
24797 this.el = Roo.get(container, true);
24799 if(typeof config == "boolean"){
24800 this.tabPosition = config ? "bottom" : "top";
24802 Roo.apply(this, config);
24805 if(this.tabPosition == "bottom"){
24806 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24807 this.el.addClass("x-tabs-bottom");
24809 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
24810 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
24811 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
24813 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
24815 if(this.tabPosition != "bottom"){
24816 /** The body element that contains {@link Roo.TabPanelItem} bodies.
24817 * @type Roo.Element
24819 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24820 this.el.addClass("x-tabs-top");
24824 this.bodyEl.setStyle("position", "relative");
24826 this.active = null;
24827 this.activateDelegate = this.activate.createDelegate(this);
24832 * Fires when the active tab changes
24833 * @param {Roo.TabPanel} this
24834 * @param {Roo.TabPanelItem} activePanel The new active tab
24838 * @event beforetabchange
24839 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
24840 * @param {Roo.TabPanel} this
24841 * @param {Object} e Set cancel to true on this object to cancel the tab change
24842 * @param {Roo.TabPanelItem} tab The tab being changed to
24844 "beforetabchange" : true
24847 Roo.EventManager.onWindowResize(this.onResize, this);
24848 this.cpad = this.el.getPadding("lr");
24849 this.hiddenCount = 0;
24851 Roo.TabPanel.superclass.constructor.call(this);
24854 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
24856 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
24858 tabPosition : "top",
24860 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
24862 currentTabWidth : 0,
24864 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
24868 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
24872 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
24874 preferredTabWidth : 175,
24876 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
24878 resizeTabs : false,
24880 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
24882 monitorResize : true,
24885 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
24886 * @param {String} id The id of the div to use <b>or create</b>
24887 * @param {String} text The text for the tab
24888 * @param {String} content (optional) Content to put in the TabPanelItem body
24889 * @param {Boolean} closable (optional) True to create a close icon on the tab
24890 * @return {Roo.TabPanelItem} The created TabPanelItem
24892 addTab : function(id, text, content, closable){
24893 var item = new Roo.TabPanelItem(this, id, text, closable);
24894 this.addTabItem(item);
24896 item.setContent(content);
24902 * Returns the {@link Roo.TabPanelItem} with the specified id/index
24903 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
24904 * @return {Roo.TabPanelItem}
24906 getTab : function(id){
24907 return this.items[id];
24911 * Hides the {@link Roo.TabPanelItem} with the specified id/index
24912 * @param {String/Number} id The id or index of the TabPanelItem to hide.
24914 hideTab : function(id){
24915 var t = this.items[id];
24918 this.hiddenCount++;
24919 this.autoSizeTabs();
24924 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
24925 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
24927 unhideTab : function(id){
24928 var t = this.items[id];
24930 t.setHidden(false);
24931 this.hiddenCount--;
24932 this.autoSizeTabs();
24937 * Adds an existing {@link Roo.TabPanelItem}.
24938 * @param {Roo.TabPanelItem} item The TabPanelItem to add
24940 addTabItem : function(item){
24941 this.items[item.id] = item;
24942 this.items.push(item);
24943 if(this.resizeTabs){
24944 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
24945 this.autoSizeTabs();
24952 * Removes a {@link Roo.TabPanelItem}.
24953 * @param {String/Number} id The id or index of the TabPanelItem to remove.
24955 removeTab : function(id){
24956 var items = this.items;
24957 var tab = items[id];
24959 var index = items.indexOf(tab);
24960 if(this.active == tab && items.length > 1){
24961 var newTab = this.getNextAvailable(index);
24962 if(newTab)newTab.activate();
24964 this.stripEl.dom.removeChild(tab.pnode.dom);
24965 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
24966 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
24968 items.splice(index, 1);
24969 delete this.items[tab.id];
24970 tab.fireEvent("close", tab);
24971 tab.purgeListeners();
24972 this.autoSizeTabs();
24975 getNextAvailable : function(start){
24976 var items = this.items;
24978 // look for a next tab that will slide over to
24979 // replace the one being removed
24980 while(index < items.length){
24981 var item = items[++index];
24982 if(item && !item.isHidden()){
24986 // if one isn't found select the previous tab (on the left)
24989 var item = items[--index];
24990 if(item && !item.isHidden()){
24998 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
24999 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25001 disableTab : function(id){
25002 var tab = this.items[id];
25003 if(tab && this.active != tab){
25009 * Enables a {@link Roo.TabPanelItem} that is disabled.
25010 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25012 enableTab : function(id){
25013 var tab = this.items[id];
25018 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25019 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25020 * @return {Roo.TabPanelItem} The TabPanelItem.
25022 activate : function(id){
25023 var tab = this.items[id];
25027 if(tab == this.active || tab.disabled){
25031 this.fireEvent("beforetabchange", this, e, tab);
25032 if(e.cancel !== true && !tab.disabled){
25034 this.active.hide();
25036 this.active = this.items[id];
25037 this.active.show();
25038 this.fireEvent("tabchange", this, this.active);
25044 * Gets the active {@link Roo.TabPanelItem}.
25045 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25047 getActiveTab : function(){
25048 return this.active;
25052 * Updates the tab body element to fit the height of the container element
25053 * for overflow scrolling
25054 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25056 syncHeight : function(targetHeight){
25057 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25058 var bm = this.bodyEl.getMargins();
25059 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25060 this.bodyEl.setHeight(newHeight);
25064 onResize : function(){
25065 if(this.monitorResize){
25066 this.autoSizeTabs();
25071 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25073 beginUpdate : function(){
25074 this.updating = true;
25078 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25080 endUpdate : function(){
25081 this.updating = false;
25082 this.autoSizeTabs();
25086 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25088 autoSizeTabs : function(){
25089 var count = this.items.length;
25090 var vcount = count - this.hiddenCount;
25091 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25092 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25093 var availWidth = Math.floor(w / vcount);
25094 var b = this.stripBody;
25095 if(b.getWidth() > w){
25096 var tabs = this.items;
25097 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25098 if(availWidth < this.minTabWidth){
25099 /*if(!this.sleft){ // incomplete scrolling code
25100 this.createScrollButtons();
25103 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25106 if(this.currentTabWidth < this.preferredTabWidth){
25107 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25113 * Returns the number of tabs in this TabPanel.
25116 getCount : function(){
25117 return this.items.length;
25121 * Resizes all the tabs to the passed width
25122 * @param {Number} The new width
25124 setTabWidth : function(width){
25125 this.currentTabWidth = width;
25126 for(var i = 0, len = this.items.length; i < len; i++) {
25127 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25132 * Destroys this TabPanel
25133 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25135 destroy : function(removeEl){
25136 Roo.EventManager.removeResizeListener(this.onResize, this);
25137 for(var i = 0, len = this.items.length; i < len; i++){
25138 this.items[i].purgeListeners();
25140 if(removeEl === true){
25141 this.el.update("");
25148 * @class Roo.TabPanelItem
25149 * @extends Roo.util.Observable
25150 * Represents an individual item (tab plus body) in a TabPanel.
25151 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25152 * @param {String} id The id of this TabPanelItem
25153 * @param {String} text The text for the tab of this TabPanelItem
25154 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25156 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25158 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25159 * @type Roo.TabPanel
25161 this.tabPanel = tabPanel;
25163 * The id for this TabPanelItem
25168 this.disabled = false;
25172 this.loaded = false;
25173 this.closable = closable;
25176 * The body element for this TabPanelItem.
25177 * @type Roo.Element
25179 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25180 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25181 this.bodyEl.setStyle("display", "block");
25182 this.bodyEl.setStyle("zoom", "1");
25185 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25187 this.el = Roo.get(els.el, true);
25188 this.inner = Roo.get(els.inner, true);
25189 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25190 this.pnode = Roo.get(els.el.parentNode, true);
25191 this.el.on("mousedown", this.onTabMouseDown, this);
25192 this.el.on("click", this.onTabClick, this);
25195 var c = Roo.get(els.close, true);
25196 c.dom.title = this.closeText;
25197 c.addClassOnOver("close-over");
25198 c.on("click", this.closeClick, this);
25204 * Fires when this tab becomes the active tab.
25205 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25206 * @param {Roo.TabPanelItem} this
25210 * @event beforeclose
25211 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25212 * @param {Roo.TabPanelItem} this
25213 * @param {Object} e Set cancel to true on this object to cancel the close.
25215 "beforeclose": true,
25218 * Fires when this tab is closed.
25219 * @param {Roo.TabPanelItem} this
25223 * @event deactivate
25224 * Fires when this tab is no longer the active tab.
25225 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25226 * @param {Roo.TabPanelItem} this
25228 "deactivate" : true
25230 this.hidden = false;
25232 Roo.TabPanelItem.superclass.constructor.call(this);
25235 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25236 purgeListeners : function(){
25237 Roo.util.Observable.prototype.purgeListeners.call(this);
25238 this.el.removeAllListeners();
25241 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25244 this.pnode.addClass("on");
25247 this.tabPanel.stripWrap.repaint();
25249 this.fireEvent("activate", this.tabPanel, this);
25253 * Returns true if this tab is the active tab.
25254 * @return {Boolean}
25256 isActive : function(){
25257 return this.tabPanel.getActiveTab() == this;
25261 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25264 this.pnode.removeClass("on");
25266 this.fireEvent("deactivate", this.tabPanel, this);
25269 hideAction : function(){
25270 this.bodyEl.hide();
25271 this.bodyEl.setStyle("position", "absolute");
25272 this.bodyEl.setLeft("-20000px");
25273 this.bodyEl.setTop("-20000px");
25276 showAction : function(){
25277 this.bodyEl.setStyle("position", "relative");
25278 this.bodyEl.setTop("");
25279 this.bodyEl.setLeft("");
25280 this.bodyEl.show();
25284 * Set the tooltip for the tab.
25285 * @param {String} tooltip The tab's tooltip
25287 setTooltip : function(text){
25288 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25289 this.textEl.dom.qtip = text;
25290 this.textEl.dom.removeAttribute('title');
25292 this.textEl.dom.title = text;
25296 onTabClick : function(e){
25297 e.preventDefault();
25298 this.tabPanel.activate(this.id);
25301 onTabMouseDown : function(e){
25302 e.preventDefault();
25303 this.tabPanel.activate(this.id);
25306 getWidth : function(){
25307 return this.inner.getWidth();
25310 setWidth : function(width){
25311 var iwidth = width - this.pnode.getPadding("lr");
25312 this.inner.setWidth(iwidth);
25313 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25314 this.pnode.setWidth(width);
25318 * Show or hide the tab
25319 * @param {Boolean} hidden True to hide or false to show.
25321 setHidden : function(hidden){
25322 this.hidden = hidden;
25323 this.pnode.setStyle("display", hidden ? "none" : "");
25327 * Returns true if this tab is "hidden"
25328 * @return {Boolean}
25330 isHidden : function(){
25331 return this.hidden;
25335 * Returns the text for this tab
25338 getText : function(){
25342 autoSize : function(){
25343 //this.el.beginMeasure();
25344 this.textEl.setWidth(1);
25345 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25346 //this.el.endMeasure();
25350 * Sets the text for the tab (Note: this also sets the tooltip text)
25351 * @param {String} text The tab's text and tooltip
25353 setText : function(text){
25355 this.textEl.update(text);
25356 this.setTooltip(text);
25357 if(!this.tabPanel.resizeTabs){
25362 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25364 activate : function(){
25365 this.tabPanel.activate(this.id);
25369 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25371 disable : function(){
25372 if(this.tabPanel.active != this){
25373 this.disabled = true;
25374 this.pnode.addClass("disabled");
25379 * Enables this TabPanelItem if it was previously disabled.
25381 enable : function(){
25382 this.disabled = false;
25383 this.pnode.removeClass("disabled");
25387 * Sets the content for this TabPanelItem.
25388 * @param {String} content The content
25389 * @param {Boolean} loadScripts true to look for and load scripts
25391 setContent : function(content, loadScripts){
25392 this.bodyEl.update(content, loadScripts);
25396 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25397 * @return {Roo.UpdateManager} The UpdateManager
25399 getUpdateManager : function(){
25400 return this.bodyEl.getUpdateManager();
25404 * Set a URL to be used to load the content for this TabPanelItem.
25405 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25406 * @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)
25407 * @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)
25408 * @return {Roo.UpdateManager} The UpdateManager
25410 setUrl : function(url, params, loadOnce){
25411 if(this.refreshDelegate){
25412 this.un('activate', this.refreshDelegate);
25414 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25415 this.on("activate", this.refreshDelegate);
25416 return this.bodyEl.getUpdateManager();
25420 _handleRefresh : function(url, params, loadOnce){
25421 if(!loadOnce || !this.loaded){
25422 var updater = this.bodyEl.getUpdateManager();
25423 updater.update(url, params, this._setLoaded.createDelegate(this));
25428 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25429 * Will fail silently if the setUrl method has not been called.
25430 * This does not activate the panel, just updates its content.
25432 refresh : function(){
25433 if(this.refreshDelegate){
25434 this.loaded = false;
25435 this.refreshDelegate();
25440 _setLoaded : function(){
25441 this.loaded = true;
25445 closeClick : function(e){
25448 this.fireEvent("beforeclose", this, o);
25449 if(o.cancel !== true){
25450 this.tabPanel.removeTab(this.id);
25454 * The text displayed in the tooltip for the close icon.
25457 closeText : "Close this tab"
25461 Roo.TabPanel.prototype.createStrip = function(container){
25462 var strip = document.createElement("div");
25463 strip.className = "x-tabs-wrap";
25464 container.appendChild(strip);
25468 Roo.TabPanel.prototype.createStripList = function(strip){
25469 // div wrapper for retard IE
25470 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>';
25471 return strip.firstChild.firstChild.firstChild.firstChild;
25474 Roo.TabPanel.prototype.createBody = function(container){
25475 var body = document.createElement("div");
25476 Roo.id(body, "tab-body");
25477 Roo.fly(body).addClass("x-tabs-body");
25478 container.appendChild(body);
25482 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25483 var body = Roo.getDom(id);
25485 body = document.createElement("div");
25488 Roo.fly(body).addClass("x-tabs-item-body");
25489 bodyEl.insertBefore(body, bodyEl.firstChild);
25493 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25494 var td = document.createElement("td");
25495 stripEl.appendChild(td);
25497 td.className = "x-tabs-closable";
25498 if(!this.closeTpl){
25499 this.closeTpl = new Roo.Template(
25500 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25501 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25502 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25505 var el = this.closeTpl.overwrite(td, {"text": text});
25506 var close = el.getElementsByTagName("div")[0];
25507 var inner = el.getElementsByTagName("em")[0];
25508 return {"el": el, "close": close, "inner": inner};
25511 this.tabTpl = new Roo.Template(
25512 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25513 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25516 var el = this.tabTpl.overwrite(td, {"text": text});
25517 var inner = el.getElementsByTagName("em")[0];
25518 return {"el": el, "inner": inner};
25522 * Ext JS Library 1.1.1
25523 * Copyright(c) 2006-2007, Ext JS, LLC.
25525 * Originally Released Under LGPL - original licence link has changed is not relivant.
25528 * <script type="text/javascript">
25532 * @class Roo.Button
25533 * @extends Roo.util.Observable
25534 * Simple Button class
25535 * @cfg {String} text The button text
25536 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25537 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25538 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25539 * @cfg {Object} scope The scope of the handler
25540 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25541 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25542 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25543 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25544 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25545 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25546 applies if enableToggle = true)
25547 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25548 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25549 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25551 * Create a new button
25552 * @param {Object} config The config object
25554 Roo.Button = function(renderTo, config)
25558 renderTo = config.renderTo || false;
25561 Roo.apply(this, config);
25565 * Fires when this button is clicked
25566 * @param {Button} this
25567 * @param {EventObject} e The click event
25572 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25573 * @param {Button} this
25574 * @param {Boolean} pressed
25579 * Fires when the mouse hovers over the button
25580 * @param {Button} this
25581 * @param {Event} e The event object
25583 'mouseover' : true,
25586 * Fires when the mouse exits the button
25587 * @param {Button} this
25588 * @param {Event} e The event object
25593 * Fires when the button is rendered
25594 * @param {Button} this
25599 this.menu = Roo.menu.MenuMgr.get(this.menu);
25602 this.render(renderTo);
25605 Roo.util.Observable.call(this);
25608 Roo.extend(Roo.Button, Roo.util.Observable, {
25614 * Read-only. True if this button is hidden
25619 * Read-only. True if this button is disabled
25624 * Read-only. True if this button is pressed (only if enableToggle = true)
25630 * @cfg {Number} tabIndex
25631 * The DOM tabIndex for this button (defaults to undefined)
25633 tabIndex : undefined,
25636 * @cfg {Boolean} enableToggle
25637 * True to enable pressed/not pressed toggling (defaults to false)
25639 enableToggle: false,
25641 * @cfg {Mixed} menu
25642 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25646 * @cfg {String} menuAlign
25647 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25649 menuAlign : "tl-bl?",
25652 * @cfg {String} iconCls
25653 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25655 iconCls : undefined,
25657 * @cfg {String} type
25658 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25663 menuClassTarget: 'tr',
25666 * @cfg {String} clickEvent
25667 * The type of event to map to the button's event handler (defaults to 'click')
25669 clickEvent : 'click',
25672 * @cfg {Boolean} handleMouseEvents
25673 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25675 handleMouseEvents : true,
25678 * @cfg {String} tooltipType
25679 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
25681 tooltipType : 'qtip',
25684 * @cfg {String} cls
25685 * A CSS class to apply to the button's main element.
25689 * @cfg {Roo.Template} template (Optional)
25690 * An {@link Roo.Template} with which to create the Button's main element. This Template must
25691 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
25692 * require code modifications if required elements (e.g. a button) aren't present.
25696 render : function(renderTo){
25698 if(this.hideParent){
25699 this.parentEl = Roo.get(renderTo);
25701 if(!this.dhconfig){
25702 if(!this.template){
25703 if(!Roo.Button.buttonTemplate){
25704 // hideous table template
25705 Roo.Button.buttonTemplate = new Roo.Template(
25706 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
25707 '<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>',
25708 "</tr></tbody></table>");
25710 this.template = Roo.Button.buttonTemplate;
25712 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
25713 var btnEl = btn.child("button:first");
25714 btnEl.on('focus', this.onFocus, this);
25715 btnEl.on('blur', this.onBlur, this);
25717 btn.addClass(this.cls);
25720 btnEl.setStyle('background-image', 'url(' +this.icon +')');
25723 btnEl.addClass(this.iconCls);
25725 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
25728 if(this.tabIndex !== undefined){
25729 btnEl.dom.tabIndex = this.tabIndex;
25732 if(typeof this.tooltip == 'object'){
25733 Roo.QuickTips.tips(Roo.apply({
25737 btnEl.dom[this.tooltipType] = this.tooltip;
25741 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
25745 this.el.dom.id = this.el.id = this.id;
25748 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
25749 this.menu.on("show", this.onMenuShow, this);
25750 this.menu.on("hide", this.onMenuHide, this);
25752 btn.addClass("x-btn");
25753 if(Roo.isIE && !Roo.isIE7){
25754 this.autoWidth.defer(1, this);
25758 if(this.handleMouseEvents){
25759 btn.on("mouseover", this.onMouseOver, this);
25760 btn.on("mouseout", this.onMouseOut, this);
25761 btn.on("mousedown", this.onMouseDown, this);
25763 btn.on(this.clickEvent, this.onClick, this);
25764 //btn.on("mouseup", this.onMouseUp, this);
25771 Roo.ButtonToggleMgr.register(this);
25773 this.el.addClass("x-btn-pressed");
25776 var repeater = new Roo.util.ClickRepeater(btn,
25777 typeof this.repeat == "object" ? this.repeat : {}
25779 repeater.on("click", this.onClick, this);
25781 this.fireEvent('render', this);
25785 * Returns the button's underlying element
25786 * @return {Roo.Element} The element
25788 getEl : function(){
25793 * Destroys this Button and removes any listeners.
25795 destroy : function(){
25796 Roo.ButtonToggleMgr.unregister(this);
25797 this.el.removeAllListeners();
25798 this.purgeListeners();
25803 autoWidth : function(){
25805 this.el.setWidth("auto");
25806 if(Roo.isIE7 && Roo.isStrict){
25807 var ib = this.el.child('button');
25808 if(ib && ib.getWidth() > 20){
25810 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
25815 this.el.beginMeasure();
25817 if(this.el.getWidth() < this.minWidth){
25818 this.el.setWidth(this.minWidth);
25821 this.el.endMeasure();
25828 * Assigns this button's click handler
25829 * @param {Function} handler The function to call when the button is clicked
25830 * @param {Object} scope (optional) Scope for the function passed in
25832 setHandler : function(handler, scope){
25833 this.handler = handler;
25834 this.scope = scope;
25838 * Sets this button's text
25839 * @param {String} text The button text
25841 setText : function(text){
25844 this.el.child("td.x-btn-center button.x-btn-text").update(text);
25850 * Gets the text for this button
25851 * @return {String} The button text
25853 getText : function(){
25861 this.hidden = false;
25863 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
25871 this.hidden = true;
25873 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
25878 * Convenience function for boolean show/hide
25879 * @param {Boolean} visible True to show, false to hide
25881 setVisible: function(visible){
25890 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
25891 * @param {Boolean} state (optional) Force a particular state
25893 toggle : function(state){
25894 state = state === undefined ? !this.pressed : state;
25895 if(state != this.pressed){
25897 this.el.addClass("x-btn-pressed");
25898 this.pressed = true;
25899 this.fireEvent("toggle", this, true);
25901 this.el.removeClass("x-btn-pressed");
25902 this.pressed = false;
25903 this.fireEvent("toggle", this, false);
25905 if(this.toggleHandler){
25906 this.toggleHandler.call(this.scope || this, this, state);
25914 focus : function(){
25915 this.el.child('button:first').focus();
25919 * Disable this button
25921 disable : function(){
25923 this.el.addClass("x-btn-disabled");
25925 this.disabled = true;
25929 * Enable this button
25931 enable : function(){
25933 this.el.removeClass("x-btn-disabled");
25935 this.disabled = false;
25939 * Convenience function for boolean enable/disable
25940 * @param {Boolean} enabled True to enable, false to disable
25942 setDisabled : function(v){
25943 this[v !== true ? "enable" : "disable"]();
25947 onClick : function(e){
25949 e.preventDefault();
25954 if(!this.disabled){
25955 if(this.enableToggle){
25958 if(this.menu && !this.menu.isVisible()){
25959 this.menu.show(this.el, this.menuAlign);
25961 this.fireEvent("click", this, e);
25963 this.el.removeClass("x-btn-over");
25964 this.handler.call(this.scope || this, this, e);
25969 onMouseOver : function(e){
25970 if(!this.disabled){
25971 this.el.addClass("x-btn-over");
25972 this.fireEvent('mouseover', this, e);
25976 onMouseOut : function(e){
25977 if(!e.within(this.el, true)){
25978 this.el.removeClass("x-btn-over");
25979 this.fireEvent('mouseout', this, e);
25983 onFocus : function(e){
25984 if(!this.disabled){
25985 this.el.addClass("x-btn-focus");
25989 onBlur : function(e){
25990 this.el.removeClass("x-btn-focus");
25993 onMouseDown : function(e){
25994 if(!this.disabled && e.button == 0){
25995 this.el.addClass("x-btn-click");
25996 Roo.get(document).on('mouseup', this.onMouseUp, this);
26000 onMouseUp : function(e){
26002 this.el.removeClass("x-btn-click");
26003 Roo.get(document).un('mouseup', this.onMouseUp, this);
26007 onMenuShow : function(e){
26008 this.el.addClass("x-btn-menu-active");
26011 onMenuHide : function(e){
26012 this.el.removeClass("x-btn-menu-active");
26016 // Private utility class used by Button
26017 Roo.ButtonToggleMgr = function(){
26020 function toggleGroup(btn, state){
26022 var g = groups[btn.toggleGroup];
26023 for(var i = 0, l = g.length; i < l; i++){
26025 g[i].toggle(false);
26032 register : function(btn){
26033 if(!btn.toggleGroup){
26036 var g = groups[btn.toggleGroup];
26038 g = groups[btn.toggleGroup] = [];
26041 btn.on("toggle", toggleGroup);
26044 unregister : function(btn){
26045 if(!btn.toggleGroup){
26048 var g = groups[btn.toggleGroup];
26051 btn.un("toggle", toggleGroup);
26057 * Ext JS Library 1.1.1
26058 * Copyright(c) 2006-2007, Ext JS, LLC.
26060 * Originally Released Under LGPL - original licence link has changed is not relivant.
26063 * <script type="text/javascript">
26067 * @class Roo.SplitButton
26068 * @extends Roo.Button
26069 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26070 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26071 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26072 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26073 * @cfg {String} arrowTooltip The title attribute of the arrow
26075 * Create a new menu button
26076 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26077 * @param {Object} config The config object
26079 Roo.SplitButton = function(renderTo, config){
26080 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26082 * @event arrowclick
26083 * Fires when this button's arrow is clicked
26084 * @param {SplitButton} this
26085 * @param {EventObject} e The click event
26087 this.addEvents({"arrowclick":true});
26090 Roo.extend(Roo.SplitButton, Roo.Button, {
26091 render : function(renderTo){
26092 // this is one sweet looking template!
26093 var tpl = new Roo.Template(
26094 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26095 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26096 '<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>',
26097 "</tbody></table></td><td>",
26098 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26099 '<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>',
26100 "</tbody></table></td></tr></table>"
26102 var btn = tpl.append(renderTo, [this.text, this.type], true);
26103 var btnEl = btn.child("button");
26105 btn.addClass(this.cls);
26108 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26111 btnEl.addClass(this.iconCls);
26113 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26117 if(this.handleMouseEvents){
26118 btn.on("mouseover", this.onMouseOver, this);
26119 btn.on("mouseout", this.onMouseOut, this);
26120 btn.on("mousedown", this.onMouseDown, this);
26121 btn.on("mouseup", this.onMouseUp, this);
26123 btn.on(this.clickEvent, this.onClick, this);
26125 if(typeof this.tooltip == 'object'){
26126 Roo.QuickTips.tips(Roo.apply({
26130 btnEl.dom[this.tooltipType] = this.tooltip;
26133 if(this.arrowTooltip){
26134 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26143 this.el.addClass("x-btn-pressed");
26145 if(Roo.isIE && !Roo.isIE7){
26146 this.autoWidth.defer(1, this);
26151 this.menu.on("show", this.onMenuShow, this);
26152 this.menu.on("hide", this.onMenuHide, this);
26154 this.fireEvent('render', this);
26158 autoWidth : function(){
26160 var tbl = this.el.child("table:first");
26161 var tbl2 = this.el.child("table:last");
26162 this.el.setWidth("auto");
26163 tbl.setWidth("auto");
26164 if(Roo.isIE7 && Roo.isStrict){
26165 var ib = this.el.child('button:first');
26166 if(ib && ib.getWidth() > 20){
26168 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26173 this.el.beginMeasure();
26175 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26176 tbl.setWidth(this.minWidth-tbl2.getWidth());
26179 this.el.endMeasure();
26182 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26186 * Sets this button's click handler
26187 * @param {Function} handler The function to call when the button is clicked
26188 * @param {Object} scope (optional) Scope for the function passed above
26190 setHandler : function(handler, scope){
26191 this.handler = handler;
26192 this.scope = scope;
26196 * Sets this button's arrow click handler
26197 * @param {Function} handler The function to call when the arrow is clicked
26198 * @param {Object} scope (optional) Scope for the function passed above
26200 setArrowHandler : function(handler, scope){
26201 this.arrowHandler = handler;
26202 this.scope = scope;
26208 focus : function(){
26210 this.el.child("button:first").focus();
26215 onClick : function(e){
26216 e.preventDefault();
26217 if(!this.disabled){
26218 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26219 if(this.menu && !this.menu.isVisible()){
26220 this.menu.show(this.el, this.menuAlign);
26222 this.fireEvent("arrowclick", this, e);
26223 if(this.arrowHandler){
26224 this.arrowHandler.call(this.scope || this, this, e);
26227 this.fireEvent("click", this, e);
26229 this.handler.call(this.scope || this, this, e);
26235 onMouseDown : function(e){
26236 if(!this.disabled){
26237 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26241 onMouseUp : function(e){
26242 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26247 // backwards compat
26248 Roo.MenuButton = Roo.SplitButton;/*
26250 * Ext JS Library 1.1.1
26251 * Copyright(c) 2006-2007, Ext JS, LLC.
26253 * Originally Released Under LGPL - original licence link has changed is not relivant.
26256 * <script type="text/javascript">
26260 * @class Roo.Toolbar
26261 * Basic Toolbar class.
26263 * Creates a new Toolbar
26264 * @param {Object} config The config object
26266 Roo.Toolbar = function(container, buttons, config)
26268 /// old consturctor format still supported..
26269 if(container instanceof Array){ // omit the container for later rendering
26270 buttons = container;
26274 if (typeof(container) == 'object' && container.xtype) {
26275 config = container;
26276 container = config.container;
26277 buttons = config.buttons; // not really - use items!!
26280 if (config && config.items) {
26281 xitems = config.items;
26282 delete config.items;
26284 Roo.apply(this, config);
26285 this.buttons = buttons;
26288 this.render(container);
26290 Roo.each(xitems, function(b) {
26296 Roo.Toolbar.prototype = {
26298 * @cfg {Roo.data.Store} items
26299 * array of button configs or elements to add
26303 * @cfg {String/HTMLElement/Element} container
26304 * The id or element that will contain the toolbar
26307 render : function(ct){
26308 this.el = Roo.get(ct);
26310 this.el.addClass(this.cls);
26312 // using a table allows for vertical alignment
26313 // 100% width is needed by Safari...
26314 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26315 this.tr = this.el.child("tr", true);
26317 this.items = new Roo.util.MixedCollection(false, function(o){
26318 return o.id || ("item" + (++autoId));
26321 this.add.apply(this, this.buttons);
26322 delete this.buttons;
26327 * Adds element(s) to the toolbar -- this function takes a variable number of
26328 * arguments of mixed type and adds them to the toolbar.
26329 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26331 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26332 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26333 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26334 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26335 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26336 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26337 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26338 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26339 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26341 * @param {Mixed} arg2
26342 * @param {Mixed} etc.
26345 var a = arguments, l = a.length;
26346 for(var i = 0; i < l; i++){
26351 _add : function(el) {
26354 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26357 if (el.applyTo){ // some kind of form field
26358 return this.addField(el);
26360 if (el.render){ // some kind of Toolbar.Item
26361 return this.addItem(el);
26363 if (typeof el == "string"){ // string
26364 if(el == "separator" || el == "-"){
26365 return this.addSeparator();
26368 return this.addSpacer();
26371 return this.addFill();
26373 return this.addText(el);
26376 if(el.tagName){ // element
26377 return this.addElement(el);
26379 if(typeof el == "object"){ // must be button config?
26380 return this.addButton(el);
26382 // and now what?!?!
26388 * Add an Xtype element
26389 * @param {Object} xtype Xtype Object
26390 * @return {Object} created Object
26392 addxtype : function(e){
26393 return this.add(e);
26397 * Returns the Element for this toolbar.
26398 * @return {Roo.Element}
26400 getEl : function(){
26406 * @return {Roo.Toolbar.Item} The separator item
26408 addSeparator : function(){
26409 return this.addItem(new Roo.Toolbar.Separator());
26413 * Adds a spacer element
26414 * @return {Roo.Toolbar.Spacer} The spacer item
26416 addSpacer : function(){
26417 return this.addItem(new Roo.Toolbar.Spacer());
26421 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26422 * @return {Roo.Toolbar.Fill} The fill item
26424 addFill : function(){
26425 return this.addItem(new Roo.Toolbar.Fill());
26429 * Adds any standard HTML element to the toolbar
26430 * @param {String/HTMLElement/Element} el The element or id of the element to add
26431 * @return {Roo.Toolbar.Item} The element's item
26433 addElement : function(el){
26434 return this.addItem(new Roo.Toolbar.Item(el));
26437 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26438 * @type Roo.util.MixedCollection
26443 * Adds any Toolbar.Item or subclass
26444 * @param {Roo.Toolbar.Item} item
26445 * @return {Roo.Toolbar.Item} The item
26447 addItem : function(item){
26448 var td = this.nextBlock();
26450 this.items.add(item);
26455 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26456 * @param {Object/Array} config A button config or array of configs
26457 * @return {Roo.Toolbar.Button/Array}
26459 addButton : function(config){
26460 if(config instanceof Array){
26462 for(var i = 0, len = config.length; i < len; i++) {
26463 buttons.push(this.addButton(config[i]));
26468 if(!(config instanceof Roo.Toolbar.Button)){
26470 new Roo.Toolbar.SplitButton(config) :
26471 new Roo.Toolbar.Button(config);
26473 var td = this.nextBlock();
26480 * Adds text to the toolbar
26481 * @param {String} text The text to add
26482 * @return {Roo.Toolbar.Item} The element's item
26484 addText : function(text){
26485 return this.addItem(new Roo.Toolbar.TextItem(text));
26489 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26490 * @param {Number} index The index where the item is to be inserted
26491 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26492 * @return {Roo.Toolbar.Button/Item}
26494 insertButton : function(index, item){
26495 if(item instanceof Array){
26497 for(var i = 0, len = item.length; i < len; i++) {
26498 buttons.push(this.insertButton(index + i, item[i]));
26502 if (!(item instanceof Roo.Toolbar.Button)){
26503 item = new Roo.Toolbar.Button(item);
26505 var td = document.createElement("td");
26506 this.tr.insertBefore(td, this.tr.childNodes[index]);
26508 this.items.insert(index, item);
26513 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26514 * @param {Object} config
26515 * @return {Roo.Toolbar.Item} The element's item
26517 addDom : function(config, returnEl){
26518 var td = this.nextBlock();
26519 Roo.DomHelper.overwrite(td, config);
26520 var ti = new Roo.Toolbar.Item(td.firstChild);
26522 this.items.add(ti);
26527 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26528 * @type Roo.util.MixedCollection
26533 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26534 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26535 * @param {Roo.form.Field} field
26536 * @return {Roo.ToolbarItem}
26540 addField : function(field) {
26541 if (!this.fields) {
26543 this.fields = new Roo.util.MixedCollection(false, function(o){
26544 return o.id || ("item" + (++autoId));
26549 var td = this.nextBlock();
26551 var ti = new Roo.Toolbar.Item(td.firstChild);
26553 this.items.add(ti);
26554 this.fields.add(field);
26565 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26566 this.el.child('div').hide();
26574 this.el.child('div').show();
26578 nextBlock : function(){
26579 var td = document.createElement("td");
26580 this.tr.appendChild(td);
26585 destroy : function(){
26586 if(this.items){ // rendered?
26587 Roo.destroy.apply(Roo, this.items.items);
26589 if(this.fields){ // rendered?
26590 Roo.destroy.apply(Roo, this.fields.items);
26592 Roo.Element.uncache(this.el, this.tr);
26597 * @class Roo.Toolbar.Item
26598 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26600 * Creates a new Item
26601 * @param {HTMLElement} el
26603 Roo.Toolbar.Item = function(el){
26604 this.el = Roo.getDom(el);
26605 this.id = Roo.id(this.el);
26606 this.hidden = false;
26609 Roo.Toolbar.Item.prototype = {
26612 * Get this item's HTML Element
26613 * @return {HTMLElement}
26615 getEl : function(){
26620 render : function(td){
26622 td.appendChild(this.el);
26626 * Removes and destroys this item.
26628 destroy : function(){
26629 this.td.parentNode.removeChild(this.td);
26636 this.hidden = false;
26637 this.td.style.display = "";
26644 this.hidden = true;
26645 this.td.style.display = "none";
26649 * Convenience function for boolean show/hide.
26650 * @param {Boolean} visible true to show/false to hide
26652 setVisible: function(visible){
26661 * Try to focus this item.
26663 focus : function(){
26664 Roo.fly(this.el).focus();
26668 * Disables this item.
26670 disable : function(){
26671 Roo.fly(this.td).addClass("x-item-disabled");
26672 this.disabled = true;
26673 this.el.disabled = true;
26677 * Enables this item.
26679 enable : function(){
26680 Roo.fly(this.td).removeClass("x-item-disabled");
26681 this.disabled = false;
26682 this.el.disabled = false;
26688 * @class Roo.Toolbar.Separator
26689 * @extends Roo.Toolbar.Item
26690 * A simple toolbar separator class
26692 * Creates a new Separator
26694 Roo.Toolbar.Separator = function(){
26695 var s = document.createElement("span");
26696 s.className = "ytb-sep";
26697 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
26699 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
26700 enable:Roo.emptyFn,
26701 disable:Roo.emptyFn,
26706 * @class Roo.Toolbar.Spacer
26707 * @extends Roo.Toolbar.Item
26708 * A simple element that adds extra horizontal space to a toolbar.
26710 * Creates a new Spacer
26712 Roo.Toolbar.Spacer = function(){
26713 var s = document.createElement("div");
26714 s.className = "ytb-spacer";
26715 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
26717 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
26718 enable:Roo.emptyFn,
26719 disable:Roo.emptyFn,
26724 * @class Roo.Toolbar.Fill
26725 * @extends Roo.Toolbar.Spacer
26726 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
26728 * Creates a new Spacer
26730 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
26732 render : function(td){
26733 td.style.width = '100%';
26734 Roo.Toolbar.Fill.superclass.render.call(this, td);
26739 * @class Roo.Toolbar.TextItem
26740 * @extends Roo.Toolbar.Item
26741 * A simple class that renders text directly into a toolbar.
26743 * Creates a new TextItem
26744 * @param {String} text
26746 Roo.Toolbar.TextItem = function(text){
26747 if (typeof(text) == 'object') {
26750 var s = document.createElement("span");
26751 s.className = "ytb-text";
26752 s.innerHTML = text;
26753 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
26755 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
26756 enable:Roo.emptyFn,
26757 disable:Roo.emptyFn,
26762 * @class Roo.Toolbar.Button
26763 * @extends Roo.Button
26764 * A button that renders into a toolbar.
26766 * Creates a new Button
26767 * @param {Object} config A standard {@link Roo.Button} config object
26769 Roo.Toolbar.Button = function(config){
26770 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
26772 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
26773 render : function(td){
26775 Roo.Toolbar.Button.superclass.render.call(this, td);
26779 * Removes and destroys this button
26781 destroy : function(){
26782 Roo.Toolbar.Button.superclass.destroy.call(this);
26783 this.td.parentNode.removeChild(this.td);
26787 * Shows this button
26790 this.hidden = false;
26791 this.td.style.display = "";
26795 * Hides this button
26798 this.hidden = true;
26799 this.td.style.display = "none";
26803 * Disables this item
26805 disable : function(){
26806 Roo.fly(this.td).addClass("x-item-disabled");
26807 this.disabled = true;
26811 * Enables this item
26813 enable : function(){
26814 Roo.fly(this.td).removeClass("x-item-disabled");
26815 this.disabled = false;
26818 // backwards compat
26819 Roo.ToolbarButton = Roo.Toolbar.Button;
26822 * @class Roo.Toolbar.SplitButton
26823 * @extends Roo.SplitButton
26824 * A menu button that renders into a toolbar.
26826 * Creates a new SplitButton
26827 * @param {Object} config A standard {@link Roo.SplitButton} config object
26829 Roo.Toolbar.SplitButton = function(config){
26830 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
26832 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
26833 render : function(td){
26835 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
26839 * Removes and destroys this button
26841 destroy : function(){
26842 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
26843 this.td.parentNode.removeChild(this.td);
26847 * Shows this button
26850 this.hidden = false;
26851 this.td.style.display = "";
26855 * Hides this button
26858 this.hidden = true;
26859 this.td.style.display = "none";
26863 // backwards compat
26864 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
26866 * Ext JS Library 1.1.1
26867 * Copyright(c) 2006-2007, Ext JS, LLC.
26869 * Originally Released Under LGPL - original licence link has changed is not relivant.
26872 * <script type="text/javascript">
26876 * @class Roo.PagingToolbar
26877 * @extends Roo.Toolbar
26878 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26880 * Create a new PagingToolbar
26881 * @param {Object} config The config object
26883 Roo.PagingToolbar = function(el, ds, config)
26885 // old args format still supported... - xtype is prefered..
26886 if (typeof(el) == 'object' && el.xtype) {
26887 // created from xtype...
26889 ds = el.dataSource;
26890 el = config.container;
26894 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
26897 this.renderButtons(this.el);
26901 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
26903 * @cfg {Roo.data.Store} dataSource
26904 * The underlying data store providing the paged data
26907 * @cfg {String/HTMLElement/Element} container
26908 * container The id or element that will contain the toolbar
26911 * @cfg {Boolean} displayInfo
26912 * True to display the displayMsg (defaults to false)
26915 * @cfg {Number} pageSize
26916 * The number of records to display per page (defaults to 20)
26920 * @cfg {String} displayMsg
26921 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26923 displayMsg : 'Displaying {0} - {1} of {2}',
26925 * @cfg {String} emptyMsg
26926 * The message to display when no records are found (defaults to "No data to display")
26928 emptyMsg : 'No data to display',
26930 * Customizable piece of the default paging text (defaults to "Page")
26933 beforePageText : "Page",
26935 * Customizable piece of the default paging text (defaults to "of %0")
26938 afterPageText : "of {0}",
26940 * Customizable piece of the default paging text (defaults to "First Page")
26943 firstText : "First Page",
26945 * Customizable piece of the default paging text (defaults to "Previous Page")
26948 prevText : "Previous Page",
26950 * Customizable piece of the default paging text (defaults to "Next Page")
26953 nextText : "Next Page",
26955 * Customizable piece of the default paging text (defaults to "Last Page")
26958 lastText : "Last Page",
26960 * Customizable piece of the default paging text (defaults to "Refresh")
26963 refreshText : "Refresh",
26966 renderButtons : function(el){
26967 Roo.PagingToolbar.superclass.render.call(this, el);
26968 this.first = this.addButton({
26969 tooltip: this.firstText,
26970 cls: "x-btn-icon x-grid-page-first",
26972 handler: this.onClick.createDelegate(this, ["first"])
26974 this.prev = this.addButton({
26975 tooltip: this.prevText,
26976 cls: "x-btn-icon x-grid-page-prev",
26978 handler: this.onClick.createDelegate(this, ["prev"])
26980 this.addSeparator();
26981 this.add(this.beforePageText);
26982 this.field = Roo.get(this.addDom({
26987 cls: "x-grid-page-number"
26989 this.field.on("keydown", this.onPagingKeydown, this);
26990 this.field.on("focus", function(){this.dom.select();});
26991 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
26992 this.field.setHeight(18);
26993 this.addSeparator();
26994 this.next = this.addButton({
26995 tooltip: this.nextText,
26996 cls: "x-btn-icon x-grid-page-next",
26998 handler: this.onClick.createDelegate(this, ["next"])
27000 this.last = this.addButton({
27001 tooltip: this.lastText,
27002 cls: "x-btn-icon x-grid-page-last",
27004 handler: this.onClick.createDelegate(this, ["last"])
27006 this.addSeparator();
27007 this.loading = this.addButton({
27008 tooltip: this.refreshText,
27009 cls: "x-btn-icon x-grid-loading",
27010 handler: this.onClick.createDelegate(this, ["refresh"])
27013 if(this.displayInfo){
27014 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27019 updateInfo : function(){
27020 if(this.displayEl){
27021 var count = this.ds.getCount();
27022 var msg = count == 0 ?
27026 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27028 this.displayEl.update(msg);
27033 onLoad : function(ds, r, o){
27034 this.cursor = o.params ? o.params.start : 0;
27035 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27037 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27038 this.field.dom.value = ap;
27039 this.first.setDisabled(ap == 1);
27040 this.prev.setDisabled(ap == 1);
27041 this.next.setDisabled(ap == ps);
27042 this.last.setDisabled(ap == ps);
27043 this.loading.enable();
27048 getPageData : function(){
27049 var total = this.ds.getTotalCount();
27052 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27053 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27058 onLoadError : function(){
27059 this.loading.enable();
27063 onPagingKeydown : function(e){
27064 var k = e.getKey();
27065 var d = this.getPageData();
27067 var v = this.field.dom.value, pageNum;
27068 if(!v || isNaN(pageNum = parseInt(v, 10))){
27069 this.field.dom.value = d.activePage;
27072 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27073 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27076 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))
27078 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27079 this.field.dom.value = pageNum;
27080 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27083 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27085 var v = this.field.dom.value, pageNum;
27086 var increment = (e.shiftKey) ? 10 : 1;
27087 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27089 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27090 this.field.dom.value = d.activePage;
27093 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27095 this.field.dom.value = parseInt(v, 10) + increment;
27096 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27097 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27104 beforeLoad : function(){
27106 this.loading.disable();
27111 onClick : function(which){
27115 ds.load({params:{start: 0, limit: this.pageSize}});
27118 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27121 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27124 var total = ds.getTotalCount();
27125 var extra = total % this.pageSize;
27126 var lastStart = extra ? (total - extra) : total-this.pageSize;
27127 ds.load({params:{start: lastStart, limit: this.pageSize}});
27130 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27136 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27137 * @param {Roo.data.Store} store The data store to unbind
27139 unbind : function(ds){
27140 ds.un("beforeload", this.beforeLoad, this);
27141 ds.un("load", this.onLoad, this);
27142 ds.un("loadexception", this.onLoadError, this);
27143 ds.un("remove", this.updateInfo, this);
27144 ds.un("add", this.updateInfo, this);
27145 this.ds = undefined;
27149 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27150 * @param {Roo.data.Store} store The data store to bind
27152 bind : function(ds){
27153 ds.on("beforeload", this.beforeLoad, this);
27154 ds.on("load", this.onLoad, this);
27155 ds.on("loadexception", this.onLoadError, this);
27156 ds.on("remove", this.updateInfo, this);
27157 ds.on("add", this.updateInfo, this);
27162 * Ext JS Library 1.1.1
27163 * Copyright(c) 2006-2007, Ext JS, LLC.
27165 * Originally Released Under LGPL - original licence link has changed is not relivant.
27168 * <script type="text/javascript">
27172 * @class Roo.Resizable
27173 * @extends Roo.util.Observable
27174 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27175 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27176 * 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
27177 * the element will be wrapped for you automatically.</p>
27178 * <p>Here is the list of valid resize handles:</p>
27181 ------ -------------------
27192 * <p>Here's an example showing the creation of a typical Resizable:</p>
27194 var resizer = new Roo.Resizable("element-id", {
27202 resizer.on("resize", myHandler);
27204 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27205 * resizer.east.setDisplayed(false);</p>
27206 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27207 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27208 * resize operation's new size (defaults to [0, 0])
27209 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27210 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27211 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27212 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27213 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27214 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27215 * @cfg {Number} width The width of the element in pixels (defaults to null)
27216 * @cfg {Number} height The height of the element in pixels (defaults to null)
27217 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27218 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27219 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27220 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27221 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27222 * in favor of the handles config option (defaults to false)
27223 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27224 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27225 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27226 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27227 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27228 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27229 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27230 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27231 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27232 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27233 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27235 * Create a new resizable component
27236 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27237 * @param {Object} config configuration options
27239 Roo.Resizable = function(el, config){
27240 this.el = Roo.get(el);
27242 if(config && config.wrap){
27243 config.resizeChild = this.el;
27244 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27245 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27246 this.el.setStyle("overflow", "hidden");
27247 this.el.setPositioning(config.resizeChild.getPositioning());
27248 config.resizeChild.clearPositioning();
27249 if(!config.width || !config.height){
27250 var csize = config.resizeChild.getSize();
27251 this.el.setSize(csize.width, csize.height);
27253 if(config.pinned && !config.adjustments){
27254 config.adjustments = "auto";
27258 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27259 this.proxy.unselectable();
27260 this.proxy.enableDisplayMode('block');
27262 Roo.apply(this, config);
27265 this.disableTrackOver = true;
27266 this.el.addClass("x-resizable-pinned");
27268 // if the element isn't positioned, make it relative
27269 var position = this.el.getStyle("position");
27270 if(position != "absolute" && position != "fixed"){
27271 this.el.setStyle("position", "relative");
27273 if(!this.handles){ // no handles passed, must be legacy style
27274 this.handles = 's,e,se';
27275 if(this.multiDirectional){
27276 this.handles += ',n,w';
27279 if(this.handles == "all"){
27280 this.handles = "n s e w ne nw se sw";
27282 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27283 var ps = Roo.Resizable.positions;
27284 for(var i = 0, len = hs.length; i < len; i++){
27285 if(hs[i] && ps[hs[i]]){
27286 var pos = ps[hs[i]];
27287 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27291 this.corner = this.southeast;
27293 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1){
27294 this.updateBox = true;
27297 this.activeHandle = null;
27299 if(this.resizeChild){
27300 if(typeof this.resizeChild == "boolean"){
27301 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27303 this.resizeChild = Roo.get(this.resizeChild, true);
27307 if(this.adjustments == "auto"){
27308 var rc = this.resizeChild;
27309 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27310 if(rc && (hw || hn)){
27311 rc.position("relative");
27312 rc.setLeft(hw ? hw.el.getWidth() : 0);
27313 rc.setTop(hn ? hn.el.getHeight() : 0);
27315 this.adjustments = [
27316 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27317 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27321 if(this.draggable){
27322 this.dd = this.dynamic ?
27323 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27324 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27330 * @event beforeresize
27331 * Fired before resize is allowed. Set enabled to false to cancel resize.
27332 * @param {Roo.Resizable} this
27333 * @param {Roo.EventObject} e The mousedown event
27335 "beforeresize" : true,
27338 * Fired after a resize.
27339 * @param {Roo.Resizable} this
27340 * @param {Number} width The new width
27341 * @param {Number} height The new height
27342 * @param {Roo.EventObject} e The mouseup event
27347 if(this.width !== null && this.height !== null){
27348 this.resizeTo(this.width, this.height);
27350 this.updateChildSize();
27353 this.el.dom.style.zoom = 1;
27355 Roo.Resizable.superclass.constructor.call(this);
27358 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27359 resizeChild : false,
27360 adjustments : [0, 0],
27370 multiDirectional : false,
27371 disableTrackOver : false,
27372 easing : 'easeOutStrong',
27373 widthIncrement : 0,
27374 heightIncrement : 0,
27378 preserveRatio : false,
27379 transparent: false,
27385 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27387 constrainTo: undefined,
27389 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27391 resizeRegion: undefined,
27395 * Perform a manual resize
27396 * @param {Number} width
27397 * @param {Number} height
27399 resizeTo : function(width, height){
27400 this.el.setSize(width, height);
27401 this.updateChildSize();
27402 this.fireEvent("resize", this, width, height, null);
27406 startSizing : function(e, handle){
27407 this.fireEvent("beforeresize", this, e);
27408 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27411 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27412 this.overlay.unselectable();
27413 this.overlay.enableDisplayMode("block");
27414 this.overlay.on("mousemove", this.onMouseMove, this);
27415 this.overlay.on("mouseup", this.onMouseUp, this);
27417 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27419 this.resizing = true;
27420 this.startBox = this.el.getBox();
27421 this.startPoint = e.getXY();
27422 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27423 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27425 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27426 this.overlay.show();
27428 if(this.constrainTo) {
27429 var ct = Roo.get(this.constrainTo);
27430 this.resizeRegion = ct.getRegion().adjust(
27431 ct.getFrameWidth('t'),
27432 ct.getFrameWidth('l'),
27433 -ct.getFrameWidth('b'),
27434 -ct.getFrameWidth('r')
27438 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27440 this.proxy.setBox(this.startBox);
27442 this.proxy.setStyle('visibility', 'visible');
27448 onMouseDown : function(handle, e){
27451 this.activeHandle = handle;
27452 this.startSizing(e, handle);
27457 onMouseUp : function(e){
27458 var size = this.resizeElement();
27459 this.resizing = false;
27461 this.overlay.hide();
27463 this.fireEvent("resize", this, size.width, size.height, e);
27467 updateChildSize : function(){
27468 if(this.resizeChild){
27470 var child = this.resizeChild;
27471 var adj = this.adjustments;
27472 if(el.dom.offsetWidth){
27473 var b = el.getSize(true);
27474 child.setSize(b.width+adj[0], b.height+adj[1]);
27476 // Second call here for IE
27477 // The first call enables instant resizing and
27478 // the second call corrects scroll bars if they
27481 setTimeout(function(){
27482 if(el.dom.offsetWidth){
27483 var b = el.getSize(true);
27484 child.setSize(b.width+adj[0], b.height+adj[1]);
27492 snap : function(value, inc, min){
27493 if(!inc || !value) return value;
27494 var newValue = value;
27495 var m = value % inc;
27498 newValue = value + (inc-m);
27500 newValue = value - m;
27503 return Math.max(min, newValue);
27507 resizeElement : function(){
27508 var box = this.proxy.getBox();
27509 if(this.updateBox){
27510 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27512 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27514 this.updateChildSize();
27522 constrain : function(v, diff, m, mx){
27525 }else if(v - diff > mx){
27532 onMouseMove : function(e){
27534 try{// try catch so if something goes wrong the user doesn't get hung
27536 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27540 //var curXY = this.startPoint;
27541 var curSize = this.curSize || this.startBox;
27542 var x = this.startBox.x, y = this.startBox.y;
27543 var ox = x, oy = y;
27544 var w = curSize.width, h = curSize.height;
27545 var ow = w, oh = h;
27546 var mw = this.minWidth, mh = this.minHeight;
27547 var mxw = this.maxWidth, mxh = this.maxHeight;
27548 var wi = this.widthIncrement;
27549 var hi = this.heightIncrement;
27551 var eventXY = e.getXY();
27552 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27553 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27555 var pos = this.activeHandle.position;
27560 w = Math.min(Math.max(mw, w), mxw);
27564 h = Math.min(Math.max(mh, h), mxh);
27569 w = Math.min(Math.max(mw, w), mxw);
27570 h = Math.min(Math.max(mh, h), mxh);
27573 diffY = this.constrain(h, diffY, mh, mxh);
27578 diffX = this.constrain(w, diffX, mw, mxw);
27584 w = Math.min(Math.max(mw, w), mxw);
27585 diffY = this.constrain(h, diffY, mh, mxh);
27590 diffX = this.constrain(w, diffX, mw, mxw);
27591 diffY = this.constrain(h, diffY, mh, mxh);
27598 diffX = this.constrain(w, diffX, mw, mxw);
27600 h = Math.min(Math.max(mh, h), mxh);
27606 var sw = this.snap(w, wi, mw);
27607 var sh = this.snap(h, hi, mh);
27608 if(sw != w || sh != h){
27631 if(this.preserveRatio){
27636 h = Math.min(Math.max(mh, h), mxh);
27641 w = Math.min(Math.max(mw, w), mxw);
27646 w = Math.min(Math.max(mw, w), mxw);
27652 w = Math.min(Math.max(mw, w), mxw);
27658 h = Math.min(Math.max(mh, h), mxh);
27666 h = Math.min(Math.max(mh, h), mxh);
27676 h = Math.min(Math.max(mh, h), mxh);
27684 this.proxy.setBounds(x, y, w, h);
27686 this.resizeElement();
27693 handleOver : function(){
27695 this.el.addClass("x-resizable-over");
27700 handleOut : function(){
27701 if(!this.resizing){
27702 this.el.removeClass("x-resizable-over");
27707 * Returns the element this component is bound to.
27708 * @return {Roo.Element}
27710 getEl : function(){
27715 * Returns the resizeChild element (or null).
27716 * @return {Roo.Element}
27718 getResizeChild : function(){
27719 return this.resizeChild;
27723 * Destroys this resizable. If the element was wrapped and
27724 * removeEl is not true then the element remains.
27725 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
27727 destroy : function(removeEl){
27728 this.proxy.remove();
27730 this.overlay.removeAllListeners();
27731 this.overlay.remove();
27733 var ps = Roo.Resizable.positions;
27735 if(typeof ps[k] != "function" && this[ps[k]]){
27736 var h = this[ps[k]];
27737 h.el.removeAllListeners();
27742 this.el.update("");
27749 // hash to map config positions to true positions
27750 Roo.Resizable.positions = {
27751 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast"
27755 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
27757 // only initialize the template if resizable is used
27758 var tpl = Roo.DomHelper.createTemplate(
27759 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
27762 Roo.Resizable.Handle.prototype.tpl = tpl;
27764 this.position = pos;
27766 this.el = this.tpl.append(rz.el.dom, [this.position], true);
27767 this.el.unselectable();
27769 this.el.setOpacity(0);
27771 this.el.on("mousedown", this.onMouseDown, this);
27772 if(!disableTrackOver){
27773 this.el.on("mouseover", this.onMouseOver, this);
27774 this.el.on("mouseout", this.onMouseOut, this);
27779 Roo.Resizable.Handle.prototype = {
27780 afterResize : function(rz){
27784 onMouseDown : function(e){
27785 this.rz.onMouseDown(this, e);
27788 onMouseOver : function(e){
27789 this.rz.handleOver(this, e);
27792 onMouseOut : function(e){
27793 this.rz.handleOut(this, e);
27797 * Ext JS Library 1.1.1
27798 * Copyright(c) 2006-2007, Ext JS, LLC.
27800 * Originally Released Under LGPL - original licence link has changed is not relivant.
27803 * <script type="text/javascript">
27807 * @class Roo.Editor
27808 * @extends Roo.Component
27809 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
27811 * Create a new Editor
27812 * @param {Roo.form.Field} field The Field object (or descendant)
27813 * @param {Object} config The config object
27815 Roo.Editor = function(field, config){
27816 Roo.Editor.superclass.constructor.call(this, config);
27817 this.field = field;
27820 * @event beforestartedit
27821 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
27822 * false from the handler of this event.
27823 * @param {Editor} this
27824 * @param {Roo.Element} boundEl The underlying element bound to this editor
27825 * @param {Mixed} value The field value being set
27827 "beforestartedit" : true,
27830 * Fires when this editor is displayed
27831 * @param {Roo.Element} boundEl The underlying element bound to this editor
27832 * @param {Mixed} value The starting field value
27834 "startedit" : true,
27836 * @event beforecomplete
27837 * Fires after a change has been made to the field, but before the change is reflected in the underlying
27838 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
27839 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
27840 * event will not fire since no edit actually occurred.
27841 * @param {Editor} this
27842 * @param {Mixed} value The current field value
27843 * @param {Mixed} startValue The original field value
27845 "beforecomplete" : true,
27848 * Fires after editing is complete and any changed value has been written to the underlying field.
27849 * @param {Editor} this
27850 * @param {Mixed} value The current field value
27851 * @param {Mixed} startValue The original field value
27855 * @event specialkey
27856 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
27857 * {@link Roo.EventObject#getKey} to determine which key was pressed.
27858 * @param {Roo.form.Field} this
27859 * @param {Roo.EventObject} e The event object
27861 "specialkey" : true
27865 Roo.extend(Roo.Editor, Roo.Component, {
27867 * @cfg {Boolean/String} autosize
27868 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
27869 * or "height" to adopt the height only (defaults to false)
27872 * @cfg {Boolean} revertInvalid
27873 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
27874 * validation fails (defaults to true)
27877 * @cfg {Boolean} ignoreNoChange
27878 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
27879 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
27880 * will never be ignored.
27883 * @cfg {Boolean} hideEl
27884 * False to keep the bound element visible while the editor is displayed (defaults to true)
27887 * @cfg {Mixed} value
27888 * The data value of the underlying field (defaults to "")
27892 * @cfg {String} alignment
27893 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
27897 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
27898 * for bottom-right shadow (defaults to "frame")
27902 * @cfg {Boolean} constrain True to constrain the editor to the viewport
27906 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
27908 completeOnEnter : false,
27910 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
27912 cancelOnEsc : false,
27914 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
27919 onRender : function(ct, position){
27920 this.el = new Roo.Layer({
27921 shadow: this.shadow,
27927 constrain: this.constrain
27929 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
27930 if(this.field.msgTarget != 'title'){
27931 this.field.msgTarget = 'qtip';
27933 this.field.render(this.el);
27935 this.field.el.dom.setAttribute('autocomplete', 'off');
27937 this.field.on("specialkey", this.onSpecialKey, this);
27938 if(this.swallowKeys){
27939 this.field.el.swallowEvent(['keydown','keypress']);
27942 this.field.on("blur", this.onBlur, this);
27943 if(this.field.grow){
27944 this.field.on("autosize", this.el.sync, this.el, {delay:1});
27948 onSpecialKey : function(field, e){
27949 if(this.completeOnEnter && e.getKey() == e.ENTER){
27951 this.completeEdit();
27952 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
27955 this.fireEvent('specialkey', field, e);
27960 * Starts the editing process and shows the editor.
27961 * @param {String/HTMLElement/Element} el The element to edit
27962 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
27963 * to the innerHTML of el.
27965 startEdit : function(el, value){
27967 this.completeEdit();
27969 this.boundEl = Roo.get(el);
27970 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
27971 if(!this.rendered){
27972 this.render(this.parentEl || document.body);
27974 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
27977 this.startValue = v;
27978 this.field.setValue(v);
27980 var sz = this.boundEl.getSize();
27981 switch(this.autoSize){
27983 this.setSize(sz.width, "");
27986 this.setSize("", sz.height);
27989 this.setSize(sz.width, sz.height);
27992 this.el.alignTo(this.boundEl, this.alignment);
27993 this.editing = true;
27995 Roo.QuickTips.disable();
28001 * Sets the height and width of this editor.
28002 * @param {Number} width The new width
28003 * @param {Number} height The new height
28005 setSize : function(w, h){
28006 this.field.setSize(w, h);
28013 * Realigns the editor to the bound field based on the current alignment config value.
28015 realign : function(){
28016 this.el.alignTo(this.boundEl, this.alignment);
28020 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28021 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28023 completeEdit : function(remainVisible){
28027 var v = this.getValue();
28028 if(this.revertInvalid !== false && !this.field.isValid()){
28029 v = this.startValue;
28030 this.cancelEdit(true);
28032 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28033 this.editing = false;
28037 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28038 this.editing = false;
28039 if(this.updateEl && this.boundEl){
28040 this.boundEl.update(v);
28042 if(remainVisible !== true){
28045 this.fireEvent("complete", this, v, this.startValue);
28050 onShow : function(){
28052 if(this.hideEl !== false){
28053 this.boundEl.hide();
28056 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28057 this.fixIEFocus = true;
28058 this.deferredFocus.defer(50, this);
28060 this.field.focus();
28062 this.fireEvent("startedit", this.boundEl, this.startValue);
28065 deferredFocus : function(){
28067 this.field.focus();
28072 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28073 * reverted to the original starting value.
28074 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28075 * cancel (defaults to false)
28077 cancelEdit : function(remainVisible){
28079 this.setValue(this.startValue);
28080 if(remainVisible !== true){
28087 onBlur : function(){
28088 if(this.allowBlur !== true && this.editing){
28089 this.completeEdit();
28094 onHide : function(){
28096 this.completeEdit();
28100 if(this.field.collapse){
28101 this.field.collapse();
28104 if(this.hideEl !== false){
28105 this.boundEl.show();
28108 Roo.QuickTips.enable();
28113 * Sets the data value of the editor
28114 * @param {Mixed} value Any valid value supported by the underlying field
28116 setValue : function(v){
28117 this.field.setValue(v);
28121 * Gets the data value of the editor
28122 * @return {Mixed} The data value
28124 getValue : function(){
28125 return this.field.getValue();
28129 * Ext JS Library 1.1.1
28130 * Copyright(c) 2006-2007, Ext JS, LLC.
28132 * Originally Released Under LGPL - original licence link has changed is not relivant.
28135 * <script type="text/javascript">
28139 * @class Roo.BasicDialog
28140 * @extends Roo.util.Observable
28141 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28143 var dlg = new Roo.BasicDialog("my-dlg", {
28152 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28153 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28154 dlg.addButton('Cancel', dlg.hide, dlg);
28157 <b>A Dialog should always be a direct child of the body element.</b>
28158 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28159 * @cfg {String} title Default text to display in the title bar (defaults to null)
28160 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28161 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28162 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28163 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28164 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28165 * (defaults to null with no animation)
28166 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28167 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28168 * property for valid values (defaults to 'all')
28169 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28170 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28171 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28172 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28173 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28174 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28175 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28176 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28177 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28178 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28179 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28180 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28181 * draggable = true (defaults to false)
28182 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28183 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28184 * shadow (defaults to false)
28185 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28186 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28187 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28188 * @cfg {Array} buttons Array of buttons
28189 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28191 * Create a new BasicDialog.
28192 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28193 * @param {Object} config Configuration options
28195 Roo.BasicDialog = function(el, config){
28196 this.el = Roo.get(el);
28197 var dh = Roo.DomHelper;
28198 if(!this.el && config && config.autoCreate){
28199 if(typeof config.autoCreate == "object"){
28200 if(!config.autoCreate.id){
28201 config.autoCreate.id = el;
28203 this.el = dh.append(document.body,
28204 config.autoCreate, true);
28206 this.el = dh.append(document.body,
28207 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28211 el.setDisplayed(true);
28212 el.hide = this.hideAction;
28214 el.addClass("x-dlg");
28216 Roo.apply(this, config);
28218 this.proxy = el.createProxy("x-dlg-proxy");
28219 this.proxy.hide = this.hideAction;
28220 this.proxy.setOpacity(.5);
28224 el.setWidth(config.width);
28227 el.setHeight(config.height);
28229 this.size = el.getSize();
28230 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28231 this.xy = [config.x,config.y];
28233 this.xy = el.getCenterXY(true);
28235 /** The header element @type Roo.Element */
28236 this.header = el.child("> .x-dlg-hd");
28237 /** The body element @type Roo.Element */
28238 this.body = el.child("> .x-dlg-bd");
28239 /** The footer element @type Roo.Element */
28240 this.footer = el.child("> .x-dlg-ft");
28243 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28246 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28249 this.header.unselectable();
28251 this.header.update(this.title);
28253 // this element allows the dialog to be focused for keyboard event
28254 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28255 this.focusEl.swallowEvent("click", true);
28257 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28259 // wrap the body and footer for special rendering
28260 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28262 this.bwrap.dom.appendChild(this.footer.dom);
28265 this.bg = this.el.createChild({
28266 tag: "div", cls:"x-dlg-bg",
28267 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28269 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28272 if(this.autoScroll !== false && !this.autoTabs){
28273 this.body.setStyle("overflow", "auto");
28276 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28278 if(this.closable !== false){
28279 this.el.addClass("x-dlg-closable");
28280 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28281 this.close.on("click", this.closeClick, this);
28282 this.close.addClassOnOver("x-dlg-close-over");
28284 if(this.collapsible !== false){
28285 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28286 this.collapseBtn.on("click", this.collapseClick, this);
28287 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28288 this.header.on("dblclick", this.collapseClick, this);
28290 if(this.resizable !== false){
28291 this.el.addClass("x-dlg-resizable");
28292 this.resizer = new Roo.Resizable(el, {
28293 minWidth: this.minWidth || 80,
28294 minHeight:this.minHeight || 80,
28295 handles: this.resizeHandles || "all",
28298 this.resizer.on("beforeresize", this.beforeResize, this);
28299 this.resizer.on("resize", this.onResize, this);
28301 if(this.draggable !== false){
28302 el.addClass("x-dlg-draggable");
28303 if (!this.proxyDrag) {
28304 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28307 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28309 dd.setHandleElId(this.header.id);
28310 dd.endDrag = this.endMove.createDelegate(this);
28311 dd.startDrag = this.startMove.createDelegate(this);
28312 dd.onDrag = this.onDrag.createDelegate(this);
28317 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28318 this.mask.enableDisplayMode("block");
28320 this.el.addClass("x-dlg-modal");
28323 this.shadow = new Roo.Shadow({
28324 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28325 offset : this.shadowOffset
28328 this.shadowOffset = 0;
28330 if(Roo.useShims && this.shim !== false){
28331 this.shim = this.el.createShim();
28332 this.shim.hide = this.hideAction;
28340 if (this.buttons) {
28341 var bts= this.buttons;
28343 Roo.each(bts, function(b) {
28352 * Fires when a key is pressed
28353 * @param {Roo.BasicDialog} this
28354 * @param {Roo.EventObject} e
28359 * Fires when this dialog is moved by the user.
28360 * @param {Roo.BasicDialog} this
28361 * @param {Number} x The new page X
28362 * @param {Number} y The new page Y
28367 * Fires when this dialog is resized by the user.
28368 * @param {Roo.BasicDialog} this
28369 * @param {Number} width The new width
28370 * @param {Number} height The new height
28374 * @event beforehide
28375 * Fires before this dialog is hidden.
28376 * @param {Roo.BasicDialog} this
28378 "beforehide" : true,
28381 * Fires when this dialog is hidden.
28382 * @param {Roo.BasicDialog} this
28386 * @event beforeshow
28387 * Fires before this dialog is shown.
28388 * @param {Roo.BasicDialog} this
28390 "beforeshow" : true,
28393 * Fires when this dialog is shown.
28394 * @param {Roo.BasicDialog} this
28398 el.on("keydown", this.onKeyDown, this);
28399 el.on("mousedown", this.toFront, this);
28400 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28402 Roo.DialogManager.register(this);
28403 Roo.BasicDialog.superclass.constructor.call(this);
28406 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28407 shadowOffset: Roo.isIE ? 6 : 5,
28410 minButtonWidth: 75,
28411 defaultButton: null,
28412 buttonAlign: "right",
28417 * Sets the dialog title text
28418 * @param {String} text The title text to display
28419 * @return {Roo.BasicDialog} this
28421 setTitle : function(text){
28422 this.header.update(text);
28427 closeClick : function(){
28432 collapseClick : function(){
28433 this[this.collapsed ? "expand" : "collapse"]();
28437 * Collapses the dialog to its minimized state (only the title bar is visible).
28438 * Equivalent to the user clicking the collapse dialog button.
28440 collapse : function(){
28441 if(!this.collapsed){
28442 this.collapsed = true;
28443 this.el.addClass("x-dlg-collapsed");
28444 this.restoreHeight = this.el.getHeight();
28445 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28450 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28451 * clicking the expand dialog button.
28453 expand : function(){
28454 if(this.collapsed){
28455 this.collapsed = false;
28456 this.el.removeClass("x-dlg-collapsed");
28457 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28462 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28463 * @return {Roo.TabPanel} The tabs component
28465 initTabs : function(){
28466 var tabs = this.getTabs();
28467 while(tabs.getTab(0)){
28470 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28472 tabs.addTab(Roo.id(dom), dom.title);
28480 beforeResize : function(){
28481 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28485 onResize : function(){
28486 this.refreshSize();
28487 this.syncBodyHeight();
28488 this.adjustAssets();
28490 this.fireEvent("resize", this, this.size.width, this.size.height);
28494 onKeyDown : function(e){
28495 if(this.isVisible()){
28496 this.fireEvent("keydown", this, e);
28501 * Resizes the dialog.
28502 * @param {Number} width
28503 * @param {Number} height
28504 * @return {Roo.BasicDialog} this
28506 resizeTo : function(width, height){
28507 this.el.setSize(width, height);
28508 this.size = {width: width, height: height};
28509 this.syncBodyHeight();
28510 if(this.fixedcenter){
28513 if(this.isVisible()){
28514 this.constrainXY();
28515 this.adjustAssets();
28517 this.fireEvent("resize", this, width, height);
28523 * Resizes the dialog to fit the specified content size.
28524 * @param {Number} width
28525 * @param {Number} height
28526 * @return {Roo.BasicDialog} this
28528 setContentSize : function(w, h){
28529 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28530 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28531 //if(!this.el.isBorderBox()){
28532 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28533 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28536 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28537 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28539 this.resizeTo(w, h);
28544 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28545 * executed in response to a particular key being pressed while the dialog is active.
28546 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28547 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28548 * @param {Function} fn The function to call
28549 * @param {Object} scope (optional) The scope of the function
28550 * @return {Roo.BasicDialog} this
28552 addKeyListener : function(key, fn, scope){
28553 var keyCode, shift, ctrl, alt;
28554 if(typeof key == "object" && !(key instanceof Array)){
28555 keyCode = key["key"];
28556 shift = key["shift"];
28557 ctrl = key["ctrl"];
28562 var handler = function(dlg, e){
28563 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28564 var k = e.getKey();
28565 if(keyCode instanceof Array){
28566 for(var i = 0, len = keyCode.length; i < len; i++){
28567 if(keyCode[i] == k){
28568 fn.call(scope || window, dlg, k, e);
28574 fn.call(scope || window, dlg, k, e);
28579 this.on("keydown", handler);
28584 * Returns the TabPanel component (creates it if it doesn't exist).
28585 * Note: If you wish to simply check for the existence of tabs without creating them,
28586 * check for a null 'tabs' property.
28587 * @return {Roo.TabPanel} The tabs component
28589 getTabs : function(){
28591 this.el.addClass("x-dlg-auto-tabs");
28592 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28593 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28599 * Adds a button to the footer section of the dialog.
28600 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28601 * object or a valid Roo.DomHelper element config
28602 * @param {Function} handler The function called when the button is clicked
28603 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28604 * @return {Roo.Button} The new button
28606 addButton : function(config, handler, scope){
28607 var dh = Roo.DomHelper;
28609 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28611 if(!this.btnContainer){
28612 var tb = this.footer.createChild({
28614 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28615 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28617 this.btnContainer = tb.firstChild.firstChild.firstChild;
28622 minWidth: this.minButtonWidth,
28625 if(typeof config == "string"){
28626 bconfig.text = config;
28629 bconfig.dhconfig = config;
28631 Roo.apply(bconfig, config);
28635 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
28636 bconfig.position = Math.max(0, bconfig.position);
28637 fc = this.btnContainer.childNodes[bconfig.position];
28640 var btn = new Roo.Button(
28642 this.btnContainer.insertBefore(document.createElement("td"),fc)
28643 : this.btnContainer.appendChild(document.createElement("td")),
28644 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
28647 this.syncBodyHeight();
28650 * Array of all the buttons that have been added to this dialog via addButton
28655 this.buttons.push(btn);
28660 * Sets the default button to be focused when the dialog is displayed.
28661 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
28662 * @return {Roo.BasicDialog} this
28664 setDefaultButton : function(btn){
28665 this.defaultButton = btn;
28670 getHeaderFooterHeight : function(safe){
28673 height += this.header.getHeight();
28676 var fm = this.footer.getMargins();
28677 height += (this.footer.getHeight()+fm.top+fm.bottom);
28679 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
28680 height += this.centerBg.getPadding("tb");
28685 syncBodyHeight : function(){
28686 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
28687 var height = this.size.height - this.getHeaderFooterHeight(false);
28688 bd.setHeight(height-bd.getMargins("tb"));
28689 var hh = this.header.getHeight();
28690 var h = this.size.height-hh;
28692 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
28693 bw.setHeight(h-cb.getPadding("tb"));
28694 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
28695 bd.setWidth(bw.getWidth(true));
28697 this.tabs.syncHeight();
28699 this.tabs.el.repaint();
28705 * Restores the previous state of the dialog if Roo.state is configured.
28706 * @return {Roo.BasicDialog} this
28708 restoreState : function(){
28709 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
28710 if(box && box.width){
28711 this.xy = [box.x, box.y];
28712 this.resizeTo(box.width, box.height);
28718 beforeShow : function(){
28720 if(this.fixedcenter){
28721 this.xy = this.el.getCenterXY(true);
28724 Roo.get(document.body).addClass("x-body-masked");
28725 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28728 this.constrainXY();
28732 animShow : function(){
28733 var b = Roo.get(this.animateTarget, true).getBox();
28734 this.proxy.setSize(b.width, b.height);
28735 this.proxy.setLocation(b.x, b.y);
28737 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
28738 true, .35, this.showEl.createDelegate(this));
28742 * Shows the dialog.
28743 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
28744 * @return {Roo.BasicDialog} this
28746 show : function(animateTarget){
28747 if (this.fireEvent("beforeshow", this) === false){
28750 if(this.syncHeightBeforeShow){
28751 this.syncBodyHeight();
28752 }else if(this.firstShow){
28753 this.firstShow = false;
28754 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
28756 this.animateTarget = animateTarget || this.animateTarget;
28757 if(!this.el.isVisible()){
28759 if(this.animateTarget){
28769 showEl : function(){
28771 this.el.setXY(this.xy);
28773 this.adjustAssets(true);
28776 // IE peekaboo bug - fix found by Dave Fenwick
28780 this.fireEvent("show", this);
28784 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
28785 * dialog itself will receive focus.
28787 focus : function(){
28788 if(this.defaultButton){
28789 this.defaultButton.focus();
28791 this.focusEl.focus();
28796 constrainXY : function(){
28797 if(this.constraintoviewport !== false){
28798 if(!this.viewSize){
28799 if(this.container){
28800 var s = this.container.getSize();
28801 this.viewSize = [s.width, s.height];
28803 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
28806 var s = Roo.get(this.container||document).getScroll();
28808 var x = this.xy[0], y = this.xy[1];
28809 var w = this.size.width, h = this.size.height;
28810 var vw = this.viewSize[0], vh = this.viewSize[1];
28811 // only move it if it needs it
28813 // first validate right/bottom
28814 if(x + w > vw+s.left){
28818 if(y + h > vh+s.top){
28822 // then make sure top/left isn't negative
28834 if(this.isVisible()){
28835 this.el.setLocation(x, y);
28836 this.adjustAssets();
28843 onDrag : function(){
28844 if(!this.proxyDrag){
28845 this.xy = this.el.getXY();
28846 this.adjustAssets();
28851 adjustAssets : function(doShow){
28852 var x = this.xy[0], y = this.xy[1];
28853 var w = this.size.width, h = this.size.height;
28854 if(doShow === true){
28856 this.shadow.show(this.el);
28862 if(this.shadow && this.shadow.isVisible()){
28863 this.shadow.show(this.el);
28865 if(this.shim && this.shim.isVisible()){
28866 this.shim.setBounds(x, y, w, h);
28871 adjustViewport : function(w, h){
28873 w = Roo.lib.Dom.getViewWidth();
28874 h = Roo.lib.Dom.getViewHeight();
28877 this.viewSize = [w, h];
28878 if(this.modal && this.mask.isVisible()){
28879 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
28880 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28882 if(this.isVisible()){
28883 this.constrainXY();
28888 * Destroys this dialog and all its supporting elements (including any tabs, shim,
28889 * shadow, proxy, mask, etc.) Also removes all event listeners.
28890 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28892 destroy : function(removeEl){
28893 if(this.isVisible()){
28894 this.animateTarget = null;
28897 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
28899 this.tabs.destroy(removeEl);
28912 for(var i = 0, len = this.buttons.length; i < len; i++){
28913 this.buttons[i].destroy();
28916 this.el.removeAllListeners();
28917 if(removeEl === true){
28918 this.el.update("");
28921 Roo.DialogManager.unregister(this);
28925 startMove : function(){
28926 if(this.proxyDrag){
28929 if(this.constraintoviewport !== false){
28930 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
28935 endMove : function(){
28936 if(!this.proxyDrag){
28937 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
28939 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
28942 this.refreshSize();
28943 this.adjustAssets();
28945 this.fireEvent("move", this, this.xy[0], this.xy[1]);
28949 * Brings this dialog to the front of any other visible dialogs
28950 * @return {Roo.BasicDialog} this
28952 toFront : function(){
28953 Roo.DialogManager.bringToFront(this);
28958 * Sends this dialog to the back (under) of any other visible dialogs
28959 * @return {Roo.BasicDialog} this
28961 toBack : function(){
28962 Roo.DialogManager.sendToBack(this);
28967 * Centers this dialog in the viewport
28968 * @return {Roo.BasicDialog} this
28970 center : function(){
28971 var xy = this.el.getCenterXY(true);
28972 this.moveTo(xy[0], xy[1]);
28977 * Moves the dialog's top-left corner to the specified point
28978 * @param {Number} x
28979 * @param {Number} y
28980 * @return {Roo.BasicDialog} this
28982 moveTo : function(x, y){
28984 if(this.isVisible()){
28985 this.el.setXY(this.xy);
28986 this.adjustAssets();
28992 * Aligns the dialog to the specified element
28993 * @param {String/HTMLElement/Roo.Element} element The element to align to.
28994 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
28995 * @param {Array} offsets (optional) Offset the positioning by [x, y]
28996 * @return {Roo.BasicDialog} this
28998 alignTo : function(element, position, offsets){
28999 this.xy = this.el.getAlignToXY(element, position, offsets);
29000 if(this.isVisible()){
29001 this.el.setXY(this.xy);
29002 this.adjustAssets();
29008 * Anchors an element to another element and realigns it when the window is resized.
29009 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29010 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29011 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29012 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29013 * is a number, it is used as the buffer delay (defaults to 50ms).
29014 * @return {Roo.BasicDialog} this
29016 anchorTo : function(el, alignment, offsets, monitorScroll){
29017 var action = function(){
29018 this.alignTo(el, alignment, offsets);
29020 Roo.EventManager.onWindowResize(action, this);
29021 var tm = typeof monitorScroll;
29022 if(tm != 'undefined'){
29023 Roo.EventManager.on(window, 'scroll', action, this,
29024 {buffer: tm == 'number' ? monitorScroll : 50});
29031 * Returns true if the dialog is visible
29032 * @return {Boolean}
29034 isVisible : function(){
29035 return this.el.isVisible();
29039 animHide : function(callback){
29040 var b = Roo.get(this.animateTarget).getBox();
29042 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29044 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29045 this.hideEl.createDelegate(this, [callback]));
29049 * Hides the dialog.
29050 * @param {Function} callback (optional) Function to call when the dialog is hidden
29051 * @return {Roo.BasicDialog} this
29053 hide : function(callback){
29054 if (this.fireEvent("beforehide", this) === false){
29058 this.shadow.hide();
29063 if(this.animateTarget){
29064 this.animHide(callback);
29067 this.hideEl(callback);
29073 hideEl : function(callback){
29077 Roo.get(document.body).removeClass("x-body-masked");
29079 this.fireEvent("hide", this);
29080 if(typeof callback == "function"){
29086 hideAction : function(){
29087 this.setLeft("-10000px");
29088 this.setTop("-10000px");
29089 this.setStyle("visibility", "hidden");
29093 refreshSize : function(){
29094 this.size = this.el.getSize();
29095 this.xy = this.el.getXY();
29096 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29100 // z-index is managed by the DialogManager and may be overwritten at any time
29101 setZIndex : function(index){
29103 this.mask.setStyle("z-index", index);
29106 this.shim.setStyle("z-index", ++index);
29109 this.shadow.setZIndex(++index);
29111 this.el.setStyle("z-index", ++index);
29113 this.proxy.setStyle("z-index", ++index);
29116 this.resizer.proxy.setStyle("z-index", ++index);
29119 this.lastZIndex = index;
29123 * Returns the element for this dialog
29124 * @return {Roo.Element} The underlying dialog Element
29126 getEl : function(){
29132 * @class Roo.DialogManager
29133 * Provides global access to BasicDialogs that have been created and
29134 * support for z-indexing (layering) multiple open dialogs.
29136 Roo.DialogManager = function(){
29138 var accessList = [];
29142 var sortDialogs = function(d1, d2){
29143 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29147 var orderDialogs = function(){
29148 accessList.sort(sortDialogs);
29149 var seed = Roo.DialogManager.zseed;
29150 for(var i = 0, len = accessList.length; i < len; i++){
29151 var dlg = accessList[i];
29153 dlg.setZIndex(seed + (i*10));
29160 * The starting z-index for BasicDialogs (defaults to 9000)
29161 * @type Number The z-index value
29166 register : function(dlg){
29167 list[dlg.id] = dlg;
29168 accessList.push(dlg);
29172 unregister : function(dlg){
29173 delete list[dlg.id];
29176 if(!accessList.indexOf){
29177 for( i = 0, len = accessList.length; i < len; i++){
29178 if(accessList[i] == dlg){
29179 accessList.splice(i, 1);
29184 i = accessList.indexOf(dlg);
29186 accessList.splice(i, 1);
29192 * Gets a registered dialog by id
29193 * @param {String/Object} id The id of the dialog or a dialog
29194 * @return {Roo.BasicDialog} this
29196 get : function(id){
29197 return typeof id == "object" ? id : list[id];
29201 * Brings the specified dialog to the front
29202 * @param {String/Object} dlg The id of the dialog or a dialog
29203 * @return {Roo.BasicDialog} this
29205 bringToFront : function(dlg){
29206 dlg = this.get(dlg);
29209 dlg._lastAccess = new Date().getTime();
29216 * Sends the specified dialog to the back
29217 * @param {String/Object} dlg The id of the dialog or a dialog
29218 * @return {Roo.BasicDialog} this
29220 sendToBack : function(dlg){
29221 dlg = this.get(dlg);
29222 dlg._lastAccess = -(new Date().getTime());
29228 * Hides all dialogs
29230 hideAll : function(){
29231 for(var id in list){
29232 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29241 * @class Roo.LayoutDialog
29242 * @extends Roo.BasicDialog
29243 * Dialog which provides adjustments for working with a layout in a Dialog.
29244 * Add your necessary layout config options to the dialog's config.<br>
29245 * Example usage (including a nested layout):
29248 dialog = new Roo.LayoutDialog("download-dlg", {
29257 // layout config merges with the dialog config
29259 tabPosition: "top",
29260 alwaysShowTabs: true
29263 dialog.addKeyListener(27, dialog.hide, dialog);
29264 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29265 dialog.addButton("Build It!", this.getDownload, this);
29267 // we can even add nested layouts
29268 var innerLayout = new Roo.BorderLayout("dl-inner", {
29278 innerLayout.beginUpdate();
29279 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29280 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29281 innerLayout.endUpdate(true);
29283 var layout = dialog.getLayout();
29284 layout.beginUpdate();
29285 layout.add("center", new Roo.ContentPanel("standard-panel",
29286 {title: "Download the Source", fitToFrame:true}));
29287 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29288 {title: "Build your own roo.js"}));
29289 layout.getRegion("center").showPanel(sp);
29290 layout.endUpdate();
29294 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29295 * @param {Object} config configuration options
29297 Roo.LayoutDialog = function(el, cfg){
29300 if (typeof(cfg) == 'undefined') {
29301 config = Roo.apply({}, el);
29302 el = Roo.get( document.documentElement || document.body).createChild();
29303 //config.autoCreate = true;
29307 config.autoTabs = false;
29308 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29309 this.body.setStyle({overflow:"hidden", position:"relative"});
29310 this.layout = new Roo.BorderLayout(this.body.dom, config);
29311 this.layout.monitorWindowResize = false;
29312 this.el.addClass("x-dlg-auto-layout");
29313 // fix case when center region overwrites center function
29314 this.center = Roo.BasicDialog.prototype.center;
29315 this.on("show", this.layout.layout, this.layout, true);
29316 if (config.items) {
29317 var xitems = config.items;
29318 delete config.items;
29319 Roo.each(xitems, this.addxtype, this);
29324 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29326 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29329 endUpdate : function(){
29330 this.layout.endUpdate();
29334 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29337 beginUpdate : function(){
29338 this.layout.beginUpdate();
29342 * Get the BorderLayout for this dialog
29343 * @return {Roo.BorderLayout}
29345 getLayout : function(){
29346 return this.layout;
29349 showEl : function(){
29350 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29352 this.layout.layout();
29357 // Use the syncHeightBeforeShow config option to control this automatically
29358 syncBodyHeight : function(){
29359 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29360 if(this.layout){this.layout.layout();}
29364 * Add an xtype element (actually adds to the layout.)
29365 * @return {Object} xdata xtype object data.
29368 addxtype : function(c) {
29369 return this.layout.addxtype(c);
29373 * Ext JS Library 1.1.1
29374 * Copyright(c) 2006-2007, Ext JS, LLC.
29376 * Originally Released Under LGPL - original licence link has changed is not relivant.
29379 * <script type="text/javascript">
29383 * @class Roo.MessageBox
29384 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29388 Roo.Msg.alert('Status', 'Changes saved successfully.');
29390 // Prompt for user data:
29391 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29393 // process text value...
29397 // Show a dialog using config options:
29399 title:'Save Changes?',
29400 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29401 buttons: Roo.Msg.YESNOCANCEL,
29408 Roo.MessageBox = function(){
29409 var dlg, opt, mask, waitTimer;
29410 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29411 var buttons, activeTextEl, bwidth;
29414 var handleButton = function(button){
29416 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29420 var handleHide = function(){
29421 if(opt && opt.cls){
29422 dlg.el.removeClass(opt.cls);
29425 Roo.TaskMgr.stop(waitTimer);
29431 var updateButtons = function(b){
29434 buttons["ok"].hide();
29435 buttons["cancel"].hide();
29436 buttons["yes"].hide();
29437 buttons["no"].hide();
29438 dlg.footer.dom.style.display = 'none';
29441 dlg.footer.dom.style.display = '';
29442 for(var k in buttons){
29443 if(typeof buttons[k] != "function"){
29446 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29447 width += buttons[k].el.getWidth()+15;
29457 var handleEsc = function(d, k, e){
29458 if(opt && opt.closable !== false){
29468 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29469 * @return {Roo.BasicDialog} The BasicDialog element
29471 getDialog : function(){
29473 dlg = new Roo.BasicDialog("x-msg-box", {
29478 constraintoviewport:false,
29480 collapsible : false,
29483 width:400, height:100,
29484 buttonAlign:"center",
29485 closeClick : function(){
29486 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29487 handleButton("no");
29489 handleButton("cancel");
29493 dlg.on("hide", handleHide);
29495 dlg.addKeyListener(27, handleEsc);
29497 var bt = this.buttonText;
29498 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29499 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29500 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29501 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29502 bodyEl = dlg.body.createChild({
29504 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>'
29506 msgEl = bodyEl.dom.firstChild;
29507 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29508 textboxEl.enableDisplayMode();
29509 textboxEl.addKeyListener([10,13], function(){
29510 if(dlg.isVisible() && opt && opt.buttons){
29511 if(opt.buttons.ok){
29512 handleButton("ok");
29513 }else if(opt.buttons.yes){
29514 handleButton("yes");
29518 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29519 textareaEl.enableDisplayMode();
29520 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29521 progressEl.enableDisplayMode();
29522 var pf = progressEl.dom.firstChild;
29524 pp = Roo.get(pf.firstChild);
29525 pp.setHeight(pf.offsetHeight);
29533 * Updates the message box body text
29534 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29535 * the XHTML-compliant non-breaking space character '&#160;')
29536 * @return {Roo.MessageBox} This message box
29538 updateText : function(text){
29539 if(!dlg.isVisible() && !opt.width){
29540 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29542 msgEl.innerHTML = text || ' ';
29543 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29544 Math.max(opt.minWidth || this.minWidth, bwidth));
29546 activeTextEl.setWidth(w);
29548 if(dlg.isVisible()){
29549 dlg.fixedcenter = false;
29551 dlg.setContentSize(w, bodyEl.getHeight());
29552 if(dlg.isVisible()){
29553 dlg.fixedcenter = true;
29559 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29560 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29561 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29562 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29563 * @return {Roo.MessageBox} This message box
29565 updateProgress : function(value, text){
29567 this.updateText(text);
29569 if (pp) { // weird bug on my firefox - for some reason this is not defined
29570 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29576 * Returns true if the message box is currently displayed
29577 * @return {Boolean} True if the message box is visible, else false
29579 isVisible : function(){
29580 return dlg && dlg.isVisible();
29584 * Hides the message box if it is displayed
29587 if(this.isVisible()){
29593 * Displays a new message box, or reinitializes an existing message box, based on the config options
29594 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29595 * The following config object properties are supported:
29597 Property Type Description
29598 ---------- --------------- ------------------------------------------------------------------------------------
29599 animEl String/Element An id or Element from which the message box should animate as it opens and
29600 closes (defaults to undefined)
29601 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29602 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29603 closable Boolean False to hide the top-right close button (defaults to true). Note that
29604 progress and wait dialogs will ignore this property and always hide the
29605 close button as they can only be closed programmatically.
29606 cls String A custom CSS class to apply to the message box element
29607 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29608 displayed (defaults to 75)
29609 fn Function A callback function to execute after closing the dialog. The arguments to the
29610 function will be btn (the name of the button that was clicked, if applicable,
29611 e.g. "ok"), and text (the value of the active text field, if applicable).
29612 Progress and wait dialogs will ignore this option since they do not respond to
29613 user actions and can only be closed programmatically, so any required function
29614 should be called by the same code after it closes the dialog.
29615 icon String A CSS class that provides a background image to be used as an icon for
29616 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29617 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29618 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29619 modal Boolean False to allow user interaction with the page while the message box is
29620 displayed (defaults to true)
29621 msg String A string that will replace the existing message box body text (defaults
29622 to the XHTML-compliant non-breaking space character ' ')
29623 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
29624 progress Boolean True to display a progress bar (defaults to false)
29625 progressText String The text to display inside the progress bar if progress = true (defaults to '')
29626 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
29627 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
29628 title String The title text
29629 value String The string value to set into the active textbox element if displayed
29630 wait Boolean True to display a progress bar (defaults to false)
29631 width Number The width of the dialog in pixels
29638 msg: 'Please enter your address:',
29640 buttons: Roo.MessageBox.OKCANCEL,
29643 animEl: 'addAddressBtn'
29646 * @param {Object} config Configuration options
29647 * @return {Roo.MessageBox} This message box
29649 show : function(options){
29650 if(this.isVisible()){
29653 var d = this.getDialog();
29655 d.setTitle(opt.title || " ");
29656 d.close.setDisplayed(opt.closable !== false);
29657 activeTextEl = textboxEl;
29658 opt.prompt = opt.prompt || (opt.multiline ? true : false);
29663 textareaEl.setHeight(typeof opt.multiline == "number" ?
29664 opt.multiline : this.defaultTextHeight);
29665 activeTextEl = textareaEl;
29674 progressEl.setDisplayed(opt.progress === true);
29675 this.updateProgress(0);
29676 activeTextEl.dom.value = opt.value || "";
29678 dlg.setDefaultButton(activeTextEl);
29680 var bs = opt.buttons;
29683 db = buttons["ok"];
29684 }else if(bs && bs.yes){
29685 db = buttons["yes"];
29687 dlg.setDefaultButton(db);
29689 bwidth = updateButtons(opt.buttons);
29690 this.updateText(opt.msg);
29692 d.el.addClass(opt.cls);
29694 d.proxyDrag = opt.proxyDrag === true;
29695 d.modal = opt.modal !== false;
29696 d.mask = opt.modal !== false ? mask : false;
29697 if(!d.isVisible()){
29698 // force it to the end of the z-index stack so it gets a cursor in FF
29699 document.body.appendChild(dlg.el.dom);
29700 d.animateTarget = null;
29701 d.show(options.animEl);
29707 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
29708 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
29709 * and closing the message box when the process is complete.
29710 * @param {String} title The title bar text
29711 * @param {String} msg The message box body text
29712 * @return {Roo.MessageBox} This message box
29714 progress : function(title, msg){
29721 minWidth: this.minProgressWidth,
29728 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
29729 * If a callback function is passed it will be called after the user clicks the button, and the
29730 * id of the button that was clicked will be passed as the only parameter to the callback
29731 * (could also be the top-right close button).
29732 * @param {String} title The title bar text
29733 * @param {String} msg The message box body text
29734 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29735 * @param {Object} scope (optional) The scope of the callback function
29736 * @return {Roo.MessageBox} This message box
29738 alert : function(title, msg, fn, scope){
29751 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
29752 * interaction while waiting for a long-running process to complete that does not have defined intervals.
29753 * You are responsible for closing the message box when the process is complete.
29754 * @param {String} msg The message box body text
29755 * @param {String} title (optional) The title bar text
29756 * @return {Roo.MessageBox} This message box
29758 wait : function(msg, title){
29769 waitTimer = Roo.TaskMgr.start({
29771 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
29779 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
29780 * If a callback function is passed it will be called after the user clicks either button, and the id of the
29781 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
29782 * @param {String} title The title bar text
29783 * @param {String} msg The message box body text
29784 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29785 * @param {Object} scope (optional) The scope of the callback function
29786 * @return {Roo.MessageBox} This message box
29788 confirm : function(title, msg, fn, scope){
29792 buttons: this.YESNO,
29801 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
29802 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
29803 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
29804 * (could also be the top-right close button) and the text that was entered will be passed as the two
29805 * parameters to the callback.
29806 * @param {String} title The title bar text
29807 * @param {String} msg The message box body text
29808 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29809 * @param {Object} scope (optional) The scope of the callback function
29810 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
29811 * property, or the height in pixels to create the textbox (defaults to false / single-line)
29812 * @return {Roo.MessageBox} This message box
29814 prompt : function(title, msg, fn, scope, multiline){
29818 buttons: this.OKCANCEL,
29823 multiline: multiline,
29830 * Button config that displays a single OK button
29835 * Button config that displays Yes and No buttons
29838 YESNO : {yes:true, no:true},
29840 * Button config that displays OK and Cancel buttons
29843 OKCANCEL : {ok:true, cancel:true},
29845 * Button config that displays Yes, No and Cancel buttons
29848 YESNOCANCEL : {yes:true, no:true, cancel:true},
29851 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
29854 defaultTextHeight : 75,
29856 * The maximum width in pixels of the message box (defaults to 600)
29861 * The minimum width in pixels of the message box (defaults to 100)
29866 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
29867 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
29870 minProgressWidth : 250,
29872 * An object containing the default button text strings that can be overriden for localized language support.
29873 * Supported properties are: ok, cancel, yes and no.
29874 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
29887 * Shorthand for {@link Roo.MessageBox}
29889 Roo.Msg = Roo.MessageBox;/*
29891 * Ext JS Library 1.1.1
29892 * Copyright(c) 2006-2007, Ext JS, LLC.
29894 * Originally Released Under LGPL - original licence link has changed is not relivant.
29897 * <script type="text/javascript">
29900 * @class Roo.QuickTips
29901 * Provides attractive and customizable tooltips for any element.
29904 Roo.QuickTips = function(){
29905 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
29906 var ce, bd, xy, dd;
29907 var visible = false, disabled = true, inited = false;
29908 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
29910 var onOver = function(e){
29914 var t = e.getTarget();
29915 if(!t || t.nodeType !== 1 || t == document || t == document.body){
29918 if(ce && t == ce.el){
29919 clearTimeout(hideProc);
29922 if(t && tagEls[t.id]){
29923 tagEls[t.id].el = t;
29924 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
29927 var ttp, et = Roo.fly(t);
29928 var ns = cfg.namespace;
29929 if(tm.interceptTitles && t.title){
29932 t.removeAttribute("title");
29933 e.preventDefault();
29935 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
29938 showProc = show.defer(tm.showDelay, tm, [{
29941 width: et.getAttributeNS(ns, cfg.width),
29942 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
29943 title: et.getAttributeNS(ns, cfg.title),
29944 cls: et.getAttributeNS(ns, cfg.cls)
29949 var onOut = function(e){
29950 clearTimeout(showProc);
29951 var t = e.getTarget();
29952 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
29953 hideProc = setTimeout(hide, tm.hideDelay);
29957 var onMove = function(e){
29963 if(tm.trackMouse && ce){
29968 var onDown = function(e){
29969 clearTimeout(showProc);
29970 clearTimeout(hideProc);
29972 if(tm.hideOnClick){
29975 tm.enable.defer(100, tm);
29980 var getPad = function(){
29981 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
29984 var show = function(o){
29988 clearTimeout(dismissProc);
29990 if(removeCls){ // in case manually hidden
29991 el.removeClass(removeCls);
29995 el.addClass(ce.cls);
29996 removeCls = ce.cls;
29999 tipTitle.update(ce.title);
30002 tipTitle.update('');
30005 el.dom.style.width = tm.maxWidth+'px';
30006 //tipBody.dom.style.width = '';
30007 tipBodyText.update(o.text);
30008 var p = getPad(), w = ce.width;
30010 var td = tipBodyText.dom;
30011 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30012 if(aw > tm.maxWidth){
30014 }else if(aw < tm.minWidth){
30020 //tipBody.setWidth(w);
30021 el.setWidth(parseInt(w, 10) + p);
30022 if(ce.autoHide === false){
30023 close.setDisplayed(true);
30028 close.setDisplayed(false);
30034 el.avoidY = xy[1]-18;
30039 el.setStyle("visibility", "visible");
30040 el.fadeIn({callback: afterShow});
30046 var afterShow = function(){
30050 if(tm.autoDismiss && ce.autoHide !== false){
30051 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30056 var hide = function(noanim){
30057 clearTimeout(dismissProc);
30058 clearTimeout(hideProc);
30060 if(el.isVisible()){
30062 if(noanim !== true && tm.animate){
30063 el.fadeOut({callback: afterHide});
30070 var afterHide = function(){
30073 el.removeClass(removeCls);
30080 * @cfg {Number} minWidth
30081 * The minimum width of the quick tip (defaults to 40)
30085 * @cfg {Number} maxWidth
30086 * The maximum width of the quick tip (defaults to 300)
30090 * @cfg {Boolean} interceptTitles
30091 * True to automatically use the element's DOM title value if available (defaults to false)
30093 interceptTitles : false,
30095 * @cfg {Boolean} trackMouse
30096 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30098 trackMouse : false,
30100 * @cfg {Boolean} hideOnClick
30101 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30103 hideOnClick : true,
30105 * @cfg {Number} showDelay
30106 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30110 * @cfg {Number} hideDelay
30111 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30115 * @cfg {Boolean} autoHide
30116 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30117 * Used in conjunction with hideDelay.
30122 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30123 * (defaults to true). Used in conjunction with autoDismissDelay.
30125 autoDismiss : true,
30128 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30130 autoDismissDelay : 5000,
30132 * @cfg {Boolean} animate
30133 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30138 * @cfg {String} title
30139 * Title text to display (defaults to ''). This can be any valid HTML markup.
30143 * @cfg {String} text
30144 * Body text to display (defaults to ''). This can be any valid HTML markup.
30148 * @cfg {String} cls
30149 * A CSS class to apply to the base quick tip element (defaults to '').
30153 * @cfg {Number} width
30154 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30155 * minWidth or maxWidth.
30160 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30161 * or display QuickTips in a page.
30164 tm = Roo.QuickTips;
30165 cfg = tm.tagConfig;
30167 if(!Roo.isReady){ // allow calling of init() before onReady
30168 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30171 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30172 el.fxDefaults = {stopFx: true};
30173 // maximum custom styling
30174 //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>');
30175 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>');
30176 tipTitle = el.child('h3');
30177 tipTitle.enableDisplayMode("block");
30178 tipBody = el.child('div.x-tip-bd');
30179 tipBodyText = el.child('div.x-tip-bd-inner');
30180 //bdLeft = el.child('div.x-tip-bd-left');
30181 //bdRight = el.child('div.x-tip-bd-right');
30182 close = el.child('div.x-tip-close');
30183 close.enableDisplayMode("block");
30184 close.on("click", hide);
30185 var d = Roo.get(document);
30186 d.on("mousedown", onDown);
30187 d.on("mouseover", onOver);
30188 d.on("mouseout", onOut);
30189 d.on("mousemove", onMove);
30190 esc = d.addKeyListener(27, hide);
30193 dd = el.initDD("default", null, {
30194 onDrag : function(){
30198 dd.setHandleElId(tipTitle.id);
30207 * Configures a new quick tip instance and assigns it to a target element. The following config options
30210 Property Type Description
30211 ---------- --------------------- ------------------------------------------------------------------------
30212 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30214 * @param {Object} config The config object
30216 register : function(config){
30217 var cs = config instanceof Array ? config : arguments;
30218 for(var i = 0, len = cs.length; i < len; i++) {
30220 var target = c.target;
30222 if(target instanceof Array){
30223 for(var j = 0, jlen = target.length; j < jlen; j++){
30224 tagEls[target[j]] = c;
30227 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30234 * Removes this quick tip from its element and destroys it.
30235 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30237 unregister : function(el){
30238 delete tagEls[Roo.id(el)];
30242 * Enable this quick tip.
30244 enable : function(){
30245 if(inited && disabled){
30247 if(locks.length < 1){
30254 * Disable this quick tip.
30256 disable : function(){
30258 clearTimeout(showProc);
30259 clearTimeout(hideProc);
30260 clearTimeout(dismissProc);
30268 * Returns true if the quick tip is enabled, else false.
30270 isEnabled : function(){
30277 attribute : "qtip",
30287 // backwards compat
30288 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30290 * Ext JS Library 1.1.1
30291 * Copyright(c) 2006-2007, Ext JS, LLC.
30293 * Originally Released Under LGPL - original licence link has changed is not relivant.
30296 * <script type="text/javascript">
30301 * @class Roo.tree.TreePanel
30302 * @extends Roo.data.Tree
30304 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30305 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30306 * @cfg {Boolean} enableDD true to enable drag and drop
30307 * @cfg {Boolean} enableDrag true to enable just drag
30308 * @cfg {Boolean} enableDrop true to enable just drop
30309 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30310 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30311 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30312 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30313 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30314 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30315 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30316 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30317 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30318 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30319 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30320 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30321 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30322 * @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>
30323 * @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>
30326 * @param {String/HTMLElement/Element} el The container element
30327 * @param {Object} config
30329 Roo.tree.TreePanel = function(el, config){
30331 var loader = false;
30333 root = config.root;
30334 delete config.root;
30336 if (config.loader) {
30337 loader = config.loader;
30338 delete config.loader;
30341 Roo.apply(this, config);
30342 Roo.tree.TreePanel.superclass.constructor.call(this);
30343 this.el = Roo.get(el);
30344 this.el.addClass('x-tree');
30345 //console.log(root);
30347 this.setRootNode( Roo.factory(root, Roo.tree));
30350 this.loader = Roo.factory(loader, Roo.tree);
30353 * Read-only. The id of the container element becomes this TreePanel's id.
30355 this.id = this.el.id;
30358 * @event beforeload
30359 * Fires before a node is loaded, return false to cancel
30360 * @param {Node} node The node being loaded
30362 "beforeload" : true,
30365 * Fires when a node is loaded
30366 * @param {Node} node The node that was loaded
30370 * @event textchange
30371 * Fires when the text for a node is changed
30372 * @param {Node} node The node
30373 * @param {String} text The new text
30374 * @param {String} oldText The old text
30376 "textchange" : true,
30378 * @event beforeexpand
30379 * Fires before a node is expanded, return false to cancel.
30380 * @param {Node} node The node
30381 * @param {Boolean} deep
30382 * @param {Boolean} anim
30384 "beforeexpand" : true,
30386 * @event beforecollapse
30387 * Fires before a node is collapsed, return false to cancel.
30388 * @param {Node} node The node
30389 * @param {Boolean} deep
30390 * @param {Boolean} anim
30392 "beforecollapse" : true,
30395 * Fires when a node is expanded
30396 * @param {Node} node The node
30400 * @event disabledchange
30401 * Fires when the disabled status of a node changes
30402 * @param {Node} node The node
30403 * @param {Boolean} disabled
30405 "disabledchange" : true,
30408 * Fires when a node is collapsed
30409 * @param {Node} node The node
30413 * @event beforeclick
30414 * Fires before click processing on a node. Return false to cancel the default action.
30415 * @param {Node} node The node
30416 * @param {Roo.EventObject} e The event object
30418 "beforeclick":true,
30420 * @event checkchange
30421 * Fires when a node with a checkbox's checked property changes
30422 * @param {Node} this This node
30423 * @param {Boolean} checked
30425 "checkchange":true,
30428 * Fires when a node is clicked
30429 * @param {Node} node The node
30430 * @param {Roo.EventObject} e The event object
30435 * Fires when a node is double clicked
30436 * @param {Node} node The node
30437 * @param {Roo.EventObject} e The event object
30441 * @event contextmenu
30442 * Fires when a node is right clicked
30443 * @param {Node} node The node
30444 * @param {Roo.EventObject} e The event object
30446 "contextmenu":true,
30448 * @event beforechildrenrendered
30449 * Fires right before the child nodes for a node are rendered
30450 * @param {Node} node The node
30452 "beforechildrenrendered":true,
30455 * Fires when a node starts being dragged
30456 * @param {Roo.tree.TreePanel} this
30457 * @param {Roo.tree.TreeNode} node
30458 * @param {event} e The raw browser event
30460 "startdrag" : true,
30463 * Fires when a drag operation is complete
30464 * @param {Roo.tree.TreePanel} this
30465 * @param {Roo.tree.TreeNode} node
30466 * @param {event} e The raw browser event
30471 * Fires when a dragged node is dropped on a valid DD target
30472 * @param {Roo.tree.TreePanel} this
30473 * @param {Roo.tree.TreeNode} node
30474 * @param {DD} dd The dd it was dropped on
30475 * @param {event} e The raw browser event
30479 * @event beforenodedrop
30480 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30481 * passed to handlers has the following properties:<br />
30482 * <ul style="padding:5px;padding-left:16px;">
30483 * <li>tree - The TreePanel</li>
30484 * <li>target - The node being targeted for the drop</li>
30485 * <li>data - The drag data from the drag source</li>
30486 * <li>point - The point of the drop - append, above or below</li>
30487 * <li>source - The drag source</li>
30488 * <li>rawEvent - Raw mouse event</li>
30489 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30490 * to be inserted by setting them on this object.</li>
30491 * <li>cancel - Set this to true to cancel the drop.</li>
30493 * @param {Object} dropEvent
30495 "beforenodedrop" : true,
30498 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30499 * passed to handlers has the following properties:<br />
30500 * <ul style="padding:5px;padding-left:16px;">
30501 * <li>tree - The TreePanel</li>
30502 * <li>target - The node being targeted for the drop</li>
30503 * <li>data - The drag data from the drag source</li>
30504 * <li>point - The point of the drop - append, above or below</li>
30505 * <li>source - The drag source</li>
30506 * <li>rawEvent - Raw mouse event</li>
30507 * <li>dropNode - Dropped node(s).</li>
30509 * @param {Object} dropEvent
30513 * @event nodedragover
30514 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30515 * passed to handlers has the following properties:<br />
30516 * <ul style="padding:5px;padding-left:16px;">
30517 * <li>tree - The TreePanel</li>
30518 * <li>target - The node being targeted for the drop</li>
30519 * <li>data - The drag data from the drag source</li>
30520 * <li>point - The point of the drop - append, above or below</li>
30521 * <li>source - The drag source</li>
30522 * <li>rawEvent - Raw mouse event</li>
30523 * <li>dropNode - Drop node(s) provided by the source.</li>
30524 * <li>cancel - Set this to true to signal drop not allowed.</li>
30526 * @param {Object} dragOverEvent
30528 "nodedragover" : true
30531 if(this.singleExpand){
30532 this.on("beforeexpand", this.restrictExpand, this);
30535 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30536 rootVisible : true,
30537 animate: Roo.enableFx,
30540 hlDrop : Roo.enableFx,
30544 rendererTip: false,
30546 restrictExpand : function(node){
30547 var p = node.parentNode;
30549 if(p.expandedChild && p.expandedChild.parentNode == p){
30550 p.expandedChild.collapse();
30552 p.expandedChild = node;
30556 // private override
30557 setRootNode : function(node){
30558 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30559 if(!this.rootVisible){
30560 node.ui = new Roo.tree.RootTreeNodeUI(node);
30566 * Returns the container element for this TreePanel
30568 getEl : function(){
30573 * Returns the default TreeLoader for this TreePanel
30575 getLoader : function(){
30576 return this.loader;
30582 expandAll : function(){
30583 this.root.expand(true);
30587 * Collapse all nodes
30589 collapseAll : function(){
30590 this.root.collapse(true);
30594 * Returns the selection model used by this TreePanel
30596 getSelectionModel : function(){
30597 if(!this.selModel){
30598 this.selModel = new Roo.tree.DefaultSelectionModel();
30600 return this.selModel;
30604 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30605 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30606 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30609 getChecked : function(a, startNode){
30610 startNode = startNode || this.root;
30612 var f = function(){
30613 if(this.attributes.checked){
30614 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30617 startNode.cascade(f);
30622 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30623 * @param {String} path
30624 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30625 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
30626 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
30628 expandPath : function(path, attr, callback){
30629 attr = attr || "id";
30630 var keys = path.split(this.pathSeparator);
30631 var curNode = this.root;
30632 if(curNode.attributes[attr] != keys[1]){ // invalid root
30634 callback(false, null);
30639 var f = function(){
30640 if(++index == keys.length){
30642 callback(true, curNode);
30646 var c = curNode.findChild(attr, keys[index]);
30649 callback(false, curNode);
30654 c.expand(false, false, f);
30656 curNode.expand(false, false, f);
30660 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30661 * @param {String} path
30662 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30663 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
30664 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
30666 selectPath : function(path, attr, callback){
30667 attr = attr || "id";
30668 var keys = path.split(this.pathSeparator);
30669 var v = keys.pop();
30670 if(keys.length > 0){
30671 var f = function(success, node){
30672 if(success && node){
30673 var n = node.findChild(attr, v);
30679 }else if(callback){
30680 callback(false, n);
30684 callback(false, n);
30688 this.expandPath(keys.join(this.pathSeparator), attr, f);
30690 this.root.select();
30692 callback(true, this.root);
30697 getTreeEl : function(){
30702 * Trigger rendering of this TreePanel
30704 render : function(){
30705 if (this.innerCt) {
30706 return this; // stop it rendering more than once!!
30709 this.innerCt = this.el.createChild({tag:"ul",
30710 cls:"x-tree-root-ct " +
30711 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
30713 if(this.containerScroll){
30714 Roo.dd.ScrollManager.register(this.el);
30716 if((this.enableDD || this.enableDrop) && !this.dropZone){
30718 * The dropZone used by this tree if drop is enabled
30719 * @type Roo.tree.TreeDropZone
30721 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
30722 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
30725 if((this.enableDD || this.enableDrag) && !this.dragZone){
30727 * The dragZone used by this tree if drag is enabled
30728 * @type Roo.tree.TreeDragZone
30730 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
30731 ddGroup: this.ddGroup || "TreeDD",
30732 scroll: this.ddScroll
30735 this.getSelectionModel().init(this);
30737 console.log("ROOT not set in tree");
30740 this.root.render();
30741 if(!this.rootVisible){
30742 this.root.renderChildren();
30748 * Ext JS Library 1.1.1
30749 * Copyright(c) 2006-2007, Ext JS, LLC.
30751 * Originally Released Under LGPL - original licence link has changed is not relivant.
30754 * <script type="text/javascript">
30759 * @class Roo.tree.DefaultSelectionModel
30760 * @extends Roo.util.Observable
30761 * The default single selection for a TreePanel.
30763 Roo.tree.DefaultSelectionModel = function(){
30764 this.selNode = null;
30768 * @event selectionchange
30769 * Fires when the selected node changes
30770 * @param {DefaultSelectionModel} this
30771 * @param {TreeNode} node the new selection
30773 "selectionchange" : true,
30776 * @event beforeselect
30777 * Fires before the selected node changes, return false to cancel the change
30778 * @param {DefaultSelectionModel} this
30779 * @param {TreeNode} node the new selection
30780 * @param {TreeNode} node the old selection
30782 "beforeselect" : true
30786 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
30787 init : function(tree){
30789 tree.getTreeEl().on("keydown", this.onKeyDown, this);
30790 tree.on("click", this.onNodeClick, this);
30793 onNodeClick : function(node, e){
30794 if (e.ctrlKey && this.selNode == node) {
30795 this.unselect(node);
30803 * @param {TreeNode} node The node to select
30804 * @return {TreeNode} The selected node
30806 select : function(node){
30807 var last = this.selNode;
30808 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
30810 last.ui.onSelectedChange(false);
30812 this.selNode = node;
30813 node.ui.onSelectedChange(true);
30814 this.fireEvent("selectionchange", this, node, last);
30821 * @param {TreeNode} node The node to unselect
30823 unselect : function(node){
30824 if(this.selNode == node){
30825 this.clearSelections();
30830 * Clear all selections
30832 clearSelections : function(){
30833 var n = this.selNode;
30835 n.ui.onSelectedChange(false);
30836 this.selNode = null;
30837 this.fireEvent("selectionchange", this, null);
30843 * Get the selected node
30844 * @return {TreeNode} The selected node
30846 getSelectedNode : function(){
30847 return this.selNode;
30851 * Returns true if the node is selected
30852 * @param {TreeNode} node The node to check
30853 * @return {Boolean}
30855 isSelected : function(node){
30856 return this.selNode == node;
30860 * Selects the node above the selected node in the tree, intelligently walking the nodes
30861 * @return TreeNode The new selection
30863 selectPrevious : function(){
30864 var s = this.selNode || this.lastSelNode;
30868 var ps = s.previousSibling;
30870 if(!ps.isExpanded() || ps.childNodes.length < 1){
30871 return this.select(ps);
30873 var lc = ps.lastChild;
30874 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
30877 return this.select(lc);
30879 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
30880 return this.select(s.parentNode);
30886 * Selects the node above the selected node in the tree, intelligently walking the nodes
30887 * @return TreeNode The new selection
30889 selectNext : function(){
30890 var s = this.selNode || this.lastSelNode;
30894 if(s.firstChild && s.isExpanded()){
30895 return this.select(s.firstChild);
30896 }else if(s.nextSibling){
30897 return this.select(s.nextSibling);
30898 }else if(s.parentNode){
30900 s.parentNode.bubble(function(){
30901 if(this.nextSibling){
30902 newS = this.getOwnerTree().selModel.select(this.nextSibling);
30911 onKeyDown : function(e){
30912 var s = this.selNode || this.lastSelNode;
30913 // undesirable, but required
30918 var k = e.getKey();
30926 this.selectPrevious();
30929 e.preventDefault();
30930 if(s.hasChildNodes()){
30931 if(!s.isExpanded()){
30933 }else if(s.firstChild){
30934 this.select(s.firstChild, e);
30939 e.preventDefault();
30940 if(s.hasChildNodes() && s.isExpanded()){
30942 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
30943 this.select(s.parentNode, e);
30951 * @class Roo.tree.MultiSelectionModel
30952 * @extends Roo.util.Observable
30953 * Multi selection for a TreePanel.
30955 Roo.tree.MultiSelectionModel = function(){
30956 this.selNodes = [];
30960 * @event selectionchange
30961 * Fires when the selected nodes change
30962 * @param {MultiSelectionModel} this
30963 * @param {Array} nodes Array of the selected nodes
30965 "selectionchange" : true
30969 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
30970 init : function(tree){
30972 tree.getTreeEl().on("keydown", this.onKeyDown, this);
30973 tree.on("click", this.onNodeClick, this);
30976 onNodeClick : function(node, e){
30977 this.select(node, e, e.ctrlKey);
30982 * @param {TreeNode} node The node to select
30983 * @param {EventObject} e (optional) An event associated with the selection
30984 * @param {Boolean} keepExisting True to retain existing selections
30985 * @return {TreeNode} The selected node
30987 select : function(node, e, keepExisting){
30988 if(keepExisting !== true){
30989 this.clearSelections(true);
30991 if(this.isSelected(node)){
30992 this.lastSelNode = node;
30995 this.selNodes.push(node);
30996 this.selMap[node.id] = node;
30997 this.lastSelNode = node;
30998 node.ui.onSelectedChange(true);
30999 this.fireEvent("selectionchange", this, this.selNodes);
31005 * @param {TreeNode} node The node to unselect
31007 unselect : function(node){
31008 if(this.selMap[node.id]){
31009 node.ui.onSelectedChange(false);
31010 var sn = this.selNodes;
31013 index = sn.indexOf(node);
31015 for(var i = 0, len = sn.length; i < len; i++){
31023 this.selNodes.splice(index, 1);
31025 delete this.selMap[node.id];
31026 this.fireEvent("selectionchange", this, this.selNodes);
31031 * Clear all selections
31033 clearSelections : function(suppressEvent){
31034 var sn = this.selNodes;
31036 for(var i = 0, len = sn.length; i < len; i++){
31037 sn[i].ui.onSelectedChange(false);
31039 this.selNodes = [];
31041 if(suppressEvent !== true){
31042 this.fireEvent("selectionchange", this, this.selNodes);
31048 * Returns true if the node is selected
31049 * @param {TreeNode} node The node to check
31050 * @return {Boolean}
31052 isSelected : function(node){
31053 return this.selMap[node.id] ? true : false;
31057 * Returns an array of the selected nodes
31060 getSelectedNodes : function(){
31061 return this.selNodes;
31064 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31066 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31068 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31071 * Ext JS Library 1.1.1
31072 * Copyright(c) 2006-2007, Ext JS, LLC.
31074 * Originally Released Under LGPL - original licence link has changed is not relivant.
31077 * <script type="text/javascript">
31081 * @class Roo.tree.TreeNode
31082 * @extends Roo.data.Node
31083 * @cfg {String} text The text for this node
31084 * @cfg {Boolean} expanded true to start the node expanded
31085 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31086 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31087 * @cfg {Boolean} disabled true to start the node disabled
31088 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31089 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31090 * @cfg {String} cls A css class to be added to the node
31091 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31092 * @cfg {String} href URL of the link used for the node (defaults to #)
31093 * @cfg {String} hrefTarget target frame for the link
31094 * @cfg {String} qtip An Ext QuickTip for the node
31095 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31096 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31097 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31098 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31099 * (defaults to undefined with no checkbox rendered)
31101 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31103 Roo.tree.TreeNode = function(attributes){
31104 attributes = attributes || {};
31105 if(typeof attributes == "string"){
31106 attributes = {text: attributes};
31108 this.childrenRendered = false;
31109 this.rendered = false;
31110 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31111 this.expanded = attributes.expanded === true;
31112 this.isTarget = attributes.isTarget !== false;
31113 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31114 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31117 * Read-only. The text for this node. To change it use setText().
31120 this.text = attributes.text;
31122 * True if this node is disabled.
31125 this.disabled = attributes.disabled === true;
31129 * @event textchange
31130 * Fires when the text for this node is changed
31131 * @param {Node} this This node
31132 * @param {String} text The new text
31133 * @param {String} oldText The old text
31135 "textchange" : true,
31137 * @event beforeexpand
31138 * Fires before this node is expanded, return false to cancel.
31139 * @param {Node} this This node
31140 * @param {Boolean} deep
31141 * @param {Boolean} anim
31143 "beforeexpand" : true,
31145 * @event beforecollapse
31146 * Fires before this node is collapsed, return false to cancel.
31147 * @param {Node} this This node
31148 * @param {Boolean} deep
31149 * @param {Boolean} anim
31151 "beforecollapse" : true,
31154 * Fires when this node is expanded
31155 * @param {Node} this This node
31159 * @event disabledchange
31160 * Fires when the disabled status of this node changes
31161 * @param {Node} this This node
31162 * @param {Boolean} disabled
31164 "disabledchange" : true,
31167 * Fires when this node is collapsed
31168 * @param {Node} this This node
31172 * @event beforeclick
31173 * Fires before click processing. Return false to cancel the default action.
31174 * @param {Node} this This node
31175 * @param {Roo.EventObject} e The event object
31177 "beforeclick":true,
31179 * @event checkchange
31180 * Fires when a node with a checkbox's checked property changes
31181 * @param {Node} this This node
31182 * @param {Boolean} checked
31184 "checkchange":true,
31187 * Fires when this node is clicked
31188 * @param {Node} this This node
31189 * @param {Roo.EventObject} e The event object
31194 * Fires when this node is double clicked
31195 * @param {Node} this This node
31196 * @param {Roo.EventObject} e The event object
31200 * @event contextmenu
31201 * Fires when this node is right clicked
31202 * @param {Node} this This node
31203 * @param {Roo.EventObject} e The event object
31205 "contextmenu":true,
31207 * @event beforechildrenrendered
31208 * Fires right before the child nodes for this node are rendered
31209 * @param {Node} this This node
31211 "beforechildrenrendered":true
31214 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31217 * Read-only. The UI for this node
31220 this.ui = new uiClass(this);
31222 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31223 preventHScroll: true,
31225 * Returns true if this node is expanded
31226 * @return {Boolean}
31228 isExpanded : function(){
31229 return this.expanded;
31233 * Returns the UI object for this node
31234 * @return {TreeNodeUI}
31236 getUI : function(){
31240 // private override
31241 setFirstChild : function(node){
31242 var of = this.firstChild;
31243 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31244 if(this.childrenRendered && of && node != of){
31245 of.renderIndent(true, true);
31248 this.renderIndent(true, true);
31252 // private override
31253 setLastChild : function(node){
31254 var ol = this.lastChild;
31255 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31256 if(this.childrenRendered && ol && node != ol){
31257 ol.renderIndent(true, true);
31260 this.renderIndent(true, true);
31264 // these methods are overridden to provide lazy rendering support
31265 // private override
31266 appendChild : function(){
31267 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31268 if(node && this.childrenRendered){
31271 this.ui.updateExpandIcon();
31275 // private override
31276 removeChild : function(node){
31277 this.ownerTree.getSelectionModel().unselect(node);
31278 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31279 // if it's been rendered remove dom node
31280 if(this.childrenRendered){
31283 if(this.childNodes.length < 1){
31284 this.collapse(false, false);
31286 this.ui.updateExpandIcon();
31288 if(!this.firstChild) {
31289 this.childrenRendered = false;
31294 // private override
31295 insertBefore : function(node, refNode){
31296 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31297 if(newNode && refNode && this.childrenRendered){
31300 this.ui.updateExpandIcon();
31305 * Sets the text for this node
31306 * @param {String} text
31308 setText : function(text){
31309 var oldText = this.text;
31311 this.attributes.text = text;
31312 if(this.rendered){ // event without subscribing
31313 this.ui.onTextChange(this, text, oldText);
31315 this.fireEvent("textchange", this, text, oldText);
31319 * Triggers selection of this node
31321 select : function(){
31322 this.getOwnerTree().getSelectionModel().select(this);
31326 * Triggers deselection of this node
31328 unselect : function(){
31329 this.getOwnerTree().getSelectionModel().unselect(this);
31333 * Returns true if this node is selected
31334 * @return {Boolean}
31336 isSelected : function(){
31337 return this.getOwnerTree().getSelectionModel().isSelected(this);
31341 * Expand this node.
31342 * @param {Boolean} deep (optional) True to expand all children as well
31343 * @param {Boolean} anim (optional) false to cancel the default animation
31344 * @param {Function} callback (optional) A callback to be called when
31345 * expanding this node completes (does not wait for deep expand to complete).
31346 * Called with 1 parameter, this node.
31348 expand : function(deep, anim, callback){
31349 if(!this.expanded){
31350 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31353 if(!this.childrenRendered){
31354 this.renderChildren();
31356 this.expanded = true;
31357 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31358 this.ui.animExpand(function(){
31359 this.fireEvent("expand", this);
31360 if(typeof callback == "function"){
31364 this.expandChildNodes(true);
31366 }.createDelegate(this));
31370 this.fireEvent("expand", this);
31371 if(typeof callback == "function"){
31376 if(typeof callback == "function"){
31381 this.expandChildNodes(true);
31385 isHiddenRoot : function(){
31386 return this.isRoot && !this.getOwnerTree().rootVisible;
31390 * Collapse this node.
31391 * @param {Boolean} deep (optional) True to collapse all children as well
31392 * @param {Boolean} anim (optional) false to cancel the default animation
31394 collapse : function(deep, anim){
31395 if(this.expanded && !this.isHiddenRoot()){
31396 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31399 this.expanded = false;
31400 if((this.getOwnerTree().animate && anim !== false) || anim){
31401 this.ui.animCollapse(function(){
31402 this.fireEvent("collapse", this);
31404 this.collapseChildNodes(true);
31406 }.createDelegate(this));
31409 this.ui.collapse();
31410 this.fireEvent("collapse", this);
31414 var cs = this.childNodes;
31415 for(var i = 0, len = cs.length; i < len; i++) {
31416 cs[i].collapse(true, false);
31422 delayedExpand : function(delay){
31423 if(!this.expandProcId){
31424 this.expandProcId = this.expand.defer(delay, this);
31429 cancelExpand : function(){
31430 if(this.expandProcId){
31431 clearTimeout(this.expandProcId);
31433 this.expandProcId = false;
31437 * Toggles expanded/collapsed state of the node
31439 toggle : function(){
31448 * Ensures all parent nodes are expanded
31450 ensureVisible : function(callback){
31451 var tree = this.getOwnerTree();
31452 tree.expandPath(this.parentNode.getPath(), false, function(){
31453 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31454 Roo.callback(callback);
31455 }.createDelegate(this));
31459 * Expand all child nodes
31460 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31462 expandChildNodes : function(deep){
31463 var cs = this.childNodes;
31464 for(var i = 0, len = cs.length; i < len; i++) {
31465 cs[i].expand(deep);
31470 * Collapse all child nodes
31471 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31473 collapseChildNodes : function(deep){
31474 var cs = this.childNodes;
31475 for(var i = 0, len = cs.length; i < len; i++) {
31476 cs[i].collapse(deep);
31481 * Disables this node
31483 disable : function(){
31484 this.disabled = true;
31486 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31487 this.ui.onDisableChange(this, true);
31489 this.fireEvent("disabledchange", this, true);
31493 * Enables this node
31495 enable : function(){
31496 this.disabled = false;
31497 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31498 this.ui.onDisableChange(this, false);
31500 this.fireEvent("disabledchange", this, false);
31504 renderChildren : function(suppressEvent){
31505 if(suppressEvent !== false){
31506 this.fireEvent("beforechildrenrendered", this);
31508 var cs = this.childNodes;
31509 for(var i = 0, len = cs.length; i < len; i++){
31510 cs[i].render(true);
31512 this.childrenRendered = true;
31516 sort : function(fn, scope){
31517 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31518 if(this.childrenRendered){
31519 var cs = this.childNodes;
31520 for(var i = 0, len = cs.length; i < len; i++){
31521 cs[i].render(true);
31527 render : function(bulkRender){
31528 this.ui.render(bulkRender);
31529 if(!this.rendered){
31530 this.rendered = true;
31532 this.expanded = false;
31533 this.expand(false, false);
31539 renderIndent : function(deep, refresh){
31541 this.ui.childIndent = null;
31543 this.ui.renderIndent();
31544 if(deep === true && this.childrenRendered){
31545 var cs = this.childNodes;
31546 for(var i = 0, len = cs.length; i < len; i++){
31547 cs[i].renderIndent(true, refresh);
31553 * Ext JS Library 1.1.1
31554 * Copyright(c) 2006-2007, Ext JS, LLC.
31556 * Originally Released Under LGPL - original licence link has changed is not relivant.
31559 * <script type="text/javascript">
31563 * @class Roo.tree.AsyncTreeNode
31564 * @extends Roo.tree.TreeNode
31565 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31567 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31569 Roo.tree.AsyncTreeNode = function(config){
31570 this.loaded = false;
31571 this.loading = false;
31572 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31574 * @event beforeload
31575 * Fires before this node is loaded, return false to cancel
31576 * @param {Node} this This node
31578 this.addEvents({'beforeload':true, 'load': true});
31581 * Fires when this node is loaded
31582 * @param {Node} this This node
31585 * The loader used by this node (defaults to using the tree's defined loader)
31590 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31591 expand : function(deep, anim, callback){
31592 if(this.loading){ // if an async load is already running, waiting til it's done
31594 var f = function(){
31595 if(!this.loading){ // done loading
31596 clearInterval(timer);
31597 this.expand(deep, anim, callback);
31599 }.createDelegate(this);
31600 timer = setInterval(f, 200);
31604 if(this.fireEvent("beforeload", this) === false){
31607 this.loading = true;
31608 this.ui.beforeLoad(this);
31609 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31611 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31615 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31619 * Returns true if this node is currently loading
31620 * @return {Boolean}
31622 isLoading : function(){
31623 return this.loading;
31626 loadComplete : function(deep, anim, callback){
31627 this.loading = false;
31628 this.loaded = true;
31629 this.ui.afterLoad(this);
31630 this.fireEvent("load", this);
31631 this.expand(deep, anim, callback);
31635 * Returns true if this node has been loaded
31636 * @return {Boolean}
31638 isLoaded : function(){
31639 return this.loaded;
31642 hasChildNodes : function(){
31643 if(!this.isLeaf() && !this.loaded){
31646 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
31651 * Trigger a reload for this node
31652 * @param {Function} callback
31654 reload : function(callback){
31655 this.collapse(false, false);
31656 while(this.firstChild){
31657 this.removeChild(this.firstChild);
31659 this.childrenRendered = false;
31660 this.loaded = false;
31661 if(this.isHiddenRoot()){
31662 this.expanded = false;
31664 this.expand(false, false, callback);
31668 * Ext JS Library 1.1.1
31669 * Copyright(c) 2006-2007, Ext JS, LLC.
31671 * Originally Released Under LGPL - original licence link has changed is not relivant.
31674 * <script type="text/javascript">
31678 * @class Roo.tree.TreeNodeUI
31680 * @param {Object} node The node to render
31681 * The TreeNode UI implementation is separate from the
31682 * tree implementation. Unless you are customizing the tree UI,
31683 * you should never have to use this directly.
31685 Roo.tree.TreeNodeUI = function(node){
31687 this.rendered = false;
31688 this.animating = false;
31689 this.emptyIcon = Roo.BLANK_IMAGE_URL;
31692 Roo.tree.TreeNodeUI.prototype = {
31693 removeChild : function(node){
31695 this.ctNode.removeChild(node.ui.getEl());
31699 beforeLoad : function(){
31700 this.addClass("x-tree-node-loading");
31703 afterLoad : function(){
31704 this.removeClass("x-tree-node-loading");
31707 onTextChange : function(node, text, oldText){
31709 this.textNode.innerHTML = text;
31713 onDisableChange : function(node, state){
31714 this.disabled = state;
31716 this.addClass("x-tree-node-disabled");
31718 this.removeClass("x-tree-node-disabled");
31722 onSelectedChange : function(state){
31725 this.addClass("x-tree-selected");
31728 this.removeClass("x-tree-selected");
31732 onMove : function(tree, node, oldParent, newParent, index, refNode){
31733 this.childIndent = null;
31735 var targetNode = newParent.ui.getContainer();
31736 if(!targetNode){//target not rendered
31737 this.holder = document.createElement("div");
31738 this.holder.appendChild(this.wrap);
31741 var insertBefore = refNode ? refNode.ui.getEl() : null;
31743 targetNode.insertBefore(this.wrap, insertBefore);
31745 targetNode.appendChild(this.wrap);
31747 this.node.renderIndent(true);
31751 addClass : function(cls){
31753 Roo.fly(this.elNode).addClass(cls);
31757 removeClass : function(cls){
31759 Roo.fly(this.elNode).removeClass(cls);
31763 remove : function(){
31765 this.holder = document.createElement("div");
31766 this.holder.appendChild(this.wrap);
31770 fireEvent : function(){
31771 return this.node.fireEvent.apply(this.node, arguments);
31774 initEvents : function(){
31775 this.node.on("move", this.onMove, this);
31776 var E = Roo.EventManager;
31777 var a = this.anchor;
31779 var el = Roo.fly(a, '_treeui');
31781 if(Roo.isOpera){ // opera render bug ignores the CSS
31782 el.setStyle("text-decoration", "none");
31785 el.on("click", this.onClick, this);
31786 el.on("dblclick", this.onDblClick, this);
31789 Roo.EventManager.on(this.checkbox,
31790 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
31793 el.on("contextmenu", this.onContextMenu, this);
31795 var icon = Roo.fly(this.iconNode);
31796 icon.on("click", this.onClick, this);
31797 icon.on("dblclick", this.onDblClick, this);
31798 icon.on("contextmenu", this.onContextMenu, this);
31799 E.on(this.ecNode, "click", this.ecClick, this, true);
31801 if(this.node.disabled){
31802 this.addClass("x-tree-node-disabled");
31804 if(this.node.hidden){
31805 this.addClass("x-tree-node-disabled");
31807 var ot = this.node.getOwnerTree();
31808 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
31809 if(dd && (!this.node.isRoot || ot.rootVisible)){
31810 Roo.dd.Registry.register(this.elNode, {
31812 handles: this.getDDHandles(),
31818 getDDHandles : function(){
31819 return [this.iconNode, this.textNode];
31824 this.wrap.style.display = "none";
31830 this.wrap.style.display = "";
31834 onContextMenu : function(e){
31835 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
31836 e.preventDefault();
31838 this.fireEvent("contextmenu", this.node, e);
31842 onClick : function(e){
31847 if(this.fireEvent("beforeclick", this.node, e) !== false){
31848 if(!this.disabled && this.node.attributes.href){
31849 this.fireEvent("click", this.node, e);
31852 e.preventDefault();
31857 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
31858 this.node.toggle();
31861 this.fireEvent("click", this.node, e);
31867 onDblClick : function(e){
31868 e.preventDefault();
31873 this.toggleCheck();
31875 if(!this.animating && this.node.hasChildNodes()){
31876 this.node.toggle();
31878 this.fireEvent("dblclick", this.node, e);
31881 onCheckChange : function(){
31882 var checked = this.checkbox.checked;
31883 this.node.attributes.checked = checked;
31884 this.fireEvent('checkchange', this.node, checked);
31887 ecClick : function(e){
31888 if(!this.animating && this.node.hasChildNodes()){
31889 this.node.toggle();
31893 startDrop : function(){
31894 this.dropping = true;
31897 // delayed drop so the click event doesn't get fired on a drop
31898 endDrop : function(){
31899 setTimeout(function(){
31900 this.dropping = false;
31901 }.createDelegate(this), 50);
31904 expand : function(){
31905 this.updateExpandIcon();
31906 this.ctNode.style.display = "";
31909 focus : function(){
31910 if(!this.node.preventHScroll){
31911 try{this.anchor.focus();
31913 }else if(!Roo.isIE){
31915 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
31916 var l = noscroll.scrollLeft;
31917 this.anchor.focus();
31918 noscroll.scrollLeft = l;
31923 toggleCheck : function(value){
31924 var cb = this.checkbox;
31926 cb.checked = (value === undefined ? !cb.checked : value);
31932 this.anchor.blur();
31936 animExpand : function(callback){
31937 var ct = Roo.get(this.ctNode);
31939 if(!this.node.hasChildNodes()){
31940 this.updateExpandIcon();
31941 this.ctNode.style.display = "";
31942 Roo.callback(callback);
31945 this.animating = true;
31946 this.updateExpandIcon();
31949 callback : function(){
31950 this.animating = false;
31951 Roo.callback(callback);
31954 duration: this.node.ownerTree.duration || .25
31958 highlight : function(){
31959 var tree = this.node.getOwnerTree();
31960 Roo.fly(this.wrap).highlight(
31961 tree.hlColor || "C3DAF9",
31962 {endColor: tree.hlBaseColor}
31966 collapse : function(){
31967 this.updateExpandIcon();
31968 this.ctNode.style.display = "none";
31971 animCollapse : function(callback){
31972 var ct = Roo.get(this.ctNode);
31973 ct.enableDisplayMode('block');
31976 this.animating = true;
31977 this.updateExpandIcon();
31980 callback : function(){
31981 this.animating = false;
31982 Roo.callback(callback);
31985 duration: this.node.ownerTree.duration || .25
31989 getContainer : function(){
31990 return this.ctNode;
31993 getEl : function(){
31997 appendDDGhost : function(ghostNode){
31998 ghostNode.appendChild(this.elNode.cloneNode(true));
32001 getDDRepairXY : function(){
32002 return Roo.lib.Dom.getXY(this.iconNode);
32005 onRender : function(){
32009 render : function(bulkRender){
32010 var n = this.node, a = n.attributes;
32011 var targetNode = n.parentNode ?
32012 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32014 if(!this.rendered){
32015 this.rendered = true;
32017 this.renderElements(n, a, targetNode, bulkRender);
32020 if(this.textNode.setAttributeNS){
32021 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32023 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32026 this.textNode.setAttribute("ext:qtip", a.qtip);
32028 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32031 }else if(a.qtipCfg){
32032 a.qtipCfg.target = Roo.id(this.textNode);
32033 Roo.QuickTips.register(a.qtipCfg);
32036 if(!this.node.expanded){
32037 this.updateExpandIcon();
32040 if(bulkRender === true) {
32041 targetNode.appendChild(this.wrap);
32046 renderElements : function(n, a, targetNode, bulkRender){
32047 // add some indent caching, this helps performance when rendering a large tree
32048 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32049 var t = n.getOwnerTree();
32050 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32051 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32052 var cb = typeof a.checked == 'boolean';
32053 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32054 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32055 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32056 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32057 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32058 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32059 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32060 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32061 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32062 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32065 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32066 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32067 n.nextSibling.ui.getEl(), buf.join(""));
32069 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32072 this.elNode = this.wrap.childNodes[0];
32073 this.ctNode = this.wrap.childNodes[1];
32074 var cs = this.elNode.childNodes;
32075 this.indentNode = cs[0];
32076 this.ecNode = cs[1];
32077 this.iconNode = cs[2];
32080 this.checkbox = cs[3];
32083 this.anchor = cs[index];
32084 this.textNode = cs[index].firstChild;
32087 getAnchor : function(){
32088 return this.anchor;
32091 getTextEl : function(){
32092 return this.textNode;
32095 getIconEl : function(){
32096 return this.iconNode;
32099 isChecked : function(){
32100 return this.checkbox ? this.checkbox.checked : false;
32103 updateExpandIcon : function(){
32105 var n = this.node, c1, c2;
32106 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32107 var hasChild = n.hasChildNodes();
32111 c1 = "x-tree-node-collapsed";
32112 c2 = "x-tree-node-expanded";
32115 c1 = "x-tree-node-expanded";
32116 c2 = "x-tree-node-collapsed";
32119 this.removeClass("x-tree-node-leaf");
32120 this.wasLeaf = false;
32122 if(this.c1 != c1 || this.c2 != c2){
32123 Roo.fly(this.elNode).replaceClass(c1, c2);
32124 this.c1 = c1; this.c2 = c2;
32128 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32131 this.wasLeaf = true;
32134 var ecc = "x-tree-ec-icon "+cls;
32135 if(this.ecc != ecc){
32136 this.ecNode.className = ecc;
32142 getChildIndent : function(){
32143 if(!this.childIndent){
32147 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32149 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32151 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32156 this.childIndent = buf.join("");
32158 return this.childIndent;
32161 renderIndent : function(){
32164 var p = this.node.parentNode;
32166 indent = p.ui.getChildIndent();
32168 if(this.indentMarkup != indent){ // don't rerender if not required
32169 this.indentNode.innerHTML = indent;
32170 this.indentMarkup = indent;
32172 this.updateExpandIcon();
32177 Roo.tree.RootTreeNodeUI = function(){
32178 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32180 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32181 render : function(){
32182 if(!this.rendered){
32183 var targetNode = this.node.ownerTree.innerCt.dom;
32184 this.node.expanded = true;
32185 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32186 this.wrap = this.ctNode = targetNode.firstChild;
32189 collapse : function(){
32191 expand : function(){
32195 * Ext JS Library 1.1.1
32196 * Copyright(c) 2006-2007, Ext JS, LLC.
32198 * Originally Released Under LGPL - original licence link has changed is not relivant.
32201 * <script type="text/javascript">
32204 * @class Roo.tree.TreeLoader
32205 * @extends Roo.util.Observable
32206 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32207 * nodes from a specified URL. The response must be a javascript Array definition
32208 * who's elements are node definition objects. eg:
32210 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32211 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32214 * A server request is sent, and child nodes are loaded only when a node is expanded.
32215 * The loading node's id is passed to the server under the parameter name "node" to
32216 * enable the server to produce the correct child nodes.
32218 * To pass extra parameters, an event handler may be attached to the "beforeload"
32219 * event, and the parameters specified in the TreeLoader's baseParams property:
32221 myTreeLoader.on("beforeload", function(treeLoader, node) {
32222 this.baseParams.category = node.attributes.category;
32225 * This would pass an HTTP parameter called "category" to the server containing
32226 * the value of the Node's "category" attribute.
32228 * Creates a new Treeloader.
32229 * @param {Object} config A config object containing config properties.
32231 Roo.tree.TreeLoader = function(config){
32232 this.baseParams = {};
32233 this.requestMethod = "POST";
32234 Roo.apply(this, config);
32239 * @event beforeload
32240 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32241 * @param {Object} This TreeLoader object.
32242 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32243 * @param {Object} callback The callback function specified in the {@link #load} call.
32248 * Fires when the node has been successfuly loaded.
32249 * @param {Object} This TreeLoader object.
32250 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32251 * @param {Object} response The response object containing the data from the server.
32255 * @event loadexception
32256 * Fires if the network request failed.
32257 * @param {Object} This TreeLoader object.
32258 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32259 * @param {Object} response The response object containing the data from the server.
32261 loadexception : true,
32264 * Fires before a node is created, enabling you to return custom Node types
32265 * @param {Object} This TreeLoader object.
32266 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32271 Roo.tree.TreeLoader.superclass.constructor.call(this);
32274 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32276 * @cfg {String} dataUrl The URL from which to request a Json string which
32277 * specifies an array of node definition object representing the child nodes
32281 * @cfg {Object} baseParams (optional) An object containing properties which
32282 * specify HTTP parameters to be passed to each request for child nodes.
32285 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32286 * created by this loader. If the attributes sent by the server have an attribute in this object,
32287 * they take priority.
32290 * @cfg {Object} uiProviders (optional) An object containing properties which
32292 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32293 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32294 * <i>uiProvider</i> attribute of a returned child node is a string rather
32295 * than a reference to a TreeNodeUI implementation, this that string value
32296 * is used as a property name in the uiProviders object. You can define the provider named
32297 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32302 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32303 * child nodes before loading.
32305 clearOnLoad : true,
32308 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32309 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32310 * Grid query { data : [ .....] }
32315 * @cfg {String} queryParam (optional)
32316 * Name of the query as it will be passed on the querystring (defaults to 'node')
32317 * eg. the request will be ?node=[id]
32324 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32325 * This is called automatically when a node is expanded, but may be used to reload
32326 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32327 * @param {Roo.tree.TreeNode} node
32328 * @param {Function} callback
32330 load : function(node, callback){
32331 if(this.clearOnLoad){
32332 while(node.firstChild){
32333 node.removeChild(node.firstChild);
32336 if(node.attributes.children){ // preloaded json children
32337 var cs = node.attributes.children;
32338 for(var i = 0, len = cs.length; i < len; i++){
32339 node.appendChild(this.createNode(cs[i]));
32341 if(typeof callback == "function"){
32344 }else if(this.dataUrl){
32345 this.requestData(node, callback);
32349 getParams: function(node){
32350 var buf = [], bp = this.baseParams;
32351 for(var key in bp){
32352 if(typeof bp[key] != "function"){
32353 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32356 var n = this.queryParam === false ? 'node' : this.queryParam;
32357 buf.push(n + "=", encodeURIComponent(node.id));
32358 return buf.join("");
32361 requestData : function(node, callback){
32362 if(this.fireEvent("beforeload", this, node, callback) !== false){
32363 this.transId = Roo.Ajax.request({
32364 method:this.requestMethod,
32365 url: this.dataUrl||this.url,
32366 success: this.handleResponse,
32367 failure: this.handleFailure,
32369 argument: {callback: callback, node: node},
32370 params: this.getParams(node)
32373 // if the load is cancelled, make sure we notify
32374 // the node that we are done
32375 if(typeof callback == "function"){
32381 isLoading : function(){
32382 return this.transId ? true : false;
32385 abort : function(){
32386 if(this.isLoading()){
32387 Roo.Ajax.abort(this.transId);
32392 createNode : function(attr){
32393 // apply baseAttrs, nice idea Corey!
32394 if(this.baseAttrs){
32395 Roo.applyIf(attr, this.baseAttrs);
32397 if(this.applyLoader !== false){
32398 attr.loader = this;
32400 // uiProvider = depreciated..
32402 if(typeof(attr.uiProvider) == 'string'){
32403 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32404 /** eval:var:attr */ eval(attr.uiProvider);
32406 if(typeof(this.uiProviders['default']) != 'undefined') {
32407 attr.uiProvider = this.uiProviders['default'];
32410 this.fireEvent('create', this, attr);
32412 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32414 new Roo.tree.TreeNode(attr) :
32415 new Roo.tree.AsyncTreeNode(attr));
32418 processResponse : function(response, node, callback){
32419 var json = response.responseText;
32422 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32423 if (this.root !== false) {
32427 for(var i = 0, len = o.length; i < len; i++){
32428 var n = this.createNode(o[i]);
32430 node.appendChild(n);
32433 if(typeof callback == "function"){
32434 callback(this, node);
32437 this.handleFailure(response);
32441 handleResponse : function(response){
32442 this.transId = false;
32443 var a = response.argument;
32444 this.processResponse(response, a.node, a.callback);
32445 this.fireEvent("load", this, a.node, response);
32448 handleFailure : function(response){
32449 this.transId = false;
32450 var a = response.argument;
32451 this.fireEvent("loadexception", this, a.node, response);
32452 if(typeof a.callback == "function"){
32453 a.callback(this, a.node);
32458 * Ext JS Library 1.1.1
32459 * Copyright(c) 2006-2007, Ext JS, LLC.
32461 * Originally Released Under LGPL - original licence link has changed is not relivant.
32464 * <script type="text/javascript">
32468 * @class Roo.tree.TreeFilter
32469 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32470 * @param {TreePanel} tree
32471 * @param {Object} config (optional)
32473 Roo.tree.TreeFilter = function(tree, config){
32475 this.filtered = {};
32476 Roo.apply(this, config);
32479 Roo.tree.TreeFilter.prototype = {
32486 * Filter the data by a specific attribute.
32487 * @param {String/RegExp} value Either string that the attribute value
32488 * should start with or a RegExp to test against the attribute
32489 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32490 * @param {TreeNode} startNode (optional) The node to start the filter at.
32492 filter : function(value, attr, startNode){
32493 attr = attr || "text";
32495 if(typeof value == "string"){
32496 var vlen = value.length;
32497 // auto clear empty filter
32498 if(vlen == 0 && this.clearBlank){
32502 value = value.toLowerCase();
32504 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32506 }else if(value.exec){ // regex?
32508 return value.test(n.attributes[attr]);
32511 throw 'Illegal filter type, must be string or regex';
32513 this.filterBy(f, null, startNode);
32517 * Filter by a function. The passed function will be called with each
32518 * node in the tree (or from the startNode). If the function returns true, the node is kept
32519 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32520 * @param {Function} fn The filter function
32521 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32523 filterBy : function(fn, scope, startNode){
32524 startNode = startNode || this.tree.root;
32525 if(this.autoClear){
32528 var af = this.filtered, rv = this.reverse;
32529 var f = function(n){
32530 if(n == startNode){
32536 var m = fn.call(scope || n, n);
32544 startNode.cascade(f);
32547 if(typeof id != "function"){
32549 if(n && n.parentNode){
32550 n.parentNode.removeChild(n);
32558 * Clears the current filter. Note: with the "remove" option
32559 * set a filter cannot be cleared.
32561 clear : function(){
32563 var af = this.filtered;
32565 if(typeof id != "function"){
32572 this.filtered = {};
32577 * Ext JS Library 1.1.1
32578 * Copyright(c) 2006-2007, Ext JS, LLC.
32580 * Originally Released Under LGPL - original licence link has changed is not relivant.
32583 * <script type="text/javascript">
32588 * @class Roo.tree.TreeSorter
32589 * Provides sorting of nodes in a TreePanel
32591 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32592 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32593 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32594 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32595 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32596 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32598 * @param {TreePanel} tree
32599 * @param {Object} config
32601 Roo.tree.TreeSorter = function(tree, config){
32602 Roo.apply(this, config);
32603 tree.on("beforechildrenrendered", this.doSort, this);
32604 tree.on("append", this.updateSort, this);
32605 tree.on("insert", this.updateSort, this);
32607 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32608 var p = this.property || "text";
32609 var sortType = this.sortType;
32610 var fs = this.folderSort;
32611 var cs = this.caseSensitive === true;
32612 var leafAttr = this.leafAttr || 'leaf';
32614 this.sortFn = function(n1, n2){
32616 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32619 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
32623 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
32624 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
32626 return dsc ? +1 : -1;
32628 return dsc ? -1 : +1;
32635 Roo.tree.TreeSorter.prototype = {
32636 doSort : function(node){
32637 node.sort(this.sortFn);
32640 compareNodes : function(n1, n2){
32641 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
32644 updateSort : function(tree, node){
32645 if(node.childrenRendered){
32646 this.doSort.defer(1, this, [node]);
32651 * Ext JS Library 1.1.1
32652 * Copyright(c) 2006-2007, Ext JS, LLC.
32654 * Originally Released Under LGPL - original licence link has changed is not relivant.
32657 * <script type="text/javascript">
32660 if(Roo.dd.DropZone){
32662 Roo.tree.TreeDropZone = function(tree, config){
32663 this.allowParentInsert = false;
32664 this.allowContainerDrop = false;
32665 this.appendOnly = false;
32666 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
32668 this.lastInsertClass = "x-tree-no-status";
32669 this.dragOverData = {};
32672 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
32673 ddGroup : "TreeDD",
32675 expandDelay : 1000,
32677 expandNode : function(node){
32678 if(node.hasChildNodes() && !node.isExpanded()){
32679 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
32683 queueExpand : function(node){
32684 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
32687 cancelExpand : function(){
32688 if(this.expandProcId){
32689 clearTimeout(this.expandProcId);
32690 this.expandProcId = false;
32694 isValidDropPoint : function(n, pt, dd, e, data){
32695 if(!n || !data){ return false; }
32696 var targetNode = n.node;
32697 var dropNode = data.node;
32698 // default drop rules
32699 if(!(targetNode && targetNode.isTarget && pt)){
32702 if(pt == "append" && targetNode.allowChildren === false){
32705 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
32708 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
32711 // reuse the object
32712 var overEvent = this.dragOverData;
32713 overEvent.tree = this.tree;
32714 overEvent.target = targetNode;
32715 overEvent.data = data;
32716 overEvent.point = pt;
32717 overEvent.source = dd;
32718 overEvent.rawEvent = e;
32719 overEvent.dropNode = dropNode;
32720 overEvent.cancel = false;
32721 var result = this.tree.fireEvent("nodedragover", overEvent);
32722 return overEvent.cancel === false && result !== false;
32725 getDropPoint : function(e, n, dd){
32728 return tn.allowChildren !== false ? "append" : false; // always append for root
32730 var dragEl = n.ddel;
32731 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
32732 var y = Roo.lib.Event.getPageY(e);
32733 var noAppend = tn.allowChildren === false || tn.isLeaf();
32734 if(this.appendOnly || tn.parentNode.allowChildren === false){
32735 return noAppend ? false : "append";
32737 var noBelow = false;
32738 if(!this.allowParentInsert){
32739 noBelow = tn.hasChildNodes() && tn.isExpanded();
32741 var q = (b - t) / (noAppend ? 2 : 3);
32742 if(y >= t && y < (t + q)){
32744 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
32751 onNodeEnter : function(n, dd, e, data){
32752 this.cancelExpand();
32755 onNodeOver : function(n, dd, e, data){
32756 var pt = this.getDropPoint(e, n, dd);
32759 // auto node expand check
32760 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
32761 this.queueExpand(node);
32762 }else if(pt != "append"){
32763 this.cancelExpand();
32766 // set the insert point style on the target node
32767 var returnCls = this.dropNotAllowed;
32768 if(this.isValidDropPoint(n, pt, dd, e, data)){
32773 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
32774 cls = "x-tree-drag-insert-above";
32775 }else if(pt == "below"){
32776 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
32777 cls = "x-tree-drag-insert-below";
32779 returnCls = "x-tree-drop-ok-append";
32780 cls = "x-tree-drag-append";
32782 if(this.lastInsertClass != cls){
32783 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
32784 this.lastInsertClass = cls;
32791 onNodeOut : function(n, dd, e, data){
32792 this.cancelExpand();
32793 this.removeDropIndicators(n);
32796 onNodeDrop : function(n, dd, e, data){
32797 var point = this.getDropPoint(e, n, dd);
32798 var targetNode = n.node;
32799 targetNode.ui.startDrop();
32800 if(!this.isValidDropPoint(n, point, dd, e, data)){
32801 targetNode.ui.endDrop();
32804 // first try to find the drop node
32805 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
32808 target: targetNode,
32813 dropNode: dropNode,
32816 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
32817 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
32818 targetNode.ui.endDrop();
32821 // allow target changing
32822 targetNode = dropEvent.target;
32823 if(point == "append" && !targetNode.isExpanded()){
32824 targetNode.expand(false, null, function(){
32825 this.completeDrop(dropEvent);
32826 }.createDelegate(this));
32828 this.completeDrop(dropEvent);
32833 completeDrop : function(de){
32834 var ns = de.dropNode, p = de.point, t = de.target;
32835 if(!(ns instanceof Array)){
32839 for(var i = 0, len = ns.length; i < len; i++){
32842 t.parentNode.insertBefore(n, t);
32843 }else if(p == "below"){
32844 t.parentNode.insertBefore(n, t.nextSibling);
32850 if(this.tree.hlDrop){
32854 this.tree.fireEvent("nodedrop", de);
32857 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
32858 if(this.tree.hlDrop){
32859 dropNode.ui.focus();
32860 dropNode.ui.highlight();
32862 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
32865 getTree : function(){
32869 removeDropIndicators : function(n){
32872 Roo.fly(el).removeClass([
32873 "x-tree-drag-insert-above",
32874 "x-tree-drag-insert-below",
32875 "x-tree-drag-append"]);
32876 this.lastInsertClass = "_noclass";
32880 beforeDragDrop : function(target, e, id){
32881 this.cancelExpand();
32885 afterRepair : function(data){
32886 if(data && Roo.enableFx){
32887 data.node.ui.highlight();
32895 * Ext JS Library 1.1.1
32896 * Copyright(c) 2006-2007, Ext JS, LLC.
32898 * Originally Released Under LGPL - original licence link has changed is not relivant.
32901 * <script type="text/javascript">
32905 if(Roo.dd.DragZone){
32906 Roo.tree.TreeDragZone = function(tree, config){
32907 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
32911 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
32912 ddGroup : "TreeDD",
32914 onBeforeDrag : function(data, e){
32916 return n && n.draggable && !n.disabled;
32919 onInitDrag : function(e){
32920 var data = this.dragData;
32921 this.tree.getSelectionModel().select(data.node);
32922 this.proxy.update("");
32923 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
32924 this.tree.fireEvent("startdrag", this.tree, data.node, e);
32927 getRepairXY : function(e, data){
32928 return data.node.ui.getDDRepairXY();
32931 onEndDrag : function(data, e){
32932 this.tree.fireEvent("enddrag", this.tree, data.node, e);
32935 onValidDrop : function(dd, e, id){
32936 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
32940 beforeInvalidDrop : function(e, id){
32941 // this scrolls the original position back into view
32942 var sm = this.tree.getSelectionModel();
32943 sm.clearSelections();
32944 sm.select(this.dragData.node);
32949 * Ext JS Library 1.1.1
32950 * Copyright(c) 2006-2007, Ext JS, LLC.
32952 * Originally Released Under LGPL - original licence link has changed is not relivant.
32955 * <script type="text/javascript">
32958 * @class Roo.tree.TreeEditor
32959 * @extends Roo.Editor
32960 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
32961 * as the editor field.
32963 * @param {TreePanel} tree
32964 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
32966 Roo.tree.TreeEditor = function(tree, config){
32967 config = config || {};
32968 var field = config.events ? config : new Roo.form.TextField(config);
32969 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
32973 tree.on('beforeclick', this.beforeNodeClick, this);
32974 tree.getTreeEl().on('mousedown', this.hide, this);
32975 this.on('complete', this.updateNode, this);
32976 this.on('beforestartedit', this.fitToTree, this);
32977 this.on('startedit', this.bindScroll, this, {delay:10});
32978 this.on('specialkey', this.onSpecialKey, this);
32981 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
32983 * @cfg {String} alignment
32984 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
32990 * @cfg {Boolean} hideEl
32991 * True to hide the bound element while the editor is displayed (defaults to false)
32995 * @cfg {String} cls
32996 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
32998 cls: "x-small-editor x-tree-editor",
33000 * @cfg {Boolean} shim
33001 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33007 * @cfg {Number} maxWidth
33008 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33009 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33010 * scroll and client offsets into account prior to each edit.
33017 fitToTree : function(ed, el){
33018 var td = this.tree.getTreeEl().dom, nd = el.dom;
33019 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33020 td.scrollLeft = nd.offsetLeft;
33024 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33025 this.setSize(w, '');
33029 triggerEdit : function(node){
33030 this.completeEdit();
33031 this.editNode = node;
33032 this.startEdit(node.ui.textNode, node.text);
33036 bindScroll : function(){
33037 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33041 beforeNodeClick : function(node, e){
33042 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33043 this.lastClick = new Date();
33044 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33046 this.triggerEdit(node);
33052 updateNode : function(ed, value){
33053 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33054 this.editNode.setText(value);
33058 onHide : function(){
33059 Roo.tree.TreeEditor.superclass.onHide.call(this);
33061 this.editNode.ui.focus();
33066 onSpecialKey : function(field, e){
33067 var k = e.getKey();
33071 }else if(k == e.ENTER && !e.hasModifier()){
33073 this.completeEdit();
33076 });//<Script type="text/javascript">
33079 * Ext JS Library 1.1.1
33080 * Copyright(c) 2006-2007, Ext JS, LLC.
33082 * Originally Released Under LGPL - original licence link has changed is not relivant.
33085 * <script type="text/javascript">
33089 * Not documented??? - probably should be...
33092 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33093 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33095 renderElements : function(n, a, targetNode, bulkRender){
33096 //consel.log("renderElements?");
33097 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33099 var t = n.getOwnerTree();
33100 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33102 var cols = t.columns;
33103 var bw = t.borderWidth;
33105 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33106 var cb = typeof a.checked == "boolean";
33107 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33108 var colcls = 'x-t-' + tid + '-c0';
33110 '<li class="x-tree-node">',
33113 '<div class="x-tree-node-el ', a.cls,'">',
33115 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33118 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33119 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33120 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33121 (a.icon ? ' x-tree-node-inline-icon' : ''),
33122 (a.iconCls ? ' '+a.iconCls : ''),
33123 '" unselectable="on" />',
33124 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33125 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33127 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33128 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33129 '<span unselectable="on" qtip="' + tx + '">',
33133 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33134 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33137 for(var i = 1, len = cols.length; i < len; i++){
33139 colcls = 'x-t-' + tid + '-c' +i;
33140 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33141 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33142 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33148 '<div class="x-clear"></div></div>',
33149 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33152 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33153 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33154 n.nextSibling.ui.getEl(), buf.join(""));
33156 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33158 var el = this.wrap.firstChild;
33160 this.elNode = el.firstChild;
33161 this.ranchor = el.childNodes[1];
33162 this.ctNode = this.wrap.childNodes[1];
33163 var cs = el.firstChild.childNodes;
33164 this.indentNode = cs[0];
33165 this.ecNode = cs[1];
33166 this.iconNode = cs[2];
33169 this.checkbox = cs[3];
33172 this.anchor = cs[index];
33174 this.textNode = cs[index].firstChild;
33176 //el.on("click", this.onClick, this);
33177 //el.on("dblclick", this.onDblClick, this);
33180 // console.log(this);
33182 initEvents : function(){
33183 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33186 var a = this.ranchor;
33188 var el = Roo.get(a);
33190 if(Roo.isOpera){ // opera render bug ignores the CSS
33191 el.setStyle("text-decoration", "none");
33194 el.on("click", this.onClick, this);
33195 el.on("dblclick", this.onDblClick, this);
33196 el.on("contextmenu", this.onContextMenu, this);
33200 /*onSelectedChange : function(state){
33203 this.addClass("x-tree-selected");
33206 this.removeClass("x-tree-selected");
33209 addClass : function(cls){
33211 Roo.fly(this.elRow).addClass(cls);
33217 removeClass : function(cls){
33219 Roo.fly(this.elRow).removeClass(cls);
33225 });//<Script type="text/javascript">
33229 * Ext JS Library 1.1.1
33230 * Copyright(c) 2006-2007, Ext JS, LLC.
33232 * Originally Released Under LGPL - original licence link has changed is not relivant.
33235 * <script type="text/javascript">
33240 * @class Roo.tree.ColumnTree
33241 * @extends Roo.data.TreePanel
33242 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33243 * @cfg {int} borderWidth compined right/left border allowance
33245 * @param {String/HTMLElement/Element} el The container element
33246 * @param {Object} config
33248 Roo.tree.ColumnTree = function(el, config)
33250 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33254 * Fire this event on a container when it resizes
33255 * @param {int} w Width
33256 * @param {int} h Height
33260 this.on('resize', this.onResize, this);
33263 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33267 borderWidth: Roo.isBorderBox ? 0 : 2,
33270 render : function(){
33271 // add the header.....
33273 Roo.tree.ColumnTree.superclass.render.apply(this);
33275 this.el.addClass('x-column-tree');
33277 this.headers = this.el.createChild(
33278 {cls:'x-tree-headers'},this.innerCt.dom);
33280 var cols = this.columns, c;
33281 var totalWidth = 0;
33283 var len = cols.length;
33284 for(var i = 0; i < len; i++){
33286 totalWidth += c.width;
33287 this.headEls.push(this.headers.createChild({
33288 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33290 cls:'x-tree-hd-text',
33293 style:'width:'+(c.width-this.borderWidth)+'px;'
33296 this.headers.createChild({cls:'x-clear'});
33297 // prevent floats from wrapping when clipped
33298 this.headers.setWidth(totalWidth);
33299 //this.innerCt.setWidth(totalWidth);
33300 this.innerCt.setStyle({ overflow: 'auto' });
33301 this.onResize(this.width, this.height);
33305 onResize : function(w,h)
33310 this.innerCt.setWidth(this.width);
33311 this.innerCt.setHeight(this.height-20);
33314 var cols = this.columns, c;
33315 var totalWidth = 0;
33317 var len = cols.length;
33318 for(var i = 0; i < len; i++){
33320 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33321 // it's the expander..
33322 expEl = this.headEls[i];
33325 totalWidth += c.width;
33329 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33331 this.headers.setWidth(w-20);
33340 * Ext JS Library 1.1.1
33341 * Copyright(c) 2006-2007, Ext JS, LLC.
33343 * Originally Released Under LGPL - original licence link has changed is not relivant.
33346 * <script type="text/javascript">
33350 * @class Roo.menu.Menu
33351 * @extends Roo.util.Observable
33352 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33353 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33355 * Creates a new Menu
33356 * @param {Object} config Configuration options
33358 Roo.menu.Menu = function(config){
33359 Roo.apply(this, config);
33360 this.id = this.id || Roo.id();
33363 * @event beforeshow
33364 * Fires before this menu is displayed
33365 * @param {Roo.menu.Menu} this
33369 * @event beforehide
33370 * Fires before this menu is hidden
33371 * @param {Roo.menu.Menu} this
33376 * Fires after this menu is displayed
33377 * @param {Roo.menu.Menu} this
33382 * Fires after this menu is hidden
33383 * @param {Roo.menu.Menu} this
33388 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33389 * @param {Roo.menu.Menu} this
33390 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33391 * @param {Roo.EventObject} e
33396 * Fires when the mouse is hovering over this menu
33397 * @param {Roo.menu.Menu} this
33398 * @param {Roo.EventObject} e
33399 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33404 * Fires when the mouse exits this menu
33405 * @param {Roo.menu.Menu} this
33406 * @param {Roo.EventObject} e
33407 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33412 * Fires when a menu item contained in this menu is clicked
33413 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33414 * @param {Roo.EventObject} e
33418 if (this.registerMenu) {
33419 Roo.menu.MenuMgr.register(this);
33422 var mis = this.items;
33423 this.items = new Roo.util.MixedCollection();
33425 this.add.apply(this, mis);
33429 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33431 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33435 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33436 * for bottom-right shadow (defaults to "sides")
33440 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33441 * this menu (defaults to "tl-tr?")
33443 subMenuAlign : "tl-tr?",
33445 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33446 * relative to its element of origin (defaults to "tl-bl?")
33448 defaultAlign : "tl-bl?",
33450 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33452 allowOtherMenus : false,
33454 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33456 registerMenu : true,
33461 render : function(){
33465 var el = this.el = new Roo.Layer({
33467 shadow:this.shadow,
33469 parentEl: this.parentEl || document.body,
33473 this.keyNav = new Roo.menu.MenuNav(this);
33476 el.addClass("x-menu-plain");
33479 el.addClass(this.cls);
33481 // generic focus element
33482 this.focusEl = el.createChild({
33483 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33485 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33486 ul.on("click", this.onClick, this);
33487 ul.on("mouseover", this.onMouseOver, this);
33488 ul.on("mouseout", this.onMouseOut, this);
33489 this.items.each(function(item){
33490 var li = document.createElement("li");
33491 li.className = "x-menu-list-item";
33492 ul.dom.appendChild(li);
33493 item.render(li, this);
33500 autoWidth : function(){
33501 var el = this.el, ul = this.ul;
33505 var w = this.width;
33508 }else if(Roo.isIE){
33509 el.setWidth(this.minWidth);
33510 var t = el.dom.offsetWidth; // force recalc
33511 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33516 delayAutoWidth : function(){
33519 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33521 this.awTask.delay(20);
33526 findTargetItem : function(e){
33527 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33528 if(t && t.menuItemId){
33529 return this.items.get(t.menuItemId);
33534 onClick : function(e){
33536 if(t = this.findTargetItem(e)){
33538 this.fireEvent("click", this, t, e);
33543 setActiveItem : function(item, autoExpand){
33544 if(item != this.activeItem){
33545 if(this.activeItem){
33546 this.activeItem.deactivate();
33548 this.activeItem = item;
33549 item.activate(autoExpand);
33550 }else if(autoExpand){
33556 tryActivate : function(start, step){
33557 var items = this.items;
33558 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33559 var item = items.get(i);
33560 if(!item.disabled && item.canActivate){
33561 this.setActiveItem(item, false);
33569 onMouseOver : function(e){
33571 if(t = this.findTargetItem(e)){
33572 if(t.canActivate && !t.disabled){
33573 this.setActiveItem(t, true);
33576 this.fireEvent("mouseover", this, e, t);
33580 onMouseOut : function(e){
33582 if(t = this.findTargetItem(e)){
33583 if(t == this.activeItem && t.shouldDeactivate(e)){
33584 this.activeItem.deactivate();
33585 delete this.activeItem;
33588 this.fireEvent("mouseout", this, e, t);
33592 * Read-only. Returns true if the menu is currently displayed, else false.
33595 isVisible : function(){
33596 return this.el && !this.hidden;
33600 * Displays this menu relative to another element
33601 * @param {String/HTMLElement/Roo.Element} element The element to align to
33602 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33603 * the element (defaults to this.defaultAlign)
33604 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33606 show : function(el, pos, parentMenu){
33607 this.parentMenu = parentMenu;
33611 this.fireEvent("beforeshow", this);
33612 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33616 * Displays this menu at a specific xy position
33617 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
33618 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33620 showAt : function(xy, parentMenu, /* private: */_e){
33621 this.parentMenu = parentMenu;
33626 this.fireEvent("beforeshow", this);
33627 xy = this.el.adjustForConstraints(xy);
33631 this.hidden = false;
33633 this.fireEvent("show", this);
33636 focus : function(){
33638 this.doFocus.defer(50, this);
33642 doFocus : function(){
33644 this.focusEl.focus();
33649 * Hides this menu and optionally all parent menus
33650 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
33652 hide : function(deep){
33653 if(this.el && this.isVisible()){
33654 this.fireEvent("beforehide", this);
33655 if(this.activeItem){
33656 this.activeItem.deactivate();
33657 this.activeItem = null;
33660 this.hidden = true;
33661 this.fireEvent("hide", this);
33663 if(deep === true && this.parentMenu){
33664 this.parentMenu.hide(true);
33669 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
33670 * Any of the following are valid:
33672 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
33673 * <li>An HTMLElement object which will be converted to a menu item</li>
33674 * <li>A menu item config object that will be created as a new menu item</li>
33675 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
33676 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
33681 var menu = new Roo.menu.Menu();
33683 // Create a menu item to add by reference
33684 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
33686 // Add a bunch of items at once using different methods.
33687 // Only the last item added will be returned.
33688 var item = menu.add(
33689 menuItem, // add existing item by ref
33690 'Dynamic Item', // new TextItem
33691 '-', // new separator
33692 { text: 'Config Item' } // new item by config
33695 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
33696 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
33699 var a = arguments, l = a.length, item;
33700 for(var i = 0; i < l; i++){
33702 if(el.render){ // some kind of Item
33703 item = this.addItem(el);
33704 }else if(typeof el == "string"){ // string
33705 if(el == "separator" || el == "-"){
33706 item = this.addSeparator();
33708 item = this.addText(el);
33710 }else if(el.tagName || el.el){ // element
33711 item = this.addElement(el);
33712 }else if(typeof el == "object"){ // must be menu item config?
33713 item = this.addMenuItem(el);
33720 * Returns this menu's underlying {@link Roo.Element} object
33721 * @return {Roo.Element} The element
33723 getEl : function(){
33731 * Adds a separator bar to the menu
33732 * @return {Roo.menu.Item} The menu item that was added
33734 addSeparator : function(){
33735 return this.addItem(new Roo.menu.Separator());
33739 * Adds an {@link Roo.Element} object to the menu
33740 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
33741 * @return {Roo.menu.Item} The menu item that was added
33743 addElement : function(el){
33744 return this.addItem(new Roo.menu.BaseItem(el));
33748 * Adds an existing object based on {@link Roo.menu.Item} to the menu
33749 * @param {Roo.menu.Item} item The menu item to add
33750 * @return {Roo.menu.Item} The menu item that was added
33752 addItem : function(item){
33753 this.items.add(item);
33755 var li = document.createElement("li");
33756 li.className = "x-menu-list-item";
33757 this.ul.dom.appendChild(li);
33758 item.render(li, this);
33759 this.delayAutoWidth();
33765 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
33766 * @param {Object} config A MenuItem config object
33767 * @return {Roo.menu.Item} The menu item that was added
33769 addMenuItem : function(config){
33770 if(!(config instanceof Roo.menu.Item)){
33771 if(typeof config.checked == "boolean"){ // must be check menu item config?
33772 config = new Roo.menu.CheckItem(config);
33774 config = new Roo.menu.Item(config);
33777 return this.addItem(config);
33781 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
33782 * @param {String} text The text to display in the menu item
33783 * @return {Roo.menu.Item} The menu item that was added
33785 addText : function(text){
33786 return this.addItem(new Roo.menu.TextItem(text));
33790 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
33791 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
33792 * @param {Roo.menu.Item} item The menu item to add
33793 * @return {Roo.menu.Item} The menu item that was added
33795 insert : function(index, item){
33796 this.items.insert(index, item);
33798 var li = document.createElement("li");
33799 li.className = "x-menu-list-item";
33800 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
33801 item.render(li, this);
33802 this.delayAutoWidth();
33808 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
33809 * @param {Roo.menu.Item} item The menu item to remove
33811 remove : function(item){
33812 this.items.removeKey(item.id);
33817 * Removes and destroys all items in the menu
33819 removeAll : function(){
33821 while(f = this.items.first()){
33827 // MenuNav is a private utility class used internally by the Menu
33828 Roo.menu.MenuNav = function(menu){
33829 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
33830 this.scope = this.menu = menu;
33833 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
33834 doRelay : function(e, h){
33835 var k = e.getKey();
33836 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
33837 this.menu.tryActivate(0, 1);
33840 return h.call(this.scope || this, e, this.menu);
33843 up : function(e, m){
33844 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
33845 m.tryActivate(m.items.length-1, -1);
33849 down : function(e, m){
33850 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
33851 m.tryActivate(0, 1);
33855 right : function(e, m){
33857 m.activeItem.expandMenu(true);
33861 left : function(e, m){
33863 if(m.parentMenu && m.parentMenu.activeItem){
33864 m.parentMenu.activeItem.activate();
33868 enter : function(e, m){
33870 e.stopPropagation();
33871 m.activeItem.onClick(e);
33872 m.fireEvent("click", this, m.activeItem);
33878 * Ext JS Library 1.1.1
33879 * Copyright(c) 2006-2007, Ext JS, LLC.
33881 * Originally Released Under LGPL - original licence link has changed is not relivant.
33884 * <script type="text/javascript">
33888 * @class Roo.menu.MenuMgr
33889 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
33892 Roo.menu.MenuMgr = function(){
33893 var menus, active, groups = {}, attached = false, lastShow = new Date();
33895 // private - called when first menu is created
33898 active = new Roo.util.MixedCollection();
33899 Roo.get(document).addKeyListener(27, function(){
33900 if(active.length > 0){
33907 function hideAll(){
33908 if(active && active.length > 0){
33909 var c = active.clone();
33910 c.each(function(m){
33917 function onHide(m){
33919 if(active.length < 1){
33920 Roo.get(document).un("mousedown", onMouseDown);
33926 function onShow(m){
33927 var last = active.last();
33928 lastShow = new Date();
33931 Roo.get(document).on("mousedown", onMouseDown);
33935 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
33936 m.parentMenu.activeChild = m;
33937 }else if(last && last.isVisible()){
33938 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
33943 function onBeforeHide(m){
33945 m.activeChild.hide();
33947 if(m.autoHideTimer){
33948 clearTimeout(m.autoHideTimer);
33949 delete m.autoHideTimer;
33954 function onBeforeShow(m){
33955 var pm = m.parentMenu;
33956 if(!pm && !m.allowOtherMenus){
33958 }else if(pm && pm.activeChild && active != m){
33959 pm.activeChild.hide();
33964 function onMouseDown(e){
33965 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
33971 function onBeforeCheck(mi, state){
33973 var g = groups[mi.group];
33974 for(var i = 0, l = g.length; i < l; i++){
33976 g[i].setChecked(false);
33985 * Hides all menus that are currently visible
33987 hideAll : function(){
33992 register : function(menu){
33996 menus[menu.id] = menu;
33997 menu.on("beforehide", onBeforeHide);
33998 menu.on("hide", onHide);
33999 menu.on("beforeshow", onBeforeShow);
34000 menu.on("show", onShow);
34001 var g = menu.group;
34002 if(g && menu.events["checkchange"]){
34006 groups[g].push(menu);
34007 menu.on("checkchange", onCheck);
34012 * Returns a {@link Roo.menu.Menu} object
34013 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34014 * be used to generate and return a new Menu instance.
34016 get : function(menu){
34017 if(typeof menu == "string"){ // menu id
34018 return menus[menu];
34019 }else if(menu.events){ // menu instance
34021 }else if(typeof menu.length == 'number'){ // array of menu items?
34022 return new Roo.menu.Menu({items:menu});
34023 }else{ // otherwise, must be a config
34024 return new Roo.menu.Menu(menu);
34029 unregister : function(menu){
34030 delete menus[menu.id];
34031 menu.un("beforehide", onBeforeHide);
34032 menu.un("hide", onHide);
34033 menu.un("beforeshow", onBeforeShow);
34034 menu.un("show", onShow);
34035 var g = menu.group;
34036 if(g && menu.events["checkchange"]){
34037 groups[g].remove(menu);
34038 menu.un("checkchange", onCheck);
34043 registerCheckable : function(menuItem){
34044 var g = menuItem.group;
34049 groups[g].push(menuItem);
34050 menuItem.on("beforecheckchange", onBeforeCheck);
34055 unregisterCheckable : function(menuItem){
34056 var g = menuItem.group;
34058 groups[g].remove(menuItem);
34059 menuItem.un("beforecheckchange", onBeforeCheck);
34065 * Ext JS Library 1.1.1
34066 * Copyright(c) 2006-2007, Ext JS, LLC.
34068 * Originally Released Under LGPL - original licence link has changed is not relivant.
34071 * <script type="text/javascript">
34076 * @class Roo.menu.BaseItem
34077 * @extends Roo.Component
34078 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34079 * management and base configuration options shared by all menu components.
34081 * Creates a new BaseItem
34082 * @param {Object} config Configuration options
34084 Roo.menu.BaseItem = function(config){
34085 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34090 * Fires when this item is clicked
34091 * @param {Roo.menu.BaseItem} this
34092 * @param {Roo.EventObject} e
34097 * Fires when this item is activated
34098 * @param {Roo.menu.BaseItem} this
34102 * @event deactivate
34103 * Fires when this item is deactivated
34104 * @param {Roo.menu.BaseItem} this
34110 this.on("click", this.handler, this.scope, true);
34114 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34116 * @cfg {Function} handler
34117 * A function that will handle the click event of this menu item (defaults to undefined)
34120 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34122 canActivate : false,
34124 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34126 activeClass : "x-menu-item-active",
34128 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34130 hideOnClick : true,
34132 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34137 ctype: "Roo.menu.BaseItem",
34140 actionMode : "container",
34143 render : function(container, parentMenu){
34144 this.parentMenu = parentMenu;
34145 Roo.menu.BaseItem.superclass.render.call(this, container);
34146 this.container.menuItemId = this.id;
34150 onRender : function(container, position){
34151 this.el = Roo.get(this.el);
34152 container.dom.appendChild(this.el.dom);
34156 onClick : function(e){
34157 if(!this.disabled && this.fireEvent("click", this, e) !== false
34158 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34159 this.handleClick(e);
34166 activate : function(){
34170 var li = this.container;
34171 li.addClass(this.activeClass);
34172 this.region = li.getRegion().adjust(2, 2, -2, -2);
34173 this.fireEvent("activate", this);
34178 deactivate : function(){
34179 this.container.removeClass(this.activeClass);
34180 this.fireEvent("deactivate", this);
34184 shouldDeactivate : function(e){
34185 return !this.region || !this.region.contains(e.getPoint());
34189 handleClick : function(e){
34190 if(this.hideOnClick){
34191 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34196 expandMenu : function(autoActivate){
34201 hideMenu : function(){
34206 * Ext JS Library 1.1.1
34207 * Copyright(c) 2006-2007, Ext JS, LLC.
34209 * Originally Released Under LGPL - original licence link has changed is not relivant.
34212 * <script type="text/javascript">
34216 * @class Roo.menu.Adapter
34217 * @extends Roo.menu.BaseItem
34218 * 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.
34219 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34221 * Creates a new Adapter
34222 * @param {Object} config Configuration options
34224 Roo.menu.Adapter = function(component, config){
34225 Roo.menu.Adapter.superclass.constructor.call(this, config);
34226 this.component = component;
34228 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34230 canActivate : true,
34233 onRender : function(container, position){
34234 this.component.render(container);
34235 this.el = this.component.getEl();
34239 activate : function(){
34243 this.component.focus();
34244 this.fireEvent("activate", this);
34249 deactivate : function(){
34250 this.fireEvent("deactivate", this);
34254 disable : function(){
34255 this.component.disable();
34256 Roo.menu.Adapter.superclass.disable.call(this);
34260 enable : function(){
34261 this.component.enable();
34262 Roo.menu.Adapter.superclass.enable.call(this);
34266 * Ext JS Library 1.1.1
34267 * Copyright(c) 2006-2007, Ext JS, LLC.
34269 * Originally Released Under LGPL - original licence link has changed is not relivant.
34272 * <script type="text/javascript">
34276 * @class Roo.menu.TextItem
34277 * @extends Roo.menu.BaseItem
34278 * Adds a static text string to a menu, usually used as either a heading or group separator.
34280 * Creates a new TextItem
34281 * @param {String} text The text to display
34283 Roo.menu.TextItem = function(text){
34285 Roo.menu.TextItem.superclass.constructor.call(this);
34288 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34290 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34292 hideOnClick : false,
34294 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34296 itemCls : "x-menu-text",
34299 onRender : function(){
34300 var s = document.createElement("span");
34301 s.className = this.itemCls;
34302 s.innerHTML = this.text;
34304 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34308 * Ext JS Library 1.1.1
34309 * Copyright(c) 2006-2007, Ext JS, LLC.
34311 * Originally Released Under LGPL - original licence link has changed is not relivant.
34314 * <script type="text/javascript">
34318 * @class Roo.menu.Separator
34319 * @extends Roo.menu.BaseItem
34320 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34321 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34323 * @param {Object} config Configuration options
34325 Roo.menu.Separator = function(config){
34326 Roo.menu.Separator.superclass.constructor.call(this, config);
34329 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34331 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34333 itemCls : "x-menu-sep",
34335 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34337 hideOnClick : false,
34340 onRender : function(li){
34341 var s = document.createElement("span");
34342 s.className = this.itemCls;
34343 s.innerHTML = " ";
34345 li.addClass("x-menu-sep-li");
34346 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34350 * Ext JS Library 1.1.1
34351 * Copyright(c) 2006-2007, Ext JS, LLC.
34353 * Originally Released Under LGPL - original licence link has changed is not relivant.
34356 * <script type="text/javascript">
34359 * @class Roo.menu.Item
34360 * @extends Roo.menu.BaseItem
34361 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34362 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34363 * activation and click handling.
34365 * Creates a new Item
34366 * @param {Object} config Configuration options
34368 Roo.menu.Item = function(config){
34369 Roo.menu.Item.superclass.constructor.call(this, config);
34371 this.menu = Roo.menu.MenuMgr.get(this.menu);
34374 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34376 * @cfg {String} icon
34377 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34380 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34382 itemCls : "x-menu-item",
34384 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34386 canActivate : true,
34388 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34391 // doc'd in BaseItem
34395 ctype: "Roo.menu.Item",
34398 onRender : function(container, position){
34399 var el = document.createElement("a");
34400 el.hideFocus = true;
34401 el.unselectable = "on";
34402 el.href = this.href || "#";
34403 if(this.hrefTarget){
34404 el.target = this.hrefTarget;
34406 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34407 el.innerHTML = String.format(
34408 '<img src="{0}" class="x-menu-item-icon {2}" />{1}',
34409 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || '');
34411 Roo.menu.Item.superclass.onRender.call(this, container, position);
34415 * Sets the text to display in this menu item
34416 * @param {String} text The text to display
34418 setText : function(text){
34421 this.el.update(String.format(
34422 '<img src="{0}" class="x-menu-item-icon {2}">{1}',
34423 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34424 this.parentMenu.autoWidth();
34429 handleClick : function(e){
34430 if(!this.href){ // if no link defined, stop the event automatically
34433 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34437 activate : function(autoExpand){
34438 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34448 shouldDeactivate : function(e){
34449 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34450 if(this.menu && this.menu.isVisible()){
34451 return !this.menu.getEl().getRegion().contains(e.getPoint());
34459 deactivate : function(){
34460 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34465 expandMenu : function(autoActivate){
34466 if(!this.disabled && this.menu){
34467 clearTimeout(this.hideTimer);
34468 delete this.hideTimer;
34469 if(!this.menu.isVisible() && !this.showTimer){
34470 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34471 }else if (this.menu.isVisible() && autoActivate){
34472 this.menu.tryActivate(0, 1);
34478 deferExpand : function(autoActivate){
34479 delete this.showTimer;
34480 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34482 this.menu.tryActivate(0, 1);
34487 hideMenu : function(){
34488 clearTimeout(this.showTimer);
34489 delete this.showTimer;
34490 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34491 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34496 deferHide : function(){
34497 delete this.hideTimer;
34502 * Ext JS Library 1.1.1
34503 * Copyright(c) 2006-2007, Ext JS, LLC.
34505 * Originally Released Under LGPL - original licence link has changed is not relivant.
34508 * <script type="text/javascript">
34512 * @class Roo.menu.CheckItem
34513 * @extends Roo.menu.Item
34514 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34516 * Creates a new CheckItem
34517 * @param {Object} config Configuration options
34519 Roo.menu.CheckItem = function(config){
34520 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34523 * @event beforecheckchange
34524 * Fires before the checked value is set, providing an opportunity to cancel if needed
34525 * @param {Roo.menu.CheckItem} this
34526 * @param {Boolean} checked The new checked value that will be set
34528 "beforecheckchange" : true,
34530 * @event checkchange
34531 * Fires after the checked value has been set
34532 * @param {Roo.menu.CheckItem} this
34533 * @param {Boolean} checked The checked value that was set
34535 "checkchange" : true
34537 if(this.checkHandler){
34538 this.on('checkchange', this.checkHandler, this.scope);
34541 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34543 * @cfg {String} group
34544 * All check items with the same group name will automatically be grouped into a single-select
34545 * radio button group (defaults to '')
34548 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34550 itemCls : "x-menu-item x-menu-check-item",
34552 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34554 groupClass : "x-menu-group-item",
34557 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34558 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34559 * initialized with checked = true will be rendered as checked.
34564 ctype: "Roo.menu.CheckItem",
34567 onRender : function(c){
34568 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34570 this.el.addClass(this.groupClass);
34572 Roo.menu.MenuMgr.registerCheckable(this);
34574 this.checked = false;
34575 this.setChecked(true, true);
34580 destroy : function(){
34582 Roo.menu.MenuMgr.unregisterCheckable(this);
34584 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
34588 * Set the checked state of this item
34589 * @param {Boolean} checked The new checked value
34590 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
34592 setChecked : function(state, suppressEvent){
34593 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
34594 if(this.container){
34595 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
34597 this.checked = state;
34598 if(suppressEvent !== true){
34599 this.fireEvent("checkchange", this, state);
34605 handleClick : function(e){
34606 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
34607 this.setChecked(!this.checked);
34609 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
34613 * Ext JS Library 1.1.1
34614 * Copyright(c) 2006-2007, Ext JS, LLC.
34616 * Originally Released Under LGPL - original licence link has changed is not relivant.
34619 * <script type="text/javascript">
34623 * @class Roo.menu.DateItem
34624 * @extends Roo.menu.Adapter
34625 * A menu item that wraps the {@link Roo.DatPicker} component.
34627 * Creates a new DateItem
34628 * @param {Object} config Configuration options
34630 Roo.menu.DateItem = function(config){
34631 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
34632 /** The Roo.DatePicker object @type Roo.DatePicker */
34633 this.picker = this.component;
34634 this.addEvents({select: true});
34636 this.picker.on("render", function(picker){
34637 picker.getEl().swallowEvent("click");
34638 picker.container.addClass("x-menu-date-item");
34641 this.picker.on("select", this.onSelect, this);
34644 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
34646 onSelect : function(picker, date){
34647 this.fireEvent("select", this, date, picker);
34648 Roo.menu.DateItem.superclass.handleClick.call(this);
34652 * Ext JS Library 1.1.1
34653 * Copyright(c) 2006-2007, Ext JS, LLC.
34655 * Originally Released Under LGPL - original licence link has changed is not relivant.
34658 * <script type="text/javascript">
34662 * @class Roo.menu.ColorItem
34663 * @extends Roo.menu.Adapter
34664 * A menu item that wraps the {@link Roo.ColorPalette} component.
34666 * Creates a new ColorItem
34667 * @param {Object} config Configuration options
34669 Roo.menu.ColorItem = function(config){
34670 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
34671 /** The Roo.ColorPalette object @type Roo.ColorPalette */
34672 this.palette = this.component;
34673 this.relayEvents(this.palette, ["select"]);
34674 if(this.selectHandler){
34675 this.on('select', this.selectHandler, this.scope);
34678 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
34680 * Ext JS Library 1.1.1
34681 * Copyright(c) 2006-2007, Ext JS, LLC.
34683 * Originally Released Under LGPL - original licence link has changed is not relivant.
34686 * <script type="text/javascript">
34691 * @class Roo.menu.DateMenu
34692 * @extends Roo.menu.Menu
34693 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
34695 * Creates a new DateMenu
34696 * @param {Object} config Configuration options
34698 Roo.menu.DateMenu = function(config){
34699 Roo.menu.DateMenu.superclass.constructor.call(this, config);
34701 var di = new Roo.menu.DateItem(config);
34704 * The {@link Roo.DatePicker} instance for this DateMenu
34707 this.picker = di.picker;
34710 * @param {DatePicker} picker
34711 * @param {Date} date
34713 this.relayEvents(di, ["select"]);
34715 this.on('beforeshow', function(){
34717 this.picker.hideMonthPicker(true);
34721 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
34725 * Ext JS Library 1.1.1
34726 * Copyright(c) 2006-2007, Ext JS, LLC.
34728 * Originally Released Under LGPL - original licence link has changed is not relivant.
34731 * <script type="text/javascript">
34736 * @class Roo.menu.ColorMenu
34737 * @extends Roo.menu.Menu
34738 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
34740 * Creates a new ColorMenu
34741 * @param {Object} config Configuration options
34743 Roo.menu.ColorMenu = function(config){
34744 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
34746 var ci = new Roo.menu.ColorItem(config);
34749 * The {@link Roo.ColorPalette} instance for this ColorMenu
34750 * @type ColorPalette
34752 this.palette = ci.palette;
34755 * @param {ColorPalette} palette
34756 * @param {String} color
34758 this.relayEvents(ci, ["select"]);
34760 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
34762 * Ext JS Library 1.1.1
34763 * Copyright(c) 2006-2007, Ext JS, LLC.
34765 * Originally Released Under LGPL - original licence link has changed is not relivant.
34768 * <script type="text/javascript">
34772 * @class Roo.form.Field
34773 * @extends Roo.BoxComponent
34774 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
34776 * Creates a new Field
34777 * @param {Object} config Configuration options
34779 Roo.form.Field = function(config){
34780 Roo.form.Field.superclass.constructor.call(this, config);
34783 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
34785 * @cfg {String} fieldLabel Label to use when rendering a form.
34788 * @cfg {String} qtip Mouse over tip
34792 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
34794 invalidClass : "x-form-invalid",
34796 * @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")
34798 invalidText : "The value in this field is invalid",
34800 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
34802 focusClass : "x-form-focus",
34804 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
34805 automatic validation (defaults to "keyup").
34807 validationEvent : "keyup",
34809 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
34811 validateOnBlur : true,
34813 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
34815 validationDelay : 250,
34817 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
34818 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
34820 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
34822 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
34824 fieldClass : "x-form-field",
34826 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
34829 ----------- ----------------------------------------------------------------------
34830 qtip Display a quick tip when the user hovers over the field
34831 title Display a default browser title attribute popup
34832 under Add a block div beneath the field containing the error text
34833 side Add an error icon to the right of the field with a popup on hover
34834 [element id] Add the error text directly to the innerHTML of the specified element
34837 msgTarget : 'qtip',
34839 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
34844 * @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.
34849 * @cfg {Boolean} disabled True to disable the field (defaults to false).
34854 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
34856 inputType : undefined,
34859 * @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).
34861 tabIndex : undefined,
34864 isFormField : true,
34869 * @property {Roo.Element} fieldEl
34870 * Element Containing the rendered Field (with label etc.)
34873 * @cfg {Mixed} value A value to initialize this field with.
34878 * @cfg {String} name The field's HTML name attribute.
34881 * @cfg {String} cls A CSS class to apply to the field's underlying element.
34885 initComponent : function(){
34886 Roo.form.Field.superclass.initComponent.call(this);
34890 * Fires when this field receives input focus.
34891 * @param {Roo.form.Field} this
34896 * Fires when this field loses input focus.
34897 * @param {Roo.form.Field} this
34901 * @event specialkey
34902 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
34903 * {@link Roo.EventObject#getKey} to determine which key was pressed.
34904 * @param {Roo.form.Field} this
34905 * @param {Roo.EventObject} e The event object
34910 * Fires just before the field blurs if the field value has changed.
34911 * @param {Roo.form.Field} this
34912 * @param {Mixed} newValue The new value
34913 * @param {Mixed} oldValue The original value
34918 * Fires after the field has been marked as invalid.
34919 * @param {Roo.form.Field} this
34920 * @param {String} msg The validation message
34925 * Fires after the field has been validated with no errors.
34926 * @param {Roo.form.Field} this
34933 * Returns the name attribute of the field if available
34934 * @return {String} name The field name
34936 getName: function(){
34937 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
34941 onRender : function(ct, position){
34942 Roo.form.Field.superclass.onRender.call(this, ct, position);
34944 var cfg = this.getAutoCreate();
34946 cfg.name = this.name || this.id;
34948 if(this.inputType){
34949 cfg.type = this.inputType;
34951 this.el = ct.createChild(cfg, position);
34953 var type = this.el.dom.type;
34955 if(type == 'password'){
34958 this.el.addClass('x-form-'+type);
34961 this.el.dom.readOnly = true;
34963 if(this.tabIndex !== undefined){
34964 this.el.dom.setAttribute('tabIndex', this.tabIndex);
34967 this.el.addClass([this.fieldClass, this.cls]);
34972 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
34973 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
34974 * @return {Roo.form.Field} this
34976 applyTo : function(target){
34977 this.allowDomMove = false;
34978 this.el = Roo.get(target);
34979 this.render(this.el.dom.parentNode);
34984 initValue : function(){
34985 if(this.value !== undefined){
34986 this.setValue(this.value);
34987 }else if(this.el.dom.value.length > 0){
34988 this.setValue(this.el.dom.value);
34993 * Returns true if this field has been changed since it was originally loaded and is not disabled.
34995 isDirty : function() {
34996 if(this.disabled) {
34999 return String(this.getValue()) !== String(this.originalValue);
35003 afterRender : function(){
35004 Roo.form.Field.superclass.afterRender.call(this);
35009 fireKey : function(e){
35010 if(e.isNavKeyPress()){
35011 this.fireEvent("specialkey", this, e);
35016 * Resets the current field value to the originally loaded value and clears any validation messages
35018 reset : function(){
35019 this.setValue(this.originalValue);
35020 this.clearInvalid();
35024 initEvents : function(){
35025 this.el.on(Roo.isIE ? "keydown" : "keypress", this.fireKey, this);
35026 this.el.on("focus", this.onFocus, this);
35027 this.el.on("blur", this.onBlur, this);
35029 // reference to original value for reset
35030 this.originalValue = this.getValue();
35034 onFocus : function(){
35035 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35036 this.el.addClass(this.focusClass);
35038 if(!this.hasFocus){
35039 this.hasFocus = true;
35040 this.startValue = this.getValue();
35041 this.fireEvent("focus", this);
35045 beforeBlur : Roo.emptyFn,
35048 onBlur : function(){
35050 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35051 this.el.removeClass(this.focusClass);
35053 this.hasFocus = false;
35054 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35057 var v = this.getValue();
35058 if(String(v) !== String(this.startValue)){
35059 this.fireEvent('change', this, v, this.startValue);
35061 this.fireEvent("blur", this);
35065 * Returns whether or not the field value is currently valid
35066 * @param {Boolean} preventMark True to disable marking the field invalid
35067 * @return {Boolean} True if the value is valid, else false
35069 isValid : function(preventMark){
35073 var restore = this.preventMark;
35074 this.preventMark = preventMark === true;
35075 var v = this.validateValue(this.processValue(this.getRawValue()));
35076 this.preventMark = restore;
35081 * Validates the field value
35082 * @return {Boolean} True if the value is valid, else false
35084 validate : function(){
35085 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35086 this.clearInvalid();
35092 processValue : function(value){
35097 // Subclasses should provide the validation implementation by overriding this
35098 validateValue : function(value){
35103 * Mark this field as invalid
35104 * @param {String} msg The validation message
35106 markInvalid : function(msg){
35107 if(!this.rendered || this.preventMark){ // not rendered
35110 this.el.addClass(this.invalidClass);
35111 msg = msg || this.invalidText;
35112 switch(this.msgTarget){
35114 this.el.dom.qtip = msg;
35115 this.el.dom.qclass = 'x-form-invalid-tip';
35116 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35117 Roo.QuickTips.enable();
35121 this.el.dom.title = msg;
35125 var elp = this.el.findParent('.x-form-element', 5, true);
35126 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35127 this.errorEl.setWidth(elp.getWidth(true)-20);
35129 this.errorEl.update(msg);
35130 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35133 if(!this.errorIcon){
35134 var elp = this.el.findParent('.x-form-element', 5, true);
35135 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35137 this.alignErrorIcon();
35138 this.errorIcon.dom.qtip = msg;
35139 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35140 this.errorIcon.show();
35141 this.on('resize', this.alignErrorIcon, this);
35144 var t = Roo.getDom(this.msgTarget);
35146 t.style.display = this.msgDisplay;
35149 this.fireEvent('invalid', this, msg);
35153 alignErrorIcon : function(){
35154 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35158 * Clear any invalid styles/messages for this field
35160 clearInvalid : function(){
35161 if(!this.rendered || this.preventMark){ // not rendered
35164 this.el.removeClass(this.invalidClass);
35165 switch(this.msgTarget){
35167 this.el.dom.qtip = '';
35170 this.el.dom.title = '';
35174 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35178 if(this.errorIcon){
35179 this.errorIcon.dom.qtip = '';
35180 this.errorIcon.hide();
35181 this.un('resize', this.alignErrorIcon, this);
35185 var t = Roo.getDom(this.msgTarget);
35187 t.style.display = 'none';
35190 this.fireEvent('valid', this);
35194 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35195 * @return {Mixed} value The field value
35197 getRawValue : function(){
35198 var v = this.el.getValue();
35199 if(v === this.emptyText){
35206 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35207 * @return {Mixed} value The field value
35209 getValue : function(){
35210 var v = this.el.getValue();
35211 if(v === this.emptyText || v === undefined){
35218 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35219 * @param {Mixed} value The value to set
35221 setRawValue : function(v){
35222 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35226 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35227 * @param {Mixed} value The value to set
35229 setValue : function(v){
35232 this.el.dom.value = (v === null || v === undefined ? '' : v);
35237 adjustSize : function(w, h){
35238 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35239 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35243 adjustWidth : function(tag, w){
35244 tag = tag.toLowerCase();
35245 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35246 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35247 if(tag == 'input'){
35250 if(tag = 'textarea'){
35253 }else if(Roo.isOpera){
35254 if(tag == 'input'){
35257 if(tag = 'textarea'){
35267 // anything other than normal should be considered experimental
35268 Roo.form.Field.msgFx = {
35270 show: function(msgEl, f){
35271 msgEl.setDisplayed('block');
35274 hide : function(msgEl, f){
35275 msgEl.setDisplayed(false).update('');
35280 show: function(msgEl, f){
35281 msgEl.slideIn('t', {stopFx:true});
35284 hide : function(msgEl, f){
35285 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35290 show: function(msgEl, f){
35291 msgEl.fixDisplay();
35292 msgEl.alignTo(f.el, 'tl-tr');
35293 msgEl.slideIn('l', {stopFx:true});
35296 hide : function(msgEl, f){
35297 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35302 * Ext JS Library 1.1.1
35303 * Copyright(c) 2006-2007, Ext JS, LLC.
35305 * Originally Released Under LGPL - original licence link has changed is not relivant.
35308 * <script type="text/javascript">
35313 * @class Roo.form.TextField
35314 * @extends Roo.form.Field
35315 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35316 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35318 * Creates a new TextField
35319 * @param {Object} config Configuration options
35321 Roo.form.TextField = function(config){
35322 Roo.form.TextField.superclass.constructor.call(this, config);
35326 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35327 * according to the default logic, but this event provides a hook for the developer to apply additional
35328 * logic at runtime to resize the field if needed.
35329 * @param {Roo.form.Field} this This text field
35330 * @param {Number} width The new field width
35336 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35338 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35342 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35346 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35350 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35354 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35358 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35360 disableKeyFilter : false,
35362 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35366 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35370 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35372 maxLength : Number.MAX_VALUE,
35374 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35376 minLengthText : "The minimum length for this field is {0}",
35378 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35380 maxLengthText : "The maximum length for this field is {0}",
35382 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35384 selectOnFocus : false,
35386 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35388 blankText : "This field is required",
35390 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35391 * If available, this function will be called only after the basic validators all return true, and will be passed the
35392 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35396 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35397 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35398 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35402 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35406 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35410 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35411 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35413 emptyClass : 'x-form-empty-field',
35416 initEvents : function(){
35417 Roo.form.TextField.superclass.initEvents.call(this);
35418 if(this.validationEvent == 'keyup'){
35419 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35420 this.el.on('keyup', this.filterValidation, this);
35422 else if(this.validationEvent !== false){
35423 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35425 if(this.selectOnFocus || this.emptyText){
35426 this.on("focus", this.preFocus, this);
35427 if(this.emptyText){
35428 this.on('blur', this.postBlur, this);
35429 this.applyEmptyText();
35432 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35433 this.el.on("keypress", this.filterKeys, this);
35436 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35437 this.el.on("click", this.autoSize, this);
35441 processValue : function(value){
35442 if(this.stripCharsRe){
35443 var newValue = value.replace(this.stripCharsRe, '');
35444 if(newValue !== value){
35445 this.setRawValue(newValue);
35452 filterValidation : function(e){
35453 if(!e.isNavKeyPress()){
35454 this.validationTask.delay(this.validationDelay);
35459 onKeyUp : function(e){
35460 if(!e.isNavKeyPress()){
35466 * Resets the current field value to the originally-loaded value and clears any validation messages.
35467 * Also adds emptyText and emptyClass if the original value was blank.
35469 reset : function(){
35470 Roo.form.TextField.superclass.reset.call(this);
35471 this.applyEmptyText();
35474 applyEmptyText : function(){
35475 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35476 this.setRawValue(this.emptyText);
35477 this.el.addClass(this.emptyClass);
35482 preFocus : function(){
35483 if(this.emptyText){
35484 if(this.el.dom.value == this.emptyText){
35485 this.setRawValue('');
35487 this.el.removeClass(this.emptyClass);
35489 if(this.selectOnFocus){
35490 this.el.dom.select();
35495 postBlur : function(){
35496 this.applyEmptyText();
35500 filterKeys : function(e){
35501 var k = e.getKey();
35502 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35505 var c = e.getCharCode(), cc = String.fromCharCode(c);
35506 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35509 if(!this.maskRe.test(cc)){
35514 setValue : function(v){
35515 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35516 this.el.removeClass(this.emptyClass);
35518 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35519 this.applyEmptyText();
35524 * Validates a value according to the field's validation rules and marks the field as invalid
35525 * if the validation fails
35526 * @param {Mixed} value The value to validate
35527 * @return {Boolean} True if the value is valid, else false
35529 validateValue : function(value){
35530 if(value.length < 1 || value === this.emptyText){ // if it's blank
35531 if(this.allowBlank){
35532 this.clearInvalid();
35535 this.markInvalid(this.blankText);
35539 if(value.length < this.minLength){
35540 this.markInvalid(String.format(this.minLengthText, this.minLength));
35543 if(value.length > this.maxLength){
35544 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35548 var vt = Roo.form.VTypes;
35549 if(!vt[this.vtype](value, this)){
35550 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35554 if(typeof this.validator == "function"){
35555 var msg = this.validator(value);
35557 this.markInvalid(msg);
35561 if(this.regex && !this.regex.test(value)){
35562 this.markInvalid(this.regexText);
35569 * Selects text in this field
35570 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
35571 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
35573 selectText : function(start, end){
35574 var v = this.getRawValue();
35576 start = start === undefined ? 0 : start;
35577 end = end === undefined ? v.length : end;
35578 var d = this.el.dom;
35579 if(d.setSelectionRange){
35580 d.setSelectionRange(start, end);
35581 }else if(d.createTextRange){
35582 var range = d.createTextRange();
35583 range.moveStart("character", start);
35584 range.moveEnd("character", v.length-end);
35591 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
35592 * This only takes effect if grow = true, and fires the autosize event.
35594 autoSize : function(){
35595 if(!this.grow || !this.rendered){
35599 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
35602 var v = el.dom.value;
35603 var d = document.createElement('div');
35604 d.appendChild(document.createTextNode(v));
35608 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
35609 this.el.setWidth(w);
35610 this.fireEvent("autosize", this, w);
35614 * Ext JS Library 1.1.1
35615 * Copyright(c) 2006-2007, Ext JS, LLC.
35617 * Originally Released Under LGPL - original licence link has changed is not relivant.
35620 * <script type="text/javascript">
35624 * @class Roo.form.Hidden
35625 * @extends Roo.form.TextField
35626 * Simple Hidden element used on forms
35628 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
35631 * Creates a new Hidden form element.
35632 * @param {Object} config Configuration options
35637 // easy hidden field...
35638 Roo.form.Hidden = function(config){
35639 Roo.form.Hidden.superclass.constructor.call(this, config);
35642 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
35644 inputType: 'hidden',
35647 labelSeparator: '',
35649 itemCls : 'x-form-item-display-none'
35657 * Ext JS Library 1.1.1
35658 * Copyright(c) 2006-2007, Ext JS, LLC.
35660 * Originally Released Under LGPL - original licence link has changed is not relivant.
35663 * <script type="text/javascript">
35667 * @class Roo.form.TriggerField
35668 * @extends Roo.form.TextField
35669 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
35670 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
35671 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
35672 * for which you can provide a custom implementation. For example:
35674 var trigger = new Roo.form.TriggerField();
35675 trigger.onTriggerClick = myTriggerFn;
35676 trigger.applyTo('my-field');
35679 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
35680 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
35681 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
35682 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
35684 * Create a new TriggerField.
35685 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
35686 * to the base TextField)
35688 Roo.form.TriggerField = function(config){
35689 this.mimicing = false;
35690 Roo.form.TriggerField.superclass.constructor.call(this, config);
35693 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
35695 * @cfg {String} triggerClass A CSS class to apply to the trigger
35698 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35699 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
35701 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
35703 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
35707 /** @cfg {Boolean} grow @hide */
35708 /** @cfg {Number} growMin @hide */
35709 /** @cfg {Number} growMax @hide */
35715 autoSize: Roo.emptyFn,
35719 deferHeight : true,
35722 actionMode : 'wrap',
35724 onResize : function(w, h){
35725 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
35726 if(typeof w == 'number'){
35727 this.el.setWidth(this.adjustWidth('input', w - this.trigger.getWidth()));
35732 adjustSize : Roo.BoxComponent.prototype.adjustSize,
35735 getResizeEl : function(){
35740 getPositionEl : function(){
35745 alignErrorIcon : function(){
35746 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
35750 onRender : function(ct, position){
35751 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
35752 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
35753 this.trigger = this.wrap.createChild(this.triggerConfig ||
35754 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
35755 if(this.hideTrigger){
35756 this.trigger.setDisplayed(false);
35758 this.initTrigger();
35760 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
35765 initTrigger : function(){
35766 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
35767 this.trigger.addClassOnOver('x-form-trigger-over');
35768 this.trigger.addClassOnClick('x-form-trigger-click');
35772 onDestroy : function(){
35774 this.trigger.removeAllListeners();
35775 this.trigger.remove();
35778 this.wrap.remove();
35780 Roo.form.TriggerField.superclass.onDestroy.call(this);
35784 onFocus : function(){
35785 Roo.form.TriggerField.superclass.onFocus.call(this);
35786 if(!this.mimicing){
35787 this.wrap.addClass('x-trigger-wrap-focus');
35788 this.mimicing = true;
35789 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
35790 if(this.monitorTab){
35791 this.el.on("keydown", this.checkTab, this);
35797 checkTab : function(e){
35798 if(e.getKey() == e.TAB){
35799 this.triggerBlur();
35804 onBlur : function(){
35809 mimicBlur : function(e, t){
35810 if(!this.wrap.contains(t) && this.validateBlur()){
35811 this.triggerBlur();
35816 triggerBlur : function(){
35817 this.mimicing = false;
35818 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
35819 if(this.monitorTab){
35820 this.el.un("keydown", this.checkTab, this);
35822 this.wrap.removeClass('x-trigger-wrap-focus');
35823 Roo.form.TriggerField.superclass.onBlur.call(this);
35827 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
35828 validateBlur : function(e, t){
35833 onDisable : function(){
35834 Roo.form.TriggerField.superclass.onDisable.call(this);
35836 this.wrap.addClass('x-item-disabled');
35841 onEnable : function(){
35842 Roo.form.TriggerField.superclass.onEnable.call(this);
35844 this.wrap.removeClass('x-item-disabled');
35849 onShow : function(){
35850 var ae = this.getActionEl();
35853 ae.dom.style.display = '';
35854 ae.dom.style.visibility = 'visible';
35860 onHide : function(){
35861 var ae = this.getActionEl();
35862 ae.dom.style.display = 'none';
35866 * The function that should handle the trigger's click event. This method does nothing by default until overridden
35867 * by an implementing function.
35869 * @param {EventObject} e
35871 onTriggerClick : Roo.emptyFn
35874 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
35875 // to be extended by an implementing class. For an example of implementing this class, see the custom
35876 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
35877 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
35878 initComponent : function(){
35879 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
35881 this.triggerConfig = {
35882 tag:'span', cls:'x-form-twin-triggers', cn:[
35883 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
35884 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
35888 getTrigger : function(index){
35889 return this.triggers[index];
35892 initTrigger : function(){
35893 var ts = this.trigger.select('.x-form-trigger', true);
35894 this.wrap.setStyle('overflow', 'hidden');
35895 var triggerField = this;
35896 ts.each(function(t, all, index){
35897 t.hide = function(){
35898 var w = triggerField.wrap.getWidth();
35899 this.dom.style.display = 'none';
35900 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
35902 t.show = function(){
35903 var w = triggerField.wrap.getWidth();
35904 this.dom.style.display = '';
35905 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
35907 var triggerIndex = 'Trigger'+(index+1);
35909 if(this['hide'+triggerIndex]){
35910 t.dom.style.display = 'none';
35912 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
35913 t.addClassOnOver('x-form-trigger-over');
35914 t.addClassOnClick('x-form-trigger-click');
35916 this.triggers = ts.elements;
35919 onTrigger1Click : Roo.emptyFn,
35920 onTrigger2Click : Roo.emptyFn
35923 * Ext JS Library 1.1.1
35924 * Copyright(c) 2006-2007, Ext JS, LLC.
35926 * Originally Released Under LGPL - original licence link has changed is not relivant.
35929 * <script type="text/javascript">
35933 * @class Roo.form.TextArea
35934 * @extends Roo.form.TextField
35935 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
35936 * support for auto-sizing.
35938 * Creates a new TextArea
35939 * @param {Object} config Configuration options
35941 Roo.form.TextArea = function(config){
35942 Roo.form.TextArea.superclass.constructor.call(this, config);
35943 // these are provided exchanges for backwards compat
35944 // minHeight/maxHeight were replaced by growMin/growMax to be
35945 // compatible with TextField growing config values
35946 if(this.minHeight !== undefined){
35947 this.growMin = this.minHeight;
35949 if(this.maxHeight !== undefined){
35950 this.growMax = this.maxHeight;
35954 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
35956 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
35960 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
35964 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
35965 * in the field (equivalent to setting overflow: hidden, defaults to false)
35967 preventScrollbars: false,
35969 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35970 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
35974 onRender : function(ct, position){
35976 this.defaultAutoCreate = {
35978 style:"width:300px;height:60px;",
35979 autocomplete: "off"
35982 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
35984 this.textSizeEl = Roo.DomHelper.append(document.body, {
35985 tag: "pre", cls: "x-form-grow-sizer"
35987 if(this.preventScrollbars){
35988 this.el.setStyle("overflow", "hidden");
35990 this.el.setHeight(this.growMin);
35994 onDestroy : function(){
35995 if(this.textSizeEl){
35996 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
35998 Roo.form.TextArea.superclass.onDestroy.call(this);
36002 onKeyUp : function(e){
36003 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36009 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36010 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36012 autoSize : function(){
36013 if(!this.grow || !this.textSizeEl){
36017 var v = el.dom.value;
36018 var ts = this.textSizeEl;
36021 ts.appendChild(document.createTextNode(v));
36024 Roo.fly(ts).setWidth(this.el.getWidth());
36026 v = "  ";
36029 v = v.replace(/\n/g, '<p> </p>');
36031 v += " \n ";
36034 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36035 if(h != this.lastHeight){
36036 this.lastHeight = h;
36037 this.el.setHeight(h);
36038 this.fireEvent("autosize", this, h);
36043 * Ext JS Library 1.1.1
36044 * Copyright(c) 2006-2007, Ext JS, LLC.
36046 * Originally Released Under LGPL - original licence link has changed is not relivant.
36049 * <script type="text/javascript">
36054 * @class Roo.form.NumberField
36055 * @extends Roo.form.TextField
36056 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36058 * Creates a new NumberField
36059 * @param {Object} config Configuration options
36061 Roo.form.NumberField = function(config){
36062 Roo.form.NumberField.superclass.constructor.call(this, config);
36065 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36067 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36069 fieldClass: "x-form-field x-form-num-field",
36071 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36073 allowDecimals : true,
36075 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36077 decimalSeparator : ".",
36079 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36081 decimalPrecision : 2,
36083 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36085 allowNegative : true,
36087 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36089 minValue : Number.NEGATIVE_INFINITY,
36091 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36093 maxValue : Number.MAX_VALUE,
36095 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36097 minText : "The minimum value for this field is {0}",
36099 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36101 maxText : "The maximum value for this field is {0}",
36103 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36104 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36106 nanText : "{0} is not a valid number",
36109 initEvents : function(){
36110 Roo.form.NumberField.superclass.initEvents.call(this);
36111 var allowed = "0123456789";
36112 if(this.allowDecimals){
36113 allowed += this.decimalSeparator;
36115 if(this.allowNegative){
36118 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36119 var keyPress = function(e){
36120 var k = e.getKey();
36121 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36124 var c = e.getCharCode();
36125 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36129 this.el.on("keypress", keyPress, this);
36133 validateValue : function(value){
36134 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36137 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36140 var num = this.parseValue(value);
36142 this.markInvalid(String.format(this.nanText, value));
36145 if(num < this.minValue){
36146 this.markInvalid(String.format(this.minText, this.minValue));
36149 if(num > this.maxValue){
36150 this.markInvalid(String.format(this.maxText, this.maxValue));
36156 getValue : function(){
36157 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36161 parseValue : function(value){
36162 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36163 return isNaN(value) ? '' : value;
36167 fixPrecision : function(value){
36168 var nan = isNaN(value);
36169 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36170 return nan ? '' : value;
36172 return parseFloat(value).toFixed(this.decimalPrecision);
36175 setValue : function(v){
36176 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36180 decimalPrecisionFcn : function(v){
36181 return Math.floor(v);
36184 beforeBlur : function(){
36185 var v = this.parseValue(this.getRawValue());
36187 this.setValue(this.fixPrecision(v));
36192 * Ext JS Library 1.1.1
36193 * Copyright(c) 2006-2007, Ext JS, LLC.
36195 * Originally Released Under LGPL - original licence link has changed is not relivant.
36198 * <script type="text/javascript">
36202 * @class Roo.form.DateField
36203 * @extends Roo.form.TriggerField
36204 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36206 * Create a new DateField
36207 * @param {Object} config
36209 Roo.form.DateField = function(config){
36210 Roo.form.DateField.superclass.constructor.call(this, config);
36216 * Fires when a date is selected
36217 * @param {Roo.form.DateField} combo This combo box
36218 * @param {Date} date The date selected
36225 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36226 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36227 this.ddMatch = null;
36228 if(this.disabledDates){
36229 var dd = this.disabledDates;
36231 for(var i = 0; i < dd.length; i++){
36233 if(i != dd.length-1) re += "|";
36235 this.ddMatch = new RegExp(re + ")");
36239 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36241 * @cfg {String} format
36242 * The default date format string which can be overriden for localization support. The format must be
36243 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36247 * @cfg {String} altFormats
36248 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36249 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36251 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36253 * @cfg {Array} disabledDays
36254 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36256 disabledDays : null,
36258 * @cfg {String} disabledDaysText
36259 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36261 disabledDaysText : "Disabled",
36263 * @cfg {Array} disabledDates
36264 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36265 * expression so they are very powerful. Some examples:
36267 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36268 * <li>["03/08", "09/16"] would disable those days for every year</li>
36269 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36270 * <li>["03/../2006"] would disable every day in March 2006</li>
36271 * <li>["^03"] would disable every day in every March</li>
36273 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36274 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36276 disabledDates : null,
36278 * @cfg {String} disabledDatesText
36279 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36281 disabledDatesText : "Disabled",
36283 * @cfg {Date/String} minValue
36284 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36285 * valid format (defaults to null).
36289 * @cfg {Date/String} maxValue
36290 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36291 * valid format (defaults to null).
36295 * @cfg {String} minText
36296 * The error text to display when the date in the cell is before minValue (defaults to
36297 * 'The date in this field must be after {minValue}').
36299 minText : "The date in this field must be equal to or after {0}",
36301 * @cfg {String} maxText
36302 * The error text to display when the date in the cell is after maxValue (defaults to
36303 * 'The date in this field must be before {maxValue}').
36305 maxText : "The date in this field must be equal to or before {0}",
36307 * @cfg {String} invalidText
36308 * The error text to display when the date in the field is invalid (defaults to
36309 * '{value} is not a valid date - it must be in the format {format}').
36311 invalidText : "{0} is not a valid date - it must be in the format {1}",
36313 * @cfg {String} triggerClass
36314 * An additional CSS class used to style the trigger button. The trigger will always get the
36315 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36316 * which displays a calendar icon).
36318 triggerClass : 'x-form-date-trigger',
36322 * @cfg {bool} useIso
36323 * if enabled, then the date field will use a hidden field to store the
36324 * real value as iso formated date. default (false)
36328 * @cfg {String/Object} autoCreate
36329 * A DomHelper element spec, or true for a default element spec (defaults to
36330 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36333 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36336 hiddenField: false,
36338 onRender : function(ct, position)
36340 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36342 this.el.dom.removeAttribute('name');
36343 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36345 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36346 // prevent input submission
36347 this.hiddenName = this.name;
36354 validateValue : function(value)
36356 value = this.formatDate(value);
36357 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36360 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36363 var svalue = value;
36364 value = this.parseDate(value);
36366 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36369 var time = value.getTime();
36370 if(this.minValue && time < this.minValue.getTime()){
36371 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36374 if(this.maxValue && time > this.maxValue.getTime()){
36375 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36378 if(this.disabledDays){
36379 var day = value.getDay();
36380 for(var i = 0; i < this.disabledDays.length; i++) {
36381 if(day === this.disabledDays[i]){
36382 this.markInvalid(this.disabledDaysText);
36387 var fvalue = this.formatDate(value);
36388 if(this.ddMatch && this.ddMatch.test(fvalue)){
36389 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36396 // Provides logic to override the default TriggerField.validateBlur which just returns true
36397 validateBlur : function(){
36398 return !this.menu || !this.menu.isVisible();
36402 * Returns the current date value of the date field.
36403 * @return {Date} The date value
36405 getValue : function(){
36407 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36411 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36412 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36413 * (the default format used is "m/d/y").
36416 //All of these calls set the same date value (May 4, 2006)
36418 //Pass a date object:
36419 var dt = new Date('5/4/06');
36420 dateField.setValue(dt);
36422 //Pass a date string (default format):
36423 dateField.setValue('5/4/06');
36425 //Pass a date string (custom format):
36426 dateField.format = 'Y-m-d';
36427 dateField.setValue('2006-5-4');
36429 * @param {String/Date} date The date or valid date string
36431 setValue : function(date){
36432 if (this.hiddenField) {
36433 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36435 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36439 parseDate : function(value){
36440 if(!value || value instanceof Date){
36443 var v = Date.parseDate(value, this.format);
36444 if(!v && this.altFormats){
36445 if(!this.altFormatsArray){
36446 this.altFormatsArray = this.altFormats.split("|");
36448 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36449 v = Date.parseDate(value, this.altFormatsArray[i]);
36456 formatDate : function(date, fmt){
36457 return (!date || !(date instanceof Date)) ?
36458 date : date.dateFormat(fmt || this.format);
36463 select: function(m, d){
36465 this.fireEvent('select', this, d);
36467 show : function(){ // retain focus styling
36471 this.focus.defer(10, this);
36472 var ml = this.menuListeners;
36473 this.menu.un("select", ml.select, this);
36474 this.menu.un("show", ml.show, this);
36475 this.menu.un("hide", ml.hide, this);
36480 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36481 onTriggerClick : function(){
36485 if(this.menu == null){
36486 this.menu = new Roo.menu.DateMenu();
36488 Roo.apply(this.menu.picker, {
36489 showClear: this.allowBlank,
36490 minDate : this.minValue,
36491 maxDate : this.maxValue,
36492 disabledDatesRE : this.ddMatch,
36493 disabledDatesText : this.disabledDatesText,
36494 disabledDays : this.disabledDays,
36495 disabledDaysText : this.disabledDaysText,
36496 format : this.format,
36497 minText : String.format(this.minText, this.formatDate(this.minValue)),
36498 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36500 this.menu.on(Roo.apply({}, this.menuListeners, {
36503 this.menu.picker.setValue(this.getValue() || new Date());
36504 this.menu.show(this.el, "tl-bl?");
36507 beforeBlur : function(){
36508 var v = this.parseDate(this.getRawValue());
36514 /** @cfg {Boolean} grow @hide */
36515 /** @cfg {Number} growMin @hide */
36516 /** @cfg {Number} growMax @hide */
36523 * Ext JS Library 1.1.1
36524 * Copyright(c) 2006-2007, Ext JS, LLC.
36526 * Originally Released Under LGPL - original licence link has changed is not relivant.
36529 * <script type="text/javascript">
36534 * @class Roo.form.ComboBox
36535 * @extends Roo.form.TriggerField
36536 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36538 * Create a new ComboBox.
36539 * @param {Object} config Configuration options
36541 Roo.form.ComboBox = function(config){
36542 Roo.form.ComboBox.superclass.constructor.call(this, config);
36546 * Fires when the dropdown list is expanded
36547 * @param {Roo.form.ComboBox} combo This combo box
36552 * Fires when the dropdown list is collapsed
36553 * @param {Roo.form.ComboBox} combo This combo box
36557 * @event beforeselect
36558 * Fires before a list item is selected. Return false to cancel the selection.
36559 * @param {Roo.form.ComboBox} combo This combo box
36560 * @param {Roo.data.Record} record The data record returned from the underlying store
36561 * @param {Number} index The index of the selected item in the dropdown list
36563 'beforeselect' : true,
36566 * Fires when a list item is selected
36567 * @param {Roo.form.ComboBox} combo This combo box
36568 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
36569 * @param {Number} index The index of the selected item in the dropdown list
36573 * @event beforequery
36574 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
36575 * The event object passed has these properties:
36576 * @param {Roo.form.ComboBox} combo This combo box
36577 * @param {String} query The query
36578 * @param {Boolean} forceAll true to force "all" query
36579 * @param {Boolean} cancel true to cancel the query
36580 * @param {Object} e The query event object
36582 'beforequery': true
36584 if(this.transform){
36585 this.allowDomMove = false;
36586 var s = Roo.getDom(this.transform);
36587 if(!this.hiddenName){
36588 this.hiddenName = s.name;
36591 this.mode = 'local';
36592 var d = [], opts = s.options;
36593 for(var i = 0, len = opts.length;i < len; i++){
36595 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
36597 this.value = value;
36599 d.push([value, o.text]);
36601 this.store = new Roo.data.SimpleStore({
36603 fields: ['value', 'text'],
36606 this.valueField = 'value';
36607 this.displayField = 'text';
36609 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
36610 if(!this.lazyRender){
36611 this.target = true;
36612 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
36613 s.parentNode.removeChild(s); // remove it
36614 this.render(this.el.parentNode);
36616 s.parentNode.removeChild(s); // remove it
36621 this.store = Roo.factory(this.store, Roo.data);
36624 this.selectedIndex = -1;
36625 if(this.mode == 'local'){
36626 if(config.queryDelay === undefined){
36627 this.queryDelay = 10;
36629 if(config.minChars === undefined){
36635 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
36637 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
36640 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
36641 * rendering into an Roo.Editor, defaults to false)
36644 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
36645 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
36648 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
36651 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
36652 * the dropdown list (defaults to undefined, with no header element)
36656 * @cfg {String/Roo.Template} tpl The template to use to render the output
36660 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
36662 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
36664 listWidth: undefined,
36666 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
36667 * mode = 'remote' or 'text' if mode = 'local')
36669 displayField: undefined,
36671 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
36672 * mode = 'remote' or 'value' if mode = 'local').
36673 * Note: use of a valueField requires the user make a selection
36674 * in order for a value to be mapped.
36676 valueField: undefined,
36678 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
36679 * field's data value (defaults to the underlying DOM element's name)
36681 hiddenName: undefined,
36683 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
36687 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
36689 selectedClass: 'x-combo-selected',
36691 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36692 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
36693 * which displays a downward arrow icon).
36695 triggerClass : 'x-form-arrow-trigger',
36697 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
36701 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
36702 * anchor positions (defaults to 'tl-bl')
36704 listAlign: 'tl-bl?',
36706 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
36710 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
36711 * query specified by the allQuery config option (defaults to 'query')
36713 triggerAction: 'query',
36715 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
36716 * (defaults to 4, does not apply if editable = false)
36720 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
36721 * delay (typeAheadDelay) if it matches a known value (defaults to false)
36725 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
36726 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
36730 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
36731 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
36735 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
36736 * when editable = true (defaults to false)
36738 selectOnFocus:false,
36740 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
36742 queryParam: 'query',
36744 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
36745 * when mode = 'remote' (defaults to 'Loading...')
36747 loadingText: 'Loading...',
36749 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
36753 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
36757 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
36758 * traditional select (defaults to true)
36762 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
36766 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
36770 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
36771 * listWidth has a higher value)
36775 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
36776 * allow the user to set arbitrary text into the field (defaults to false)
36778 forceSelection:false,
36780 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
36781 * if typeAhead = true (defaults to 250)
36783 typeAheadDelay : 250,
36785 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
36786 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
36788 valueNotFoundText : undefined,
36790 * @cfg {bool} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
36792 blockFocus : false,
36795 * @cfg {bool} disableClear Disable showing of clear button.
36797 disableClear : false,
36800 onRender : function(ct, position){
36801 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
36802 if(this.hiddenName){
36803 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
36805 this.hiddenField.value =
36806 this.hiddenValue !== undefined ? this.hiddenValue :
36807 this.value !== undefined ? this.value : '';
36809 // prevent input submission
36810 this.el.dom.removeAttribute('name');
36813 this.el.dom.setAttribute('autocomplete', 'off');
36816 var cls = 'x-combo-list';
36818 this.list = new Roo.Layer({
36819 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
36822 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
36823 this.list.setWidth(lw);
36824 this.list.swallowEvent('mousewheel');
36825 this.assetHeight = 0;
36828 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
36829 this.assetHeight += this.header.getHeight();
36832 this.innerList = this.list.createChild({cls:cls+'-inner'});
36833 this.innerList.on('mouseover', this.onViewOver, this);
36834 this.innerList.on('mousemove', this.onViewMove, this);
36835 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
36837 if(this.allowBlank && !this.pageSize && !this.disableClear){
36838 this.footer = this.list.createChild({cls:cls+'-ft'});
36839 this.pageTb = new Roo.Toolbar(this.footer);
36843 this.footer = this.list.createChild({cls:cls+'-ft'});
36844 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
36845 {pageSize: this.pageSize});
36849 if (this.pageTb && this.allowBlank && !this.disableClear) {
36851 this.pageTb.add(new Roo.Toolbar.Fill(), {
36852 cls: 'x-btn-icon x-btn-clear',
36854 handler: function()
36857 _this.clearValue();
36858 _this.onSelect(false, -1);
36863 this.assetHeight += this.footer.getHeight();
36868 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
36871 this.view = new Roo.View(this.innerList, this.tpl, {
36872 singleSelect:true, store: this.store, selectedClass: this.selectedClass
36875 this.view.on('click', this.onViewClick, this);
36877 this.store.on('beforeload', this.onBeforeLoad, this);
36878 this.store.on('load', this.onLoad, this);
36879 this.store.on('loadexception', this.collapse, this);
36881 if(this.resizable){
36882 this.resizer = new Roo.Resizable(this.list, {
36883 pinned:true, handles:'se'
36885 this.resizer.on('resize', function(r, w, h){
36886 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
36887 this.listWidth = w;
36888 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
36889 this.restrictHeight();
36891 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
36893 if(!this.editable){
36894 this.editable = true;
36895 this.setEditable(false);
36900 initEvents : function(){
36901 Roo.form.ComboBox.superclass.initEvents.call(this);
36903 this.keyNav = new Roo.KeyNav(this.el, {
36904 "up" : function(e){
36905 this.inKeyMode = true;
36909 "down" : function(e){
36910 if(!this.isExpanded()){
36911 this.onTriggerClick();
36913 this.inKeyMode = true;
36918 "enter" : function(e){
36919 this.onViewClick();
36923 "esc" : function(e){
36927 "tab" : function(e){
36928 this.onViewClick(false);
36934 doRelay : function(foo, bar, hname){
36935 if(hname == 'down' || this.scope.isExpanded()){
36936 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
36943 this.queryDelay = Math.max(this.queryDelay || 10,
36944 this.mode == 'local' ? 10 : 250);
36945 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
36946 if(this.typeAhead){
36947 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
36949 if(this.editable !== false){
36950 this.el.on("keyup", this.onKeyUp, this);
36952 if(this.forceSelection){
36953 this.on('blur', this.doForce, this);
36957 onDestroy : function(){
36959 this.view.setStore(null);
36960 this.view.el.removeAllListeners();
36961 this.view.el.remove();
36962 this.view.purgeListeners();
36965 this.list.destroy();
36968 this.store.un('beforeload', this.onBeforeLoad, this);
36969 this.store.un('load', this.onLoad, this);
36970 this.store.un('loadexception', this.collapse, this);
36972 Roo.form.ComboBox.superclass.onDestroy.call(this);
36976 fireKey : function(e){
36977 if(e.isNavKeyPress() && !this.list.isVisible()){
36978 this.fireEvent("specialkey", this, e);
36983 onResize: function(w, h){
36984 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
36985 if(this.list && this.listWidth === undefined){
36986 var lw = Math.max(w, this.minListWidth);
36987 this.list.setWidth(lw);
36988 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
36993 * Allow or prevent the user from directly editing the field text. If false is passed,
36994 * the user will only be able to select from the items defined in the dropdown list. This method
36995 * is the runtime equivalent of setting the 'editable' config option at config time.
36996 * @param {Boolean} value True to allow the user to directly edit the field text
36998 setEditable : function(value){
36999 if(value == this.editable){
37002 this.editable = value;
37004 this.el.dom.setAttribute('readOnly', true);
37005 this.el.on('mousedown', this.onTriggerClick, this);
37006 this.el.addClass('x-combo-noedit');
37008 this.el.dom.setAttribute('readOnly', false);
37009 this.el.un('mousedown', this.onTriggerClick, this);
37010 this.el.removeClass('x-combo-noedit');
37015 onBeforeLoad : function(){
37016 if(!this.hasFocus){
37019 this.innerList.update(this.loadingText ?
37020 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37021 this.restrictHeight();
37022 this.selectedIndex = -1;
37026 onLoad : function(){
37027 if(!this.hasFocus){
37030 if(this.store.getCount() > 0){
37032 this.restrictHeight();
37033 if(this.lastQuery == this.allQuery){
37035 this.el.dom.select();
37037 if(!this.selectByValue(this.value, true)){
37038 this.select(0, true);
37042 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37043 this.taTask.delay(this.typeAheadDelay);
37047 this.onEmptyResults();
37053 onTypeAhead : function(){
37054 if(this.store.getCount() > 0){
37055 var r = this.store.getAt(0);
37056 var newValue = r.data[this.displayField];
37057 var len = newValue.length;
37058 var selStart = this.getRawValue().length;
37059 if(selStart != len){
37060 this.setRawValue(newValue);
37061 this.selectText(selStart, newValue.length);
37067 onSelect : function(record, index){
37068 if(this.fireEvent('beforeselect', this, record, index) !== false){
37069 this.setFromData(index > -1 ? record.data : false);
37071 this.fireEvent('select', this, record, index);
37076 * Returns the currently selected field value or empty string if no value is set.
37077 * @return {String} value The selected value
37079 getValue : function(){
37080 if(this.valueField){
37081 return typeof this.value != 'undefined' ? this.value : '';
37083 return Roo.form.ComboBox.superclass.getValue.call(this);
37088 * Clears any text/value currently set in the field
37090 clearValue : function(){
37091 if(this.hiddenField){
37092 this.hiddenField.value = '';
37095 this.setRawValue('');
37096 this.lastSelectionText = '';
37097 this.applyEmptyText();
37101 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37102 * will be displayed in the field. If the value does not match the data value of an existing item,
37103 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37104 * Otherwise the field will be blank (although the value will still be set).
37105 * @param {String} value The value to match
37107 setValue : function(v){
37109 if(this.valueField){
37110 var r = this.findRecord(this.valueField, v);
37112 text = r.data[this.displayField];
37113 }else if(this.valueNotFoundText !== undefined){
37114 text = this.valueNotFoundText;
37117 this.lastSelectionText = text;
37118 if(this.hiddenField){
37119 this.hiddenField.value = v;
37121 Roo.form.ComboBox.superclass.setValue.call(this, text);
37125 * @property {Object} the last set data for the element
37130 * Sets the value of the field based on a object which is related to the record format for the store.
37131 * @param {Object} value the value to set as. or false on reset?
37133 setFromData : function(o){
37134 var dv = ''; // display value
37135 var vv = ''; // value value..
37137 if (this.displayField) {
37138 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37140 // this is an error condition!!!
37141 console.log('no value field set for '+ this.name);
37144 if(this.valueField){
37145 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37147 if(this.hiddenField){
37148 this.hiddenField.value = vv;
37150 this.lastSelectionText = dv;
37151 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37155 // no hidden field.. - we store the value in 'value', but still display
37156 // display field!!!!
37157 this.lastSelectionText = dv;
37158 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37164 reset : function(){
37165 // overridden so that last data is reset..
37166 this.setValue(this.originalValue);
37167 this.clearInvalid();
37168 this.lastData = false;
37171 findRecord : function(prop, value){
37173 if(this.store.getCount() > 0){
37174 this.store.each(function(r){
37175 if(r.data[prop] == value){
37185 onViewMove : function(e, t){
37186 this.inKeyMode = false;
37190 onViewOver : function(e, t){
37191 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37194 var item = this.view.findItemFromChild(t);
37196 var index = this.view.indexOf(item);
37197 this.select(index, false);
37202 onViewClick : function(doFocus){
37203 var index = this.view.getSelectedIndexes()[0];
37204 var r = this.store.getAt(index);
37206 this.onSelect(r, index);
37208 if(doFocus !== false && !this.blockFocus){
37214 restrictHeight : function(){
37215 this.innerList.dom.style.height = '';
37216 var inner = this.innerList.dom;
37217 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37218 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37219 this.list.beginUpdate();
37220 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37221 this.list.alignTo(this.el, this.listAlign);
37222 this.list.endUpdate();
37226 onEmptyResults : function(){
37231 * Returns true if the dropdown list is expanded, else false.
37233 isExpanded : function(){
37234 return this.list.isVisible();
37238 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37239 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37240 * @param {String} value The data value of the item to select
37241 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37242 * selected item if it is not currently in view (defaults to true)
37243 * @return {Boolean} True if the value matched an item in the list, else false
37245 selectByValue : function(v, scrollIntoView){
37246 if(v !== undefined && v !== null){
37247 var r = this.findRecord(this.valueField || this.displayField, v);
37249 this.select(this.store.indexOf(r), scrollIntoView);
37257 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37258 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37259 * @param {Number} index The zero-based index of the list item to select
37260 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37261 * selected item if it is not currently in view (defaults to true)
37263 select : function(index, scrollIntoView){
37264 this.selectedIndex = index;
37265 this.view.select(index);
37266 if(scrollIntoView !== false){
37267 var el = this.view.getNode(index);
37269 this.innerList.scrollChildIntoView(el, false);
37275 selectNext : function(){
37276 var ct = this.store.getCount();
37278 if(this.selectedIndex == -1){
37280 }else if(this.selectedIndex < ct-1){
37281 this.select(this.selectedIndex+1);
37287 selectPrev : function(){
37288 var ct = this.store.getCount();
37290 if(this.selectedIndex == -1){
37292 }else if(this.selectedIndex != 0){
37293 this.select(this.selectedIndex-1);
37299 onKeyUp : function(e){
37300 if(this.editable !== false && !e.isSpecialKey()){
37301 this.lastKey = e.getKey();
37302 this.dqTask.delay(this.queryDelay);
37307 validateBlur : function(){
37308 return !this.list || !this.list.isVisible();
37312 initQuery : function(){
37313 this.doQuery(this.getRawValue());
37317 doForce : function(){
37318 if(this.el.dom.value.length > 0){
37319 this.el.dom.value =
37320 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37321 this.applyEmptyText();
37326 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37327 * query allowing the query action to be canceled if needed.
37328 * @param {String} query The SQL query to execute
37329 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37330 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37331 * saved in the current store (defaults to false)
37333 doQuery : function(q, forceAll){
37334 if(q === undefined || q === null){
37339 forceAll: forceAll,
37343 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37347 forceAll = qe.forceAll;
37348 if(forceAll === true || (q.length >= this.minChars)){
37349 if(this.lastQuery != q){
37350 this.lastQuery = q;
37351 if(this.mode == 'local'){
37352 this.selectedIndex = -1;
37354 this.store.clearFilter();
37356 this.store.filter(this.displayField, q);
37360 this.store.baseParams[this.queryParam] = q;
37362 params: this.getParams(q)
37367 this.selectedIndex = -1;
37374 getParams : function(q){
37376 //p[this.queryParam] = q;
37379 p.limit = this.pageSize;
37385 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37387 collapse : function(){
37388 if(!this.isExpanded()){
37392 Roo.get(document).un('mousedown', this.collapseIf, this);
37393 Roo.get(document).un('mousewheel', this.collapseIf, this);
37394 this.fireEvent('collapse', this);
37398 collapseIf : function(e){
37399 if(!e.within(this.wrap) && !e.within(this.list)){
37405 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37407 expand : function(){
37408 if(this.isExpanded() || !this.hasFocus){
37411 this.list.alignTo(this.el, this.listAlign);
37413 Roo.get(document).on('mousedown', this.collapseIf, this);
37414 Roo.get(document).on('mousewheel', this.collapseIf, this);
37415 this.fireEvent('expand', this);
37419 // Implements the default empty TriggerField.onTriggerClick function
37420 onTriggerClick : function(){
37424 if(this.isExpanded()){
37426 if (!this.blockFocus) {
37431 this.hasFocus = true;
37432 if(this.triggerAction == 'all') {
37433 this.doQuery(this.allQuery, true);
37435 this.doQuery(this.getRawValue());
37437 if (!this.blockFocus) {
37444 * @cfg {Boolean} grow
37448 * @cfg {Number} growMin
37452 * @cfg {Number} growMax
37461 * Ext JS Library 1.1.1
37462 * Copyright(c) 2006-2007, Ext JS, LLC.
37464 * Originally Released Under LGPL - original licence link has changed is not relivant.
37467 * <script type="text/javascript">
37470 * @class Roo.form.Checkbox
37471 * @extends Roo.form.Field
37472 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
37474 * Creates a new Checkbox
37475 * @param {Object} config Configuration options
37477 Roo.form.Checkbox = function(config){
37478 Roo.form.Checkbox.superclass.constructor.call(this, config);
37482 * Fires when the checkbox is checked or unchecked.
37483 * @param {Roo.form.Checkbox} this This checkbox
37484 * @param {Boolean} checked The new checked value
37490 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
37492 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
37494 focusClass : undefined,
37496 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
37498 fieldClass: "x-form-field",
37500 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
37504 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37505 * {tag: "input", type: "checkbox", autocomplete: "off"})
37507 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
37509 * @cfg {String} boxLabel The text that appears beside the checkbox
37513 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
37517 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
37519 valueOff: '0', // value when not checked..
37521 actionMode : 'viewEl',
37524 itemCls : 'x-menu-check-item x-form-item',
37525 groupClass : 'x-menu-group-item',
37526 inputType : 'hidden',
37529 inSetChecked: false, // check that we are not calling self...
37531 inputElement: false, // real input element?
37532 basedOn: false, // ????
37534 isFormField: true, // not sure where this is needed!!!!
37536 onResize : function(){
37537 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
37538 if(!this.boxLabel){
37539 this.el.alignTo(this.wrap, 'c-c');
37543 initEvents : function(){
37544 Roo.form.Checkbox.superclass.initEvents.call(this);
37545 this.el.on("click", this.onClick, this);
37546 this.el.on("change", this.onClick, this);
37550 getResizeEl : function(){
37554 getPositionEl : function(){
37559 onRender : function(ct, position){
37560 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
37562 if(this.inputValue !== undefined){
37563 this.el.dom.value = this.inputValue;
37566 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
37567 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
37568 var viewEl = this.wrap.createChild({
37569 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
37570 this.viewEl = viewEl;
37571 this.wrap.on('click', this.onClick, this);
37573 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
37574 this.el.on('propertychange', this.setFromHidden, this); //ie
37579 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
37580 // viewEl.on('click', this.onClick, this);
37582 //if(this.checked){
37583 this.setChecked(this.checked);
37585 //this.checked = this.el.dom;
37591 initValue : Roo.emptyFn,
37594 * Returns the checked state of the checkbox.
37595 * @return {Boolean} True if checked, else false
37597 getValue : function(){
37599 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
37601 return this.valueOff;
37606 onClick : function(){
37607 this.setChecked(!this.checked);
37609 //if(this.el.dom.checked != this.checked){
37610 // this.setValue(this.el.dom.checked);
37615 * Sets the checked state of the checkbox.
37616 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
37618 setValue : function(v,suppressEvent){
37619 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
37620 //if(this.el && this.el.dom){
37621 // this.el.dom.checked = this.checked;
37622 // this.el.dom.defaultChecked = this.checked;
37624 this.setChecked(v === this.inputValue);
37625 //this.fireEvent("check", this, this.checked);
37628 setChecked : function(state,suppressEvent)
37630 if (this.inSetChecked) {
37631 this.checked = state;
37637 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
37639 this.checked = state;
37640 if(suppressEvent !== true){
37641 this.fireEvent('checkchange', this, state);
37643 this.inSetChecked = true;
37644 this.el.dom.value = state ? this.inputValue : this.valueOff;
37645 this.inSetChecked = false;
37648 // handle setting of hidden value by some other method!!?!?
37649 setFromHidden: function()
37654 //console.log("SET FROM HIDDEN");
37655 //alert('setFrom hidden');
37656 this.setValue(this.el.dom.value);
37659 onDestroy : function()
37662 Roo.get(this.viewEl).remove();
37665 Roo.form.Checkbox.superclass.onDestroy.call(this);
37670 * Ext JS Library 1.1.1
37671 * Copyright(c) 2006-2007, Ext JS, LLC.
37673 * Originally Released Under LGPL - original licence link has changed is not relivant.
37676 * <script type="text/javascript">
37680 * @class Roo.form.Radio
37681 * @extends Roo.form.Checkbox
37682 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
37683 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
37685 * Creates a new Radio
37686 * @param {Object} config Configuration options
37688 Roo.form.Radio = function(){
37689 Roo.form.Radio.superclass.constructor.apply(this, arguments);
37691 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
37692 inputType: 'radio',
37695 * If this radio is part of a group, it will return the selected value
37698 getGroupValue : function(){
37699 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
37701 });//<script type="text/javascript">
37704 * Ext JS Library 1.1.1
37705 * Copyright(c) 2006-2007, Ext JS, LLC.
37706 * licensing@extjs.com
37708 * http://www.extjs.com/license
37714 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
37715 * - IE ? - no idea how much works there.
37723 * @class Ext.form.HtmlEditor
37724 * @extends Ext.form.Field
37725 * Provides a lightweight HTML Editor component.
37726 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
37728 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
37729 * supported by this editor.</b><br/><br/>
37730 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
37731 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
37733 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
37735 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
37739 * @cfg {String} createLinkText The default text for the create link prompt
37741 createLinkText : 'Please enter the URL for the link:',
37743 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
37745 defaultLinkValue : 'http:/'+'/',
37751 // private properties
37752 validationEvent : false,
37754 initialized : false,
37756 sourceEditMode : false,
37757 onFocus : Roo.emptyFn,
37759 hideMode:'offsets',
37760 defaultAutoCreate : {
37762 style:"width:500px;height:300px;",
37763 autocomplete: "off"
37767 initComponent : function(){
37770 * @event initialize
37771 * Fires when the editor is fully initialized (including the iframe)
37772 * @param {HtmlEditor} this
37777 * Fires when the editor is first receives the focus. Any insertion must wait
37778 * until after this event.
37779 * @param {HtmlEditor} this
37783 * @event beforesync
37784 * Fires before the textarea is updated with content from the editor iframe. Return false
37785 * to cancel the sync.
37786 * @param {HtmlEditor} this
37787 * @param {String} html
37791 * @event beforepush
37792 * Fires before the iframe editor is updated with content from the textarea. Return false
37793 * to cancel the push.
37794 * @param {HtmlEditor} this
37795 * @param {String} html
37800 * Fires when the textarea is updated with content from the editor iframe.
37801 * @param {HtmlEditor} this
37802 * @param {String} html
37807 * Fires when the iframe editor is updated with content from the textarea.
37808 * @param {HtmlEditor} this
37809 * @param {String} html
37813 * @event editmodechange
37814 * Fires when the editor switches edit modes
37815 * @param {HtmlEditor} this
37816 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
37818 editmodechange: true,
37820 * @event editorevent
37821 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
37822 * @param {HtmlEditor} this
37829 * Protected method that will not generally be called directly. It
37830 * is called when the editor creates its toolbar. Override this method if you need to
37831 * add custom toolbar buttons.
37832 * @param {HtmlEditor} editor
37834 createToolbar : function(editor){
37835 if (!editor.toolbars || !editor.toolbars.length) {
37836 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
37839 for (var i =0 ; i < editor.toolbars.length;i++) {
37840 editor.toolbars[i].init(editor);
37847 * Protected method that will not generally be called directly. It
37848 * is called when the editor initializes the iframe with HTML contents. Override this method if you
37849 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
37851 getDocMarkup : function(){
37852 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
37856 onRender : function(ct, position){
37857 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
37858 this.el.dom.style.border = '0 none';
37859 this.el.dom.setAttribute('tabIndex', -1);
37860 this.el.addClass('x-hidden');
37861 if(Roo.isIE){ // fix IE 1px bogus margin
37862 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
37864 this.wrap = this.el.wrap({
37865 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
37868 this.frameId = Roo.id();
37869 this.createToolbar(this);
37876 var iframe = this.wrap.createChild({
37879 name: this.frameId,
37880 frameBorder : 'no',
37881 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
37884 // console.log(iframe);
37885 //this.wrap.dom.appendChild(iframe);
37887 this.iframe = iframe.dom;
37889 this.assignDocWin();
37891 this.doc.designMode = 'on';
37894 this.doc.write(this.getDocMarkup());
37898 var task = { // must defer to wait for browser to be ready
37900 //console.log("run task?" + this.doc.readyState);
37901 this.assignDocWin();
37902 if(this.doc.body || this.doc.readyState == 'complete'){
37906 this.doc.designMode="on";
37910 Roo.TaskMgr.stop(task);
37911 this.initEditor.defer(10, this);
37918 Roo.TaskMgr.start(task);
37921 this.setSize(this.el.getSize());
37926 onResize : function(w, h){
37927 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
37928 if(this.el && this.iframe){
37929 if(typeof w == 'number'){
37930 var aw = w - this.wrap.getFrameWidth('lr');
37931 this.el.setWidth(this.adjustWidth('textarea', aw));
37932 this.iframe.style.width = aw + 'px';
37934 if(typeof h == 'number'){
37936 for (var i =0; i < this.toolbars.length;i++) {
37937 // fixme - ask toolbars for heights?
37938 tbh += this.toolbars[i].tb.el.getHeight();
37944 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
37945 this.el.setHeight(this.adjustWidth('textarea', ah));
37946 this.iframe.style.height = ah + 'px';
37948 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
37955 * Toggles the editor between standard and source edit mode.
37956 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
37958 toggleSourceEdit : function(sourceEditMode){
37960 this.sourceEditMode = sourceEditMode === true;
37962 if(this.sourceEditMode){
37965 this.iframe.className = 'x-hidden';
37966 this.el.removeClass('x-hidden');
37967 this.el.dom.removeAttribute('tabIndex');
37972 this.iframe.className = '';
37973 this.el.addClass('x-hidden');
37974 this.el.dom.setAttribute('tabIndex', -1);
37977 this.setSize(this.wrap.getSize());
37978 this.fireEvent('editmodechange', this, this.sourceEditMode);
37981 // private used internally
37982 createLink : function(){
37983 var url = prompt(this.createLinkText, this.defaultLinkValue);
37984 if(url && url != 'http:/'+'/'){
37985 this.relayCmd('createlink', url);
37989 // private (for BoxComponent)
37990 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37992 // private (for BoxComponent)
37993 getResizeEl : function(){
37997 // private (for BoxComponent)
37998 getPositionEl : function(){
38003 initEvents : function(){
38004 this.originalValue = this.getValue();
38008 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38011 markInvalid : Roo.emptyFn,
38013 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38016 clearInvalid : Roo.emptyFn,
38018 setValue : function(v){
38019 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38024 * Protected method that will not generally be called directly. If you need/want
38025 * custom HTML cleanup, this is the method you should override.
38026 * @param {String} html The HTML to be cleaned
38027 * return {String} The cleaned HTML
38029 cleanHtml : function(html){
38030 html = String(html);
38031 if(html.length > 5){
38032 if(Roo.isSafari){ // strip safari nonsense
38033 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38036 if(html == ' '){
38043 * Protected method that will not generally be called directly. Syncs the contents
38044 * of the editor iframe with the textarea.
38046 syncValue : function(){
38047 if(this.initialized){
38048 var bd = (this.doc.body || this.doc.documentElement);
38049 var html = bd.innerHTML;
38051 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38052 var m = bs.match(/text-align:(.*?);/i);
38054 html = '<div style="'+m[0]+'">' + html + '</div>';
38057 html = this.cleanHtml(html);
38058 if(this.fireEvent('beforesync', this, html) !== false){
38059 this.el.dom.value = html;
38060 this.fireEvent('sync', this, html);
38066 * Protected method that will not generally be called directly. Pushes the value of the textarea
38067 * into the iframe editor.
38069 pushValue : function(){
38070 if(this.initialized){
38071 var v = this.el.dom.value;
38075 if(this.fireEvent('beforepush', this, v) !== false){
38076 (this.doc.body || this.doc.documentElement).innerHTML = v;
38077 this.fireEvent('push', this, v);
38083 deferFocus : function(){
38084 this.focus.defer(10, this);
38088 focus : function(){
38089 if(this.win && !this.sourceEditMode){
38096 assignDocWin: function()
38098 var iframe = this.iframe;
38101 this.doc = iframe.contentWindow.document;
38102 this.win = iframe.contentWindow;
38104 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38105 this.win = Roo.get(this.frameId).dom.contentWindow;
38110 initEditor : function(){
38111 //console.log("INIT EDITOR");
38112 this.assignDocWin();
38116 this.doc.designMode="on";
38118 this.doc.write(this.getDocMarkup());
38121 var dbody = (this.doc.body || this.doc.documentElement);
38122 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38123 // this copies styles from the containing element into thsi one..
38124 // not sure why we need all of this..
38125 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38126 ss['background-attachment'] = 'fixed'; // w3c
38127 dbody.bgProperties = 'fixed'; // ie
38128 Roo.DomHelper.applyStyles(dbody, ss);
38129 Roo.EventManager.on(this.doc, {
38130 'mousedown': this.onEditorEvent,
38131 'dblclick': this.onEditorEvent,
38132 'click': this.onEditorEvent,
38133 'keyup': this.onEditorEvent,
38138 Roo.EventManager.on(this.doc, 'keypress', this.applyCommand, this);
38140 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38141 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38143 this.initialized = true;
38145 this.fireEvent('initialize', this);
38150 onDestroy : function(){
38156 for (var i =0; i < this.toolbars.length;i++) {
38157 // fixme - ask toolbars for heights?
38158 this.toolbars[i].onDestroy();
38161 this.wrap.dom.innerHTML = '';
38162 this.wrap.remove();
38167 onFirstFocus : function(){
38169 this.assignDocWin();
38172 this.activated = true;
38173 for (var i =0; i < this.toolbars.length;i++) {
38174 this.toolbars[i].onFirstFocus();
38177 if(Roo.isGecko){ // prevent silly gecko errors
38179 var s = this.win.getSelection();
38180 if(!s.focusNode || s.focusNode.nodeType != 3){
38181 var r = s.getRangeAt(0);
38182 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38187 this.execCmd('useCSS', true);
38188 this.execCmd('styleWithCSS', false);
38191 this.fireEvent('activate', this);
38195 adjustFont: function(btn){
38196 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38197 //if(Roo.isSafari){ // safari
38200 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38201 if(Roo.isSafari){ // safari
38202 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38203 v = (v < 10) ? 10 : v;
38204 v = (v > 48) ? 48 : v;
38205 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38210 v = Math.max(1, v+adjust);
38212 this.execCmd('FontSize', v );
38215 onEditorEvent : function(e){
38216 this.fireEvent('editorevent', this, e);
38217 // this.updateToolbar();
38221 insertTag : function(tg)
38223 // could be a bit smarter... -> wrap the current selected tRoo..
38225 this.execCmd("formatblock", tg);
38229 insertText : function(txt)
38233 range = this.createRange();
38234 range.deleteContents();
38235 //alert(Sender.getAttribute('label'));
38237 range.insertNode(this.doc.createTextNode(txt));
38241 relayBtnCmd : function(btn){
38242 this.relayCmd(btn.cmd);
38246 * Executes a Midas editor command on the editor document and performs necessary focus and
38247 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38248 * @param {String} cmd The Midas command
38249 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38251 relayCmd : function(cmd, value){
38253 this.execCmd(cmd, value);
38254 this.fireEvent('editorevent', this);
38255 //this.updateToolbar();
38260 * Executes a Midas editor command directly on the editor document.
38261 * For visual commands, you should use {@link #relayCmd} instead.
38262 * <b>This should only be called after the editor is initialized.</b>
38263 * @param {String} cmd The Midas command
38264 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38266 execCmd : function(cmd, value){
38267 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38272 applyCommand : function(e){
38274 var c = e.getCharCode(), cmd;
38276 c = String.fromCharCode(c);
38292 e.preventDefault();
38299 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38301 * @param {String} text
38303 insertAtCursor : function(text){
38304 if(!this.activated){
38309 var r = this.doc.selection.createRange();
38316 }else if(Roo.isGecko || Roo.isOpera){
38318 this.execCmd('InsertHTML', text);
38320 }else if(Roo.isSafari){
38321 this.execCmd('InsertText', text);
38327 fixKeys : function(){ // load time branching for fastest keydown performance
38329 return function(e){
38330 var k = e.getKey(), r;
38333 r = this.doc.selection.createRange();
38336 r.pasteHTML('    ');
38339 }else if(k == e.ENTER){
38340 r = this.doc.selection.createRange();
38342 var target = r.parentElement();
38343 if(!target || target.tagName.toLowerCase() != 'li'){
38345 r.pasteHTML('<br />');
38352 }else if(Roo.isOpera){
38353 return function(e){
38354 var k = e.getKey();
38358 this.execCmd('InsertHTML','    ');
38362 }else if(Roo.isSafari){
38363 return function(e){
38364 var k = e.getKey();
38367 this.execCmd('InsertText','\t');
38374 getAllAncestors: function()
38376 var p = this.getSelectedNode();
38379 a.push(p); // push blank onto stack..
38380 p = this.getParentElement();
38384 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38388 a.push(this.doc.body);
38392 lastSelNode : false,
38395 getSelection : function()
38397 this.assignDocWin();
38398 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38401 getSelectedNode: function()
38403 // this may only work on Gecko!!!
38405 // should we cache this!!!!
38410 var range = this.createRange(this.getSelection());
38413 var parent = range.parentElement();
38415 var testRange = range.duplicate();
38416 testRange.moveToElementText(parent);
38417 if (testRange.inRange(range)) {
38420 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
38423 parent = parent.parentElement;
38429 var ar = range.endContainer.childNodes;
38431 ar = range.commonAncestorContainer.childNodes;
38432 //alert(ar.length);
38435 var other_nodes = [];
38436 var has_other_nodes = false;
38437 for (var i=0;i<ar.length;i++) {
38438 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
38441 // fullly contained node.
38443 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
38448 // probably selected..
38449 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
38450 other_nodes.push(ar[i]);
38453 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
38458 has_other_nodes = true;
38460 if (!nodes.length && other_nodes.length) {
38461 nodes= other_nodes;
38463 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
38469 createRange: function(sel)
38471 // this has strange effects when using with
38472 // top toolbar - not sure if it's a great idea.
38473 //this.editor.contentWindow.focus();
38474 if (typeof sel != "undefined") {
38476 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
38478 return this.doc.createRange();
38481 return this.doc.createRange();
38484 getParentElement: function()
38487 this.assignDocWin();
38488 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
38490 var range = this.createRange(sel);
38493 var p = range.commonAncestorContainer;
38494 while (p.nodeType == 3) { // text node
38506 // BC Hacks - cause I cant work out what i was trying to do..
38507 rangeIntersectsNode : function(range, node)
38509 var nodeRange = node.ownerDocument.createRange();
38511 nodeRange.selectNode(node);
38514 nodeRange.selectNodeContents(node);
38517 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
38518 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
38520 rangeCompareNode : function(range, node) {
38521 var nodeRange = node.ownerDocument.createRange();
38523 nodeRange.selectNode(node);
38525 nodeRange.selectNodeContents(node);
38527 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
38528 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
38530 if (nodeIsBefore && !nodeIsAfter)
38532 if (!nodeIsBefore && nodeIsAfter)
38534 if (nodeIsBefore && nodeIsAfter)
38542 // hide stuff that is not compatible
38556 * @event specialkey
38560 * @cfg {String} fieldClass @hide
38563 * @cfg {String} focusClass @hide
38566 * @cfg {String} autoCreate @hide
38569 * @cfg {String} inputType @hide
38572 * @cfg {String} invalidClass @hide
38575 * @cfg {String} invalidText @hide
38578 * @cfg {String} msgFx @hide
38581 * @cfg {String} validateOnBlur @hide
38583 });// <script type="text/javascript">
38586 * Ext JS Library 1.1.1
38587 * Copyright(c) 2006-2007, Ext JS, LLC.
38593 * @class Roo.form.HtmlEditorToolbar1
38598 new Roo.form.HtmlEditor({
38601 new Roo.form.HtmlEditorToolbar1({
38602 disable : { fonts: 1 , format: 1, ..., ... , ...],
38608 * @cfg {Object} disable List of elements to disable..
38609 * @cfg {Array} btns List of additional buttons.
38613 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
38616 Roo.form.HtmlEditor.ToolbarStandard = function(config)
38619 Roo.apply(this, config);
38620 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
38621 // dont call parent... till later.
38624 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
38632 * @cfg {Object} disable List of toolbar elements to disable
38637 * @cfg {Array} fontFamilies An array of available font families
38655 // "á" , ?? a acute?
38660 "°" // , // degrees
38662 // "é" , // e ecute
38663 // "ú" , // u ecute?
38666 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
38667 "input:submit", "input:button", "select", "textarea", "label" ],
38670 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
38672 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
38675 * @cfg {String} defaultFont default font to use.
38677 defaultFont: 'tahoma',
38679 fontSelect : false,
38682 formatCombo : false,
38684 init : function(editor)
38686 this.editor = editor;
38689 var fid = editor.frameId;
38691 function btn(id, toggle, handler){
38692 var xid = fid + '-'+ id ;
38696 cls : 'x-btn-icon x-edit-'+id,
38697 enableToggle:toggle !== false,
38698 scope: editor, // was editor...
38699 handler:handler||editor.relayBtnCmd,
38700 clickEvent:'mousedown',
38701 tooltip: etb.buttonTips[id] || undefined, ///tips ???
38708 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
38710 // stop form submits
38711 tb.el.on('click', function(e){
38712 e.preventDefault(); // what does this do?
38715 if(!this.disable.font && !Roo.isSafari){
38716 /* why no safari for fonts
38717 editor.fontSelect = tb.el.createChild({
38720 cls:'x-font-select',
38721 html: editor.createFontOptions()
38723 editor.fontSelect.on('change', function(){
38724 var font = editor.fontSelect.dom.value;
38725 editor.relayCmd('fontname', font);
38726 editor.deferFocus();
38729 editor.fontSelect.dom,
38734 if(!this.disable.formats){
38735 this.formatCombo = new Roo.form.ComboBox({
38736 store: new Roo.data.SimpleStore({
38739 data : this.formats // from states.js
38742 //autoCreate : {tag: "div", size: "20"},
38743 displayField:'tag',
38747 triggerAction: 'all',
38748 emptyText:'Add tag',
38749 selectOnFocus:true,
38752 'select': function(c, r, i) {
38753 editor.insertTag(r.get('tag'));
38759 tb.addField(this.formatCombo);
38763 if(!this.disable.format){
38770 if(!this.disable.fontSize){
38775 btn('increasefontsize', false, editor.adjustFont),
38776 btn('decreasefontsize', false, editor.adjustFont)
38781 if(this.disable.colors){
38784 id:editor.frameId +'-forecolor',
38785 cls:'x-btn-icon x-edit-forecolor',
38786 clickEvent:'mousedown',
38787 tooltip: this.buttonTips['forecolor'] || undefined,
38789 menu : new Roo.menu.ColorMenu({
38790 allowReselect: true,
38791 focus: Roo.emptyFn,
38794 selectHandler: function(cp, color){
38795 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
38796 editor.deferFocus();
38799 clickEvent:'mousedown'
38802 id:editor.frameId +'backcolor',
38803 cls:'x-btn-icon x-edit-backcolor',
38804 clickEvent:'mousedown',
38805 tooltip: this.buttonTips['backcolor'] || undefined,
38807 menu : new Roo.menu.ColorMenu({
38808 focus: Roo.emptyFn,
38811 allowReselect: true,
38812 selectHandler: function(cp, color){
38814 editor.execCmd('useCSS', false);
38815 editor.execCmd('hilitecolor', color);
38816 editor.execCmd('useCSS', true);
38817 editor.deferFocus();
38819 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
38820 Roo.isSafari || Roo.isIE ? '#'+color : color);
38821 editor.deferFocus();
38825 clickEvent:'mousedown'
38830 // now add all the items...
38833 if(!this.disable.alignments){
38836 btn('justifyleft'),
38837 btn('justifycenter'),
38838 btn('justifyright')
38842 //if(!Roo.isSafari){
38843 if(!this.disable.links){
38846 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
38850 if(!this.disable.lists){
38853 btn('insertorderedlist'),
38854 btn('insertunorderedlist')
38857 if(!this.disable.sourceEdit){
38860 btn('sourceedit', true, function(btn){
38861 this.toggleSourceEdit(btn.pressed);
38868 // special menu.. - needs to be tidied up..
38869 if (!this.disable.special) {
38872 cls: 'x-edit-none',
38877 for (var i =0; i < this.specialChars.length; i++) {
38878 smenu.menu.items.push({
38880 text: this.specialChars[i],
38881 handler: function(a,b) {
38882 editor.insertAtCursor(String.fromCharCode(a.text.replace('&#','').replace(';', '')));
38894 for(var i =0; i< this.btns.length;i++) {
38895 var b = this.btns[i];
38896 b.cls = 'x-edit-none';
38905 // disable everything...
38907 this.tb.items.each(function(item){
38908 if(item.id != editor.frameId+ '-sourceedit'){
38912 this.rendered = true;
38914 // the all the btns;
38915 editor.on('editorevent', this.updateToolbar, this);
38916 // other toolbars need to implement this..
38917 //editor.on('editmodechange', this.updateToolbar, this);
38923 * Protected method that will not generally be called directly. It triggers
38924 * a toolbar update by reading the markup state of the current selection in the editor.
38926 updateToolbar: function(){
38928 if(!this.editor.activated){
38929 this.editor.onFirstFocus();
38933 var btns = this.tb.items.map,
38934 doc = this.editor.doc,
38935 frameId = this.editor.frameId;
38937 if(!this.disable.font && !Roo.isSafari){
38939 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
38940 if(name != this.fontSelect.dom.value){
38941 this.fontSelect.dom.value = name;
38945 if(!this.disable.format){
38946 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
38947 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
38948 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
38950 if(!this.disable.alignments){
38951 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
38952 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
38953 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
38955 if(!Roo.isSafari && !this.disable.lists){
38956 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
38957 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
38960 var ans = this.editor.getAllAncestors();
38961 if (this.formatCombo) {
38964 var store = this.formatCombo.store;
38965 this.formatCombo.setValue("");
38966 for (var i =0; i < ans.length;i++) {
38967 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), true).length) {
38969 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
38977 // hides menus... - so this cant be on a menu...
38978 Roo.menu.MenuMgr.hideAll();
38980 //this.editorsyncValue();
38984 createFontOptions : function(){
38985 var buf = [], fs = this.fontFamilies, ff, lc;
38986 for(var i = 0, len = fs.length; i< len; i++){
38988 lc = ff.toLowerCase();
38990 '<option value="',lc,'" style="font-family:',ff,';"',
38991 (this.defaultFont == lc ? ' selected="true">' : '>'),
38996 return buf.join('');
38999 toggleSourceEdit : function(sourceEditMode){
39000 if(sourceEditMode === undefined){
39001 sourceEditMode = !this.sourceEditMode;
39003 this.sourceEditMode = sourceEditMode === true;
39004 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39005 // just toggle the button?
39006 if(btn.pressed !== this.editor.sourceEditMode){
39007 btn.toggle(this.editor.sourceEditMode);
39011 if(this.sourceEditMode){
39012 this.tb.items.each(function(item){
39013 if(item.cmd != 'sourceedit'){
39019 if(this.initialized){
39020 this.tb.items.each(function(item){
39026 // tell the editor that it's been pressed..
39027 this.editor.toggleSourceEdit(sourceEditMode);
39031 * Object collection of toolbar tooltips for the buttons in the editor. The key
39032 * is the command id associated with that button and the value is a valid QuickTips object.
39037 title: 'Bold (Ctrl+B)',
39038 text: 'Make the selected text bold.',
39039 cls: 'x-html-editor-tip'
39042 title: 'Italic (Ctrl+I)',
39043 text: 'Make the selected text italic.',
39044 cls: 'x-html-editor-tip'
39052 title: 'Bold (Ctrl+B)',
39053 text: 'Make the selected text bold.',
39054 cls: 'x-html-editor-tip'
39057 title: 'Italic (Ctrl+I)',
39058 text: 'Make the selected text italic.',
39059 cls: 'x-html-editor-tip'
39062 title: 'Underline (Ctrl+U)',
39063 text: 'Underline the selected text.',
39064 cls: 'x-html-editor-tip'
39066 increasefontsize : {
39067 title: 'Grow Text',
39068 text: 'Increase the font size.',
39069 cls: 'x-html-editor-tip'
39071 decreasefontsize : {
39072 title: 'Shrink Text',
39073 text: 'Decrease the font size.',
39074 cls: 'x-html-editor-tip'
39077 title: 'Text Highlight Color',
39078 text: 'Change the background color of the selected text.',
39079 cls: 'x-html-editor-tip'
39082 title: 'Font Color',
39083 text: 'Change the color of the selected text.',
39084 cls: 'x-html-editor-tip'
39087 title: 'Align Text Left',
39088 text: 'Align text to the left.',
39089 cls: 'x-html-editor-tip'
39092 title: 'Center Text',
39093 text: 'Center text in the editor.',
39094 cls: 'x-html-editor-tip'
39097 title: 'Align Text Right',
39098 text: 'Align text to the right.',
39099 cls: 'x-html-editor-tip'
39101 insertunorderedlist : {
39102 title: 'Bullet List',
39103 text: 'Start a bulleted list.',
39104 cls: 'x-html-editor-tip'
39106 insertorderedlist : {
39107 title: 'Numbered List',
39108 text: 'Start a numbered list.',
39109 cls: 'x-html-editor-tip'
39112 title: 'Hyperlink',
39113 text: 'Make the selected text a hyperlink.',
39114 cls: 'x-html-editor-tip'
39117 title: 'Source Edit',
39118 text: 'Switch to source editing mode.',
39119 cls: 'x-html-editor-tip'
39123 onDestroy : function(){
39126 this.tb.items.each(function(item){
39128 item.menu.removeAll();
39130 item.menu.el.destroy();
39138 onFirstFocus: function() {
39139 this.tb.items.each(function(item){
39148 // <script type="text/javascript">
39151 * Ext JS Library 1.1.1
39152 * Copyright(c) 2006-2007, Ext JS, LLC.
39159 * @class Roo.form.HtmlEditor.ToolbarContext
39164 new Roo.form.HtmlEditor({
39167 new Roo.form.HtmlEditor.ToolbarStandard(),
39168 new Roo.form.HtmlEditor.ToolbarContext()
39173 * @config : {Object} disable List of elements to disable.. (not done yet.)
39178 Roo.form.HtmlEditor.ToolbarContext = function(config)
39181 Roo.apply(this, config);
39182 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39183 // dont call parent... till later.
39185 Roo.form.HtmlEditor.ToolbarContext.types = {
39197 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39259 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
39264 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
39328 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
39336 * @cfg {Object} disable List of toolbar elements to disable
39345 init : function(editor)
39347 this.editor = editor;
39350 var fid = editor.frameId;
39352 function btn(id, toggle, handler){
39353 var xid = fid + '-'+ id ;
39357 cls : 'x-btn-icon x-edit-'+id,
39358 enableToggle:toggle !== false,
39359 scope: editor, // was editor...
39360 handler:handler||editor.relayBtnCmd,
39361 clickEvent:'mousedown',
39362 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39366 // create a new element.
39367 var wdiv = editor.wrap.createChild({
39369 }, editor.wrap.dom.firstChild.nextSibling, true);
39371 // can we do this more than once??
39373 // stop form submits
39376 // disable everything...
39377 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39378 this.toolbars = {};
39380 for (var i in ty) {
39381 this.toolbars[i] = this.buildToolbar(ty[i],i);
39383 this.tb = this.toolbars.BODY;
39387 this.rendered = true;
39389 // the all the btns;
39390 editor.on('editorevent', this.updateToolbar, this);
39391 // other toolbars need to implement this..
39392 //editor.on('editmodechange', this.updateToolbar, this);
39398 * Protected method that will not generally be called directly. It triggers
39399 * a toolbar update by reading the markup state of the current selection in the editor.
39401 updateToolbar: function(){
39403 if(!this.editor.activated){
39404 this.editor.onFirstFocus();
39409 var ans = this.editor.getAllAncestors();
39412 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39413 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
39414 sel = sel ? sel : this.editor.doc.body;
39415 sel = sel.tagName.length ? sel : this.editor.doc.body;
39416 var tn = sel.tagName.toUpperCase();
39417 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
39418 tn = sel.tagName.toUpperCase();
39419 if (this.tb.name == tn) {
39420 return; // no change
39423 ///console.log("show: " + tn);
39424 this.tb = this.toolbars[tn];
39426 this.tb.fields.each(function(e) {
39427 e.setValue(sel.getAttribute(e.name));
39429 this.tb.selectedNode = sel;
39432 Roo.menu.MenuMgr.hideAll();
39434 //this.editorsyncValue();
39439 onDestroy : function(){
39442 this.tb.items.each(function(item){
39444 item.menu.removeAll();
39446 item.menu.el.destroy();
39454 onFirstFocus: function() {
39455 // need to do this for all the toolbars..
39456 this.tb.items.each(function(item){
39460 buildToolbar: function(tlist, nm)
39462 var editor = this.editor;
39463 // create a new element.
39464 var wdiv = editor.wrap.createChild({
39466 }, editor.wrap.dom.firstChild.nextSibling, true);
39469 var tb = new Roo.Toolbar(wdiv);
39470 tb.add(nm+ ": ");
39471 for (var i in tlist) {
39472 var item = tlist[i];
39473 tb.add(item.title + ": ");
39478 tb.addField( new Roo.form.ComboBox({
39479 store: new Roo.data.SimpleStore({
39482 data : item.opts // from states.js
39485 displayField:'val',
39489 triggerAction: 'all',
39490 emptyText:'Select',
39491 selectOnFocus:true,
39492 width: item.width ? item.width : 130,
39494 'select': function(c, r, i) {
39495 tb.selectedNode.setAttribute(c.name, r.get('val'));
39506 tb.addField( new Roo.form.TextField({
39509 //allowBlank:false,
39514 tb.addField( new Roo.form.TextField({
39520 'change' : function(f, nv, ov) {
39521 tb.selectedNode.setAttribute(f.name, nv);
39527 tb.el.on('click', function(e){
39528 e.preventDefault(); // what does this do?
39530 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
39533 // dont need to disable them... as they will get hidden
39550 * Ext JS Library 1.1.1
39551 * Copyright(c) 2006-2007, Ext JS, LLC.
39553 * Originally Released Under LGPL - original licence link has changed is not relivant.
39556 * <script type="text/javascript">
39560 * @class Roo.form.BasicForm
39561 * @extends Roo.util.Observable
39562 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
39564 * @param {String/HTMLElement/Roo.Element} el The form element or its id
39565 * @param {Object} config Configuration options
39567 Roo.form.BasicForm = function(el, config){
39568 Roo.apply(this, config);
39570 * The Roo.form.Field items in this form.
39571 * @type MixedCollection
39573 this.items = new Roo.util.MixedCollection(false, function(o){
39574 return o.id || (o.id = Roo.id());
39578 * @event beforeaction
39579 * Fires before any action is performed. Return false to cancel the action.
39580 * @param {Form} this
39581 * @param {Action} action The action to be performed
39583 beforeaction: true,
39585 * @event actionfailed
39586 * Fires when an action fails.
39587 * @param {Form} this
39588 * @param {Action} action The action that failed
39590 actionfailed : true,
39592 * @event actioncomplete
39593 * Fires when an action is completed.
39594 * @param {Form} this
39595 * @param {Action} action The action that completed
39597 actioncomplete : true
39602 Roo.form.BasicForm.superclass.constructor.call(this);
39605 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
39607 * @cfg {String} method
39608 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
39611 * @cfg {DataReader} reader
39612 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
39613 * This is optional as there is built-in support for processing JSON.
39616 * @cfg {DataReader} errorReader
39617 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
39618 * This is completely optional as there is built-in support for processing JSON.
39621 * @cfg {String} url
39622 * The URL to use for form actions if one isn't supplied in the action options.
39625 * @cfg {Boolean} fileUpload
39626 * Set to true if this form is a file upload.
39629 * @cfg {Object} baseParams
39630 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
39633 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
39638 activeAction : null,
39641 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
39642 * or setValues() data instead of when the form was first created.
39644 trackResetOnLoad : false,
39647 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
39648 * element by passing it or its id or mask the form itself by passing in true.
39651 waitMsgTarget : undefined,
39654 initEl : function(el){
39655 this.el = Roo.get(el);
39656 this.id = this.el.id || Roo.id();
39657 this.el.on('submit', this.onSubmit, this);
39658 this.el.addClass('x-form');
39662 onSubmit : function(e){
39667 * Returns true if client-side validation on the form is successful.
39670 isValid : function(){
39672 this.items.each(function(f){
39681 * Returns true if any fields in this form have changed since their original load.
39684 isDirty : function(){
39686 this.items.each(function(f){
39696 * Performs a predefined action (submit or load) or custom actions you define on this form.
39697 * @param {String} actionName The name of the action type
39698 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
39699 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
39700 * accept other config options):
39702 Property Type Description
39703 ---------------- --------------- ----------------------------------------------------------------------------------
39704 url String The url for the action (defaults to the form's url)
39705 method String The form method to use (defaults to the form's method, or POST if not defined)
39706 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
39707 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
39708 validate the form on the client (defaults to false)
39710 * @return {BasicForm} this
39712 doAction : function(action, options){
39713 if(typeof action == 'string'){
39714 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
39716 if(this.fireEvent('beforeaction', this, action) !== false){
39717 this.beforeAction(action);
39718 action.run.defer(100, action);
39724 * Shortcut to do a submit action.
39725 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39726 * @return {BasicForm} this
39728 submit : function(options){
39729 this.doAction('submit', options);
39734 * Shortcut to do a load action.
39735 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39736 * @return {BasicForm} this
39738 load : function(options){
39739 this.doAction('load', options);
39744 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
39745 * @param {Record} record The record to edit
39746 * @return {BasicForm} this
39748 updateRecord : function(record){
39749 record.beginEdit();
39750 var fs = record.fields;
39751 fs.each(function(f){
39752 var field = this.findField(f.name);
39754 record.set(f.name, field.getValue());
39762 * Loads an Roo.data.Record into this form.
39763 * @param {Record} record The record to load
39764 * @return {BasicForm} this
39766 loadRecord : function(record){
39767 this.setValues(record.data);
39772 beforeAction : function(action){
39773 var o = action.options;
39775 if(this.waitMsgTarget === true){
39776 this.el.mask(o.waitMsg, 'x-mask-loading');
39777 }else if(this.waitMsgTarget){
39778 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
39779 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
39781 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
39787 afterAction : function(action, success){
39788 this.activeAction = null;
39789 var o = action.options;
39791 if(this.waitMsgTarget === true){
39793 }else if(this.waitMsgTarget){
39794 this.waitMsgTarget.unmask();
39796 Roo.MessageBox.updateProgress(1);
39797 Roo.MessageBox.hide();
39804 Roo.callback(o.success, o.scope, [this, action]);
39805 this.fireEvent('actioncomplete', this, action);
39807 Roo.callback(o.failure, o.scope, [this, action]);
39808 this.fireEvent('actionfailed', this, action);
39813 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
39814 * @param {String} id The value to search for
39817 findField : function(id){
39818 var field = this.items.get(id);
39820 this.items.each(function(f){
39821 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
39827 return field || null;
39832 * Mark fields in this form invalid in bulk.
39833 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
39834 * @return {BasicForm} this
39836 markInvalid : function(errors){
39837 if(errors instanceof Array){
39838 for(var i = 0, len = errors.length; i < len; i++){
39839 var fieldError = errors[i];
39840 var f = this.findField(fieldError.id);
39842 f.markInvalid(fieldError.msg);
39848 if(typeof errors[id] != 'function' && (field = this.findField(id))){
39849 field.markInvalid(errors[id]);
39857 * Set values for fields in this form in bulk.
39858 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
39859 * @return {BasicForm} this
39861 setValues : function(values){
39862 if(values instanceof Array){ // array of objects
39863 for(var i = 0, len = values.length; i < len; i++){
39865 var f = this.findField(v.id);
39867 f.setValue(v.value);
39868 if(this.trackResetOnLoad){
39869 f.originalValue = f.getValue();
39873 }else{ // object hash
39876 if(typeof values[id] != 'function' && (field = this.findField(id))){
39878 if (field.setFromData &&
39879 field.valueField &&
39880 field.displayField &&
39881 // combos' with local stores can
39882 // be queried via setValue()
39883 // to set their value..
39884 (field.store && !field.store.isLocal)
39888 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
39889 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
39890 field.setFromData(sd);
39893 field.setValue(values[id]);
39897 if(this.trackResetOnLoad){
39898 field.originalValue = field.getValue();
39907 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
39908 * they are returned as an array.
39909 * @param {Boolean} asString
39912 getValues : function(asString){
39913 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
39914 if(asString === true){
39917 return Roo.urlDecode(fs);
39921 * Clears all invalid messages in this form.
39922 * @return {BasicForm} this
39924 clearInvalid : function(){
39925 this.items.each(function(f){
39932 * Resets this form.
39933 * @return {BasicForm} this
39935 reset : function(){
39936 this.items.each(function(f){
39943 * Add Roo.form components to this form.
39944 * @param {Field} field1
39945 * @param {Field} field2 (optional)
39946 * @param {Field} etc (optional)
39947 * @return {BasicForm} this
39950 this.items.addAll(Array.prototype.slice.call(arguments, 0));
39956 * Removes a field from the items collection (does NOT remove its markup).
39957 * @param {Field} field
39958 * @return {BasicForm} this
39960 remove : function(field){
39961 this.items.remove(field);
39966 * Looks at the fields in this form, checks them for an id attribute,
39967 * and calls applyTo on the existing dom element with that id.
39968 * @return {BasicForm} this
39970 render : function(){
39971 this.items.each(function(f){
39972 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
39980 * Calls {@link Ext#apply} for all fields in this form with the passed object.
39981 * @param {Object} values
39982 * @return {BasicForm} this
39984 applyToFields : function(o){
39985 this.items.each(function(f){
39992 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
39993 * @param {Object} values
39994 * @return {BasicForm} this
39996 applyIfToFields : function(o){
39997 this.items.each(function(f){
40005 Roo.BasicForm = Roo.form.BasicForm;/*
40007 * Ext JS Library 1.1.1
40008 * Copyright(c) 2006-2007, Ext JS, LLC.
40010 * Originally Released Under LGPL - original licence link has changed is not relivant.
40013 * <script type="text/javascript">
40017 * @class Roo.form.Form
40018 * @extends Roo.form.BasicForm
40019 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40021 * @param {Object} config Configuration options
40023 Roo.form.Form = function(config){
40025 if (config.items) {
40026 xitems = config.items;
40027 delete config.items;
40031 Roo.form.Form.superclass.constructor.call(this, null, config);
40032 this.url = this.url || this.action;
40034 this.root = new Roo.form.Layout(Roo.applyIf({
40038 this.active = this.root;
40040 * Array of all the buttons that have been added to this form via {@link addButton}
40044 this.allItems = [];
40047 * @event clientvalidation
40048 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40049 * @param {Form} this
40050 * @param {Boolean} valid true if the form has passed client-side validation
40052 clientvalidation: true,
40055 * Fires when the form is rendered
40056 * @param {Roo.form.Form} form
40061 Roo.each(xitems, this.addxtype, this);
40067 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40069 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40072 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40075 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40077 buttonAlign:'center',
40080 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40085 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40086 * This property cascades to child containers if not set.
40091 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40092 * fires a looping event with that state. This is required to bind buttons to the valid
40093 * state using the config value formBind:true on the button.
40095 monitorValid : false,
40098 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40103 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40104 * fields are added and the column is closed. If no fields are passed the column remains open
40105 * until end() is called.
40106 * @param {Object} config The config to pass to the column
40107 * @param {Field} field1 (optional)
40108 * @param {Field} field2 (optional)
40109 * @param {Field} etc (optional)
40110 * @return Column The column container object
40112 column : function(c){
40113 var col = new Roo.form.Column(c);
40115 if(arguments.length > 1){ // duplicate code required because of Opera
40116 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40123 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40124 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40125 * until end() is called.
40126 * @param {Object} config The config to pass to the fieldset
40127 * @param {Field} field1 (optional)
40128 * @param {Field} field2 (optional)
40129 * @param {Field} etc (optional)
40130 * @return FieldSet The fieldset container object
40132 fieldset : function(c){
40133 var fs = new Roo.form.FieldSet(c);
40135 if(arguments.length > 1){ // duplicate code required because of Opera
40136 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40143 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
40144 * fields are added and the container is closed. If no fields are passed the container remains open
40145 * until end() is called.
40146 * @param {Object} config The config to pass to the Layout
40147 * @param {Field} field1 (optional)
40148 * @param {Field} field2 (optional)
40149 * @param {Field} etc (optional)
40150 * @return Layout The container object
40152 container : function(c){
40153 var l = new Roo.form.Layout(c);
40155 if(arguments.length > 1){ // duplicate code required because of Opera
40156 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40163 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
40164 * @param {Object} container A Roo.form.Layout or subclass of Layout
40165 * @return {Form} this
40167 start : function(c){
40168 // cascade label info
40169 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
40170 this.active.stack.push(c);
40171 c.ownerCt = this.active;
40177 * Closes the current open container
40178 * @return {Form} this
40181 if(this.active == this.root){
40184 this.active = this.active.ownerCt;
40189 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
40190 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
40191 * as the label of the field.
40192 * @param {Field} field1
40193 * @param {Field} field2 (optional)
40194 * @param {Field} etc. (optional)
40195 * @return {Form} this
40198 this.active.stack.push.apply(this.active.stack, arguments);
40199 this.allItems.push.apply(this.allItems,arguments);
40201 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
40202 if(a[i].isFormField){
40207 Roo.form.Form.superclass.add.apply(this, r);
40212 * Find any element that has been added to a form, using it's ID or name
40213 * This can include framesets, columns etc. along with regular fields..
40214 * @param {String} id - id or name to find.
40216 * @return {Element} e - or false if nothing found.
40218 findbyId : function(id)
40224 Ext.each(this.allItems, function(f){
40225 if (f.id == id || f.name == id ){
40236 * Render this form into the passed container. This should only be called once!
40237 * @param {String/HTMLElement/Element} container The element this component should be rendered into
40238 * @return {Form} this
40240 render : function(ct){
40242 var o = this.autoCreate || {
40244 method : this.method || 'POST',
40245 id : this.id || Roo.id()
40247 this.initEl(ct.createChild(o));
40249 this.root.render(this.el);
40251 this.items.each(function(f){
40252 f.render('x-form-el-'+f.id);
40255 if(this.buttons.length > 0){
40256 // tables are required to maintain order and for correct IE layout
40257 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
40258 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
40259 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
40261 var tr = tb.getElementsByTagName('tr')[0];
40262 for(var i = 0, len = this.buttons.length; i < len; i++) {
40263 var b = this.buttons[i];
40264 var td = document.createElement('td');
40265 td.className = 'x-form-btn-td';
40266 b.render(tr.appendChild(td));
40269 if(this.monitorValid){ // initialize after render
40270 this.startMonitoring();
40272 this.fireEvent('rendered', this);
40277 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
40278 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
40279 * object or a valid Roo.DomHelper element config
40280 * @param {Function} handler The function called when the button is clicked
40281 * @param {Object} scope (optional) The scope of the handler function
40282 * @return {Roo.Button}
40284 addButton : function(config, handler, scope){
40288 minWidth: this.minButtonWidth,
40291 if(typeof config == "string"){
40294 Roo.apply(bc, config);
40296 var btn = new Roo.Button(null, bc);
40297 this.buttons.push(btn);
40302 * Adds a series of form elements (using the xtype property as the factory method.
40303 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
40304 * @param {Object} config
40307 addxtype : function()
40309 var ar = Array.prototype.slice.call(arguments, 0);
40311 for(var i = 0; i < ar.length; i++) {
40313 continue; // skip -- if this happends something invalid got sent, we
40314 // should ignore it, as basically that interface element will not show up
40315 // and that should be pretty obvious!!
40318 if (Roo.form[ar[i].xtype]) {
40320 var fe = Roo.factory(ar[i], Roo.form);
40326 fe.store.form = this;
40331 this.allItems.push(fe);
40332 if (fe.items && fe.addxtype) {
40333 fe.addxtype.apply(fe, fe.items);
40343 // console.log('adding ' + ar[i].xtype);
40345 if (ar[i].xtype == 'Button') {
40346 //console.log('adding button');
40347 //console.log(ar[i]);
40348 this.addButton(ar[i]);
40349 this.allItems.push(fe);
40353 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
40354 alert('end is not supported on xtype any more, use items');
40356 // //console.log('adding end');
40364 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
40365 * option "monitorValid"
40367 startMonitoring : function(){
40370 Roo.TaskMgr.start({
40371 run : this.bindHandler,
40372 interval : this.monitorPoll || 200,
40379 * Stops monitoring of the valid state of this form
40381 stopMonitoring : function(){
40382 this.bound = false;
40386 bindHandler : function(){
40388 return false; // stops binding
40391 this.items.each(function(f){
40392 if(!f.isValid(true)){
40397 for(var i = 0, len = this.buttons.length; i < len; i++){
40398 var btn = this.buttons[i];
40399 if(btn.formBind === true && btn.disabled === valid){
40400 btn.setDisabled(!valid);
40403 this.fireEvent('clientvalidation', this, valid);
40417 Roo.Form = Roo.form.Form;
40420 * Ext JS Library 1.1.1
40421 * Copyright(c) 2006-2007, Ext JS, LLC.
40423 * Originally Released Under LGPL - original licence link has changed is not relivant.
40426 * <script type="text/javascript">
40430 * @class Roo.form.Action
40431 * Internal Class used to handle form actions
40433 * @param {Roo.form.BasicForm} el The form element or its id
40434 * @param {Object} config Configuration options
40438 // define the action interface
40439 Roo.form.Action = function(form, options){
40441 this.options = options || {};
40444 * Client Validation Failed
40447 Roo.form.Action.CLIENT_INVALID = 'client';
40449 * Server Validation Failed
40452 Roo.form.Action.SERVER_INVALID = 'server';
40454 * Connect to Server Failed
40457 Roo.form.Action.CONNECT_FAILURE = 'connect';
40459 * Reading Data from Server Failed
40462 Roo.form.Action.LOAD_FAILURE = 'load';
40464 Roo.form.Action.prototype = {
40466 failureType : undefined,
40467 response : undefined,
40468 result : undefined,
40470 // interface method
40471 run : function(options){
40475 // interface method
40476 success : function(response){
40480 // interface method
40481 handleResponse : function(response){
40485 // default connection failure
40486 failure : function(response){
40487 this.response = response;
40488 this.failureType = Roo.form.Action.CONNECT_FAILURE;
40489 this.form.afterAction(this, false);
40492 processResponse : function(response){
40493 this.response = response;
40494 if(!response.responseText){
40497 this.result = this.handleResponse(response);
40498 return this.result;
40501 // utility functions used internally
40502 getUrl : function(appendParams){
40503 var url = this.options.url || this.form.url || this.form.el.dom.action;
40505 var p = this.getParams();
40507 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
40513 getMethod : function(){
40514 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
40517 getParams : function(){
40518 var bp = this.form.baseParams;
40519 var p = this.options.params;
40521 if(typeof p == "object"){
40522 p = Roo.urlEncode(Roo.applyIf(p, bp));
40523 }else if(typeof p == 'string' && bp){
40524 p += '&' + Roo.urlEncode(bp);
40527 p = Roo.urlEncode(bp);
40532 createCallback : function(){
40534 success: this.success,
40535 failure: this.failure,
40537 timeout: (this.form.timeout*1000),
40538 upload: this.form.fileUpload ? this.success : undefined
40543 Roo.form.Action.Submit = function(form, options){
40544 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
40547 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
40551 var o = this.options;
40552 var method = this.getMethod();
40553 var isPost = method == 'POST';
40554 if(o.clientValidation === false || this.form.isValid()){
40555 Roo.Ajax.request(Roo.apply(this.createCallback(), {
40556 form:this.form.el.dom,
40557 url:this.getUrl(!isPost),
40559 params:isPost ? this.getParams() : null,
40560 isUpload: this.form.fileUpload
40563 }else if (o.clientValidation !== false){ // client validation failed
40564 this.failureType = Roo.form.Action.CLIENT_INVALID;
40565 this.form.afterAction(this, false);
40569 success : function(response){
40570 var result = this.processResponse(response);
40571 if(result === true || result.success){
40572 this.form.afterAction(this, true);
40576 this.form.markInvalid(result.errors);
40577 this.failureType = Roo.form.Action.SERVER_INVALID;
40579 this.form.afterAction(this, false);
40582 handleResponse : function(response){
40583 if(this.form.errorReader){
40584 var rs = this.form.errorReader.read(response);
40587 for(var i = 0, len = rs.records.length; i < len; i++) {
40588 var r = rs.records[i];
40589 errors[i] = r.data;
40592 if(errors.length < 1){
40596 success : rs.success,
40602 ret = Roo.decode(response.responseText);
40606 errorMsg: "Failed to read server message: " + response.responseText,
40616 Roo.form.Action.Load = function(form, options){
40617 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
40618 this.reader = this.form.reader;
40621 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
40625 Roo.Ajax.request(Roo.apply(
40626 this.createCallback(), {
40627 method:this.getMethod(),
40628 url:this.getUrl(false),
40629 params:this.getParams()
40633 success : function(response){
40634 var result = this.processResponse(response);
40635 if(result === true || !result.success || !result.data){
40636 this.failureType = Roo.form.Action.LOAD_FAILURE;
40637 this.form.afterAction(this, false);
40640 this.form.clearInvalid();
40641 this.form.setValues(result.data);
40642 this.form.afterAction(this, true);
40645 handleResponse : function(response){
40646 if(this.form.reader){
40647 var rs = this.form.reader.read(response);
40648 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
40650 success : rs.success,
40654 return Roo.decode(response.responseText);
40658 Roo.form.Action.ACTION_TYPES = {
40659 'load' : Roo.form.Action.Load,
40660 'submit' : Roo.form.Action.Submit
40663 * Ext JS Library 1.1.1
40664 * Copyright(c) 2006-2007, Ext JS, LLC.
40666 * Originally Released Under LGPL - original licence link has changed is not relivant.
40669 * <script type="text/javascript">
40673 * @class Roo.form.Layout
40674 * @extends Roo.Component
40675 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
40677 * @param {Object} config Configuration options
40679 Roo.form.Layout = function(config){
40681 if (config.items) {
40682 xitems = config.items;
40683 delete config.items;
40685 Roo.form.Layout.superclass.constructor.call(this, config);
40687 Roo.each(xitems, this.addxtype, this);
40691 Roo.extend(Roo.form.Layout, Roo.Component, {
40693 * @cfg {String/Object} autoCreate
40694 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
40697 * @cfg {String/Object/Function} style
40698 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
40699 * a function which returns such a specification.
40702 * @cfg {String} labelAlign
40703 * Valid values are "left," "top" and "right" (defaults to "left")
40706 * @cfg {Number} labelWidth
40707 * Fixed width in pixels of all field labels (defaults to undefined)
40710 * @cfg {Boolean} clear
40711 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
40715 * @cfg {String} labelSeparator
40716 * The separator to use after field labels (defaults to ':')
40718 labelSeparator : ':',
40720 * @cfg {Boolean} hideLabels
40721 * True to suppress the display of field labels in this layout (defaults to false)
40723 hideLabels : false,
40726 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
40731 onRender : function(ct, position){
40732 if(this.el){ // from markup
40733 this.el = Roo.get(this.el);
40734 }else { // generate
40735 var cfg = this.getAutoCreate();
40736 this.el = ct.createChild(cfg, position);
40739 this.el.applyStyles(this.style);
40741 if(this.labelAlign){
40742 this.el.addClass('x-form-label-'+this.labelAlign);
40744 if(this.hideLabels){
40745 this.labelStyle = "display:none";
40746 this.elementStyle = "padding-left:0;";
40748 if(typeof this.labelWidth == 'number'){
40749 this.labelStyle = "width:"+this.labelWidth+"px;";
40750 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
40752 if(this.labelAlign == 'top'){
40753 this.labelStyle = "width:auto;";
40754 this.elementStyle = "padding-left:0;";
40757 var stack = this.stack;
40758 var slen = stack.length;
40760 if(!this.fieldTpl){
40761 var t = new Roo.Template(
40762 '<div class="x-form-item {5}">',
40763 '<label for="{0}" style="{2}">{1}{4}</label>',
40764 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
40766 '</div><div class="x-form-clear-left"></div>'
40768 t.disableFormats = true;
40770 Roo.form.Layout.prototype.fieldTpl = t;
40772 for(var i = 0; i < slen; i++) {
40773 if(stack[i].isFormField){
40774 this.renderField(stack[i]);
40776 this.renderComponent(stack[i]);
40781 this.el.createChild({cls:'x-form-clear'});
40786 renderField : function(f){
40787 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
40790 f.labelStyle||this.labelStyle||'', //2
40791 this.elementStyle||'', //3
40792 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
40793 f.itemCls||this.itemCls||'' //5
40794 ], true).getPrevSibling());
40798 renderComponent : function(c){
40799 c.render(c.isLayout ? this.el : this.el.createChild());
40802 * Adds a object form elements (using the xtype property as the factory method.)
40803 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
40804 * @param {Object} config
40806 addxtype : function(o)
40808 // create the lement.
40809 o.form = this.form;
40810 var fe = Roo.factory(o, Roo.form);
40811 this.form.allItems.push(fe);
40812 this.stack.push(fe);
40814 if (fe.isFormField) {
40815 this.form.items.add(fe);
40823 * @class Roo.form.Column
40824 * @extends Roo.form.Layout
40825 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
40827 * @param {Object} config Configuration options
40829 Roo.form.Column = function(config){
40830 Roo.form.Column.superclass.constructor.call(this, config);
40833 Roo.extend(Roo.form.Column, Roo.form.Layout, {
40835 * @cfg {Number/String} width
40836 * The fixed width of the column in pixels or CSS value (defaults to "auto")
40839 * @cfg {String/Object} autoCreate
40840 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
40844 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
40847 onRender : function(ct, position){
40848 Roo.form.Column.superclass.onRender.call(this, ct, position);
40850 this.el.setWidth(this.width);
40857 * @class Roo.form.Row
40858 * @extends Roo.form.Layout
40859 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
40861 * @param {Object} config Configuration options
40865 Roo.form.Row = function(config){
40866 Roo.form.Row.superclass.constructor.call(this, config);
40869 Roo.extend(Roo.form.Row, Roo.form.Layout, {
40871 * @cfg {Number/String} width
40872 * The fixed width of the column in pixels or CSS value (defaults to "auto")
40875 * @cfg {Number/String} height
40876 * The fixed height of the column in pixels or CSS value (defaults to "auto")
40878 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
40882 onRender : function(ct, position){
40883 //console.log('row render');
40885 var t = new Roo.Template(
40886 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
40887 '<label for="{0}" style="{2}">{1}{4}</label>',
40888 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
40892 t.disableFormats = true;
40894 Roo.form.Layout.prototype.rowTpl = t;
40896 this.fieldTpl = this.rowTpl;
40898 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
40899 var labelWidth = 100;
40901 if ((this.labelAlign != 'top')) {
40902 if (typeof this.labelWidth == 'number') {
40903 labelWidth = this.labelWidth
40905 this.padWidth = 20 + labelWidth;
40909 Roo.form.Column.superclass.onRender.call(this, ct, position);
40911 this.el.setWidth(this.width);
40914 this.el.setHeight(this.height);
40919 renderField : function(f){
40920 f.fieldEl = this.fieldTpl.append(this.el, [
40921 f.id, f.fieldLabel,
40922 f.labelStyle||this.labelStyle||'',
40923 this.elementStyle||'',
40924 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
40925 f.itemCls||this.itemCls||'',
40926 f.width ? f.width + this.padWidth : 160 + this.padWidth
40933 * @class Roo.form.FieldSet
40934 * @extends Roo.form.Layout
40935 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
40937 * @param {Object} config Configuration options
40939 Roo.form.FieldSet = function(config){
40940 Roo.form.FieldSet.superclass.constructor.call(this, config);
40943 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
40945 * @cfg {String} legend
40946 * The text to display as the legend for the FieldSet (defaults to '')
40949 * @cfg {String/Object} autoCreate
40950 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
40954 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
40957 onRender : function(ct, position){
40958 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
40960 this.setLegend(this.legend);
40965 setLegend : function(text){
40967 this.el.child('legend').update(text);
40972 * Ext JS Library 1.1.1
40973 * Copyright(c) 2006-2007, Ext JS, LLC.
40975 * Originally Released Under LGPL - original licence link has changed is not relivant.
40978 * <script type="text/javascript">
40981 * @class Roo.form.VTypes
40982 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
40985 Roo.form.VTypes = function(){
40986 // closure these in so they are only created once.
40987 var alpha = /^[a-zA-Z_]+$/;
40988 var alphanum = /^[a-zA-Z0-9_]+$/;
40989 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
40990 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
40992 // All these messages and functions are configurable
40995 * The function used to validate email addresses
40996 * @param {String} value The email address
40998 'email' : function(v){
40999 return email.test(v);
41002 * The error text to display when the email validation function returns false
41005 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
41007 * The keystroke filter mask to be applied on email input
41010 'emailMask' : /[a-z0-9_\.\-@]/i,
41013 * The function used to validate URLs
41014 * @param {String} value The URL
41016 'url' : function(v){
41017 return url.test(v);
41020 * The error text to display when the url validation function returns false
41023 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
41026 * The function used to validate alpha values
41027 * @param {String} value The value
41029 'alpha' : function(v){
41030 return alpha.test(v);
41033 * The error text to display when the alpha validation function returns false
41036 'alphaText' : 'This field should only contain letters and _',
41038 * The keystroke filter mask to be applied on alpha input
41041 'alphaMask' : /[a-z_]/i,
41044 * The function used to validate alphanumeric values
41045 * @param {String} value The value
41047 'alphanum' : function(v){
41048 return alphanum.test(v);
41051 * The error text to display when the alphanumeric validation function returns false
41054 'alphanumText' : 'This field should only contain letters, numbers and _',
41056 * The keystroke filter mask to be applied on alphanumeric input
41059 'alphanumMask' : /[a-z0-9_]/i
41061 }();//<script type="text/javascript">
41064 * @class Roo.form.FCKeditor
41065 * @extends Roo.form.TextArea
41066 * Wrapper around the FCKEditor http://www.fckeditor.net
41068 * Creates a new FCKeditor
41069 * @param {Object} config Configuration options
41071 Roo.form.FCKeditor = function(config){
41072 Roo.form.FCKeditor.superclass.constructor.call(this, config);
41075 * @event editorinit
41076 * Fired when the editor is initialized - you can add extra handlers here..
41077 * @param {FCKeditor} this
41078 * @param {Object} the FCK object.
41085 Roo.form.FCKeditor.editors = { };
41086 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
41088 //defaultAutoCreate : {
41089 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
41093 * @cfg {Object} fck options - see fck manual for details.
41098 * @cfg {Object} fck toolbar set (Basic or Default)
41100 toolbarSet : 'Basic',
41102 * @cfg {Object} fck BasePath
41104 basePath : '/fckeditor/',
41112 onRender : function(ct, position)
41115 this.defaultAutoCreate = {
41117 style:"width:300px;height:60px;",
41118 autocomplete: "off"
41121 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
41124 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
41125 if(this.preventScrollbars){
41126 this.el.setStyle("overflow", "hidden");
41128 this.el.setHeight(this.growMin);
41131 //console.log('onrender' + this.getId() );
41132 Roo.form.FCKeditor.editors[this.getId()] = this;
41135 this.replaceTextarea() ;
41139 getEditor : function() {
41140 return this.fckEditor;
41143 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
41144 * @param {Mixed} value The value to set
41148 setValue : function(value)
41150 //console.log('setValue: ' + value);
41152 if(typeof(value) == 'undefined') { // not sure why this is happending...
41155 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41157 //if(!this.el || !this.getEditor()) {
41158 // this.value = value;
41159 //this.setValue.defer(100,this,[value]);
41163 if(!this.getEditor()) {
41167 this.getEditor().SetData(value);
41174 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
41175 * @return {Mixed} value The field value
41177 getValue : function()
41180 if (this.frame && this.frame.dom.style.display == 'none') {
41181 return Roo.form.FCKeditor.superclass.getValue.call(this);
41184 if(!this.el || !this.getEditor()) {
41186 // this.getValue.defer(100,this);
41191 var value=this.getEditor().GetData();
41192 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41193 return Roo.form.FCKeditor.superclass.getValue.call(this);
41199 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
41200 * @return {Mixed} value The field value
41202 getRawValue : function()
41204 if (this.frame && this.frame.dom.style.display == 'none') {
41205 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41208 if(!this.el || !this.getEditor()) {
41209 //this.getRawValue.defer(100,this);
41216 var value=this.getEditor().GetData();
41217 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
41218 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41222 setSize : function(w,h) {
41226 //if (this.frame && this.frame.dom.style.display == 'none') {
41227 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41230 //if(!this.el || !this.getEditor()) {
41231 // this.setSize.defer(100,this, [w,h]);
41237 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41239 this.frame.dom.setAttribute('width', w);
41240 this.frame.dom.setAttribute('height', h);
41241 this.frame.setSize(w,h);
41245 toggleSourceEdit : function(value) {
41249 this.el.dom.style.display = value ? '' : 'none';
41250 this.frame.dom.style.display = value ? 'none' : '';
41255 focus: function(tag)
41257 if (this.frame.dom.style.display == 'none') {
41258 return Roo.form.FCKeditor.superclass.focus.call(this);
41260 if(!this.el || !this.getEditor()) {
41261 this.focus.defer(100,this, [tag]);
41268 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
41269 this.getEditor().Focus();
41271 if (!this.getEditor().Selection.GetSelection()) {
41272 this.focus.defer(100,this, [tag]);
41277 var r = this.getEditor().EditorDocument.createRange();
41278 r.setStart(tgs[0],0);
41279 r.setEnd(tgs[0],0);
41280 this.getEditor().Selection.GetSelection().removeAllRanges();
41281 this.getEditor().Selection.GetSelection().addRange(r);
41282 this.getEditor().Focus();
41289 replaceTextarea : function()
41291 if ( document.getElementById( this.getId() + '___Frame' ) )
41293 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
41295 // We must check the elements firstly using the Id and then the name.
41296 var oTextarea = document.getElementById( this.getId() );
41298 var colElementsByName = document.getElementsByName( this.getId() ) ;
41300 oTextarea.style.display = 'none' ;
41302 if ( oTextarea.tabIndex ) {
41303 this.TabIndex = oTextarea.tabIndex ;
41306 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
41307 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
41308 this.frame = Roo.get(this.getId() + '___Frame')
41311 _getConfigHtml : function()
41315 for ( var o in this.fckconfig ) {
41316 sConfig += sConfig.length > 0 ? '&' : '';
41317 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
41320 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
41324 _getIFrameHtml : function()
41326 var sFile = 'fckeditor.html' ;
41327 /* no idea what this is about..
41330 if ( (/fcksource=true/i).test( window.top.location.search ) )
41331 sFile = 'fckeditor.original.html' ;
41336 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
41337 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
41340 var html = '<iframe id="' + this.getId() +
41341 '___Frame" src="' + sLink +
41342 '" width="' + this.width +
41343 '" height="' + this.height + '"' +
41344 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
41345 ' frameborder="0" scrolling="no"></iframe>' ;
41350 _insertHtmlBefore : function( html, element )
41352 if ( element.insertAdjacentHTML ) {
41354 element.insertAdjacentHTML( 'beforeBegin', html ) ;
41356 var oRange = document.createRange() ;
41357 oRange.setStartBefore( element ) ;
41358 var oFragment = oRange.createContextualFragment( html );
41359 element.parentNode.insertBefore( oFragment, element ) ;
41372 //Roo.reg('fckeditor', Roo.form.FCKeditor);
41374 function FCKeditor_OnComplete(editorInstance){
41375 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
41376 f.fckEditor = editorInstance;
41377 //console.log("loaded");
41378 f.fireEvent('editorinit', f, editorInstance);
41398 //<script type="text/javascript">
41400 * @class Roo.form.GridField
41401 * @extends Roo.form.Field
41402 * Embed a grid (or editable grid into a form)
41405 * Creates a new GridField
41406 * @param {Object} config Configuration options
41408 Roo.form.GridField = function(config){
41409 Roo.form.GridField.superclass.constructor.call(this, config);
41413 Roo.extend(Roo.form.GridField, Roo.form.Field, {
41415 * @cfg {Number} width - used to restrict width of grid..
41419 * @cfg {Number} height - used to restrict height of grid..
41423 * @cfg {Object} xgrid (xtype'd description of grid) Grid or EditorGrid
41427 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41428 * {tag: "input", type: "checkbox", autocomplete: "off"})
41430 // defaultAutoCreate : { tag: 'div' },
41431 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
41433 * @cfg {String} addTitle Text to include for adding a title.
41437 onResize : function(){
41438 Roo.form.Field.superclass.onResize.apply(this, arguments);
41441 initEvents : function(){
41442 // Roo.form.Checkbox.superclass.initEvents.call(this);
41443 // has no events...
41448 getResizeEl : function(){
41452 getPositionEl : function(){
41457 onRender : function(ct, position){
41459 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
41460 var style = this.style;
41463 Roo.form.DisplayImage.superclass.onRender.call(this, ct, position);
41464 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
41465 this.viewEl = this.wrap.createChild({ tag: 'div' });
41467 this.viewEl.applyStyles(style);
41470 this.viewEl.setWidth(this.width);
41473 this.viewEl.setHeight(this.height);
41475 //if(this.inputValue !== undefined){
41476 //this.setValue(this.value);
41479 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
41482 this.grid.render();
41483 this.grid.getDataSource().on('remove', this.refreshValue, this);
41484 this.grid.getDataSource().on('update', this.refreshValue, this);
41485 this.grid.on('afteredit', this.refreshValue, this);
41491 * Sets the value of the item.
41492 * @param {String} either an object or a string..
41494 setValue : function(v){
41496 v = v || []; // empty set..
41497 // this does not seem smart - it really only affects memoryproxy grids..
41498 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
41499 var ds = this.grid.getDataSource();
41500 // assumes a json reader..
41502 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
41503 ds.loadData( data);
41505 Roo.form.GridField.superclass.setValue.call(this, v);
41506 this.refreshValue();
41507 // should load data in the grid really....
41511 refreshValue: function() {
41513 this.grid.getDataSource().each(function(r) {
41516 this.el.dom.value = Roo.encode(val);
41522 });//<script type="text/javasscript">
41526 * @class Roo.DDView
41527 * A DnD enabled version of Roo.View.
41528 * @param {Element/String} container The Element in which to create the View.
41529 * @param {String} tpl The template string used to create the markup for each element of the View
41530 * @param {Object} config The configuration properties. These include all the config options of
41531 * {@link Roo.View} plus some specific to this class.<br>
41533 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
41534 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
41536 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
41537 .x-view-drag-insert-above {
41538 border-top:1px dotted #3366cc;
41540 .x-view-drag-insert-below {
41541 border-bottom:1px dotted #3366cc;
41547 Roo.DDView = function(container, tpl, config) {
41548 Roo.DDView.superclass.constructor.apply(this, arguments);
41549 this.getEl().setStyle("outline", "0px none");
41550 this.getEl().unselectable();
41551 if (this.dragGroup) {
41552 this.setDraggable(this.dragGroup.split(","));
41554 if (this.dropGroup) {
41555 this.setDroppable(this.dropGroup.split(","));
41557 if (this.deletable) {
41558 this.setDeletable();
41560 this.isDirtyFlag = false;
41566 Roo.extend(Roo.DDView, Roo.View, {
41567 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
41568 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
41569 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
41570 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
41574 reset: Roo.emptyFn,
41576 clearInvalid: Roo.form.Field.prototype.clearInvalid,
41578 validate: function() {
41582 destroy: function() {
41583 this.purgeListeners();
41584 this.getEl.removeAllListeners();
41585 this.getEl().remove();
41586 if (this.dragZone) {
41587 if (this.dragZone.destroy) {
41588 this.dragZone.destroy();
41591 if (this.dropZone) {
41592 if (this.dropZone.destroy) {
41593 this.dropZone.destroy();
41598 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
41599 getName: function() {
41603 /** Loads the View from a JSON string representing the Records to put into the Store. */
41604 setValue: function(v) {
41606 throw "DDView.setValue(). DDView must be constructed with a valid Store";
41609 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
41610 this.store.proxy = new Roo.data.MemoryProxy(data);
41614 /** @return {String} a parenthesised list of the ids of the Records in the View. */
41615 getValue: function() {
41617 this.store.each(function(rec) {
41618 result += rec.id + ',';
41620 return result.substr(0, result.length - 1) + ')';
41623 getIds: function() {
41624 var i = 0, result = new Array(this.store.getCount());
41625 this.store.each(function(rec) {
41626 result[i++] = rec.id;
41631 isDirty: function() {
41632 return this.isDirtyFlag;
41636 * Part of the Roo.dd.DropZone interface. If no target node is found, the
41637 * whole Element becomes the target, and this causes the drop gesture to append.
41639 getTargetFromEvent : function(e) {
41640 var target = e.getTarget();
41641 while ((target !== null) && (target.parentNode != this.el.dom)) {
41642 target = target.parentNode;
41645 target = this.el.dom.lastChild || this.el.dom;
41651 * Create the drag data which consists of an object which has the property "ddel" as
41652 * the drag proxy element.
41654 getDragData : function(e) {
41655 var target = this.findItemFromChild(e.getTarget());
41657 this.handleSelection(e);
41658 var selNodes = this.getSelectedNodes();
41661 copy: this.copy || (this.allowCopy && e.ctrlKey),
41665 var selectedIndices = this.getSelectedIndexes();
41666 for (var i = 0; i < selectedIndices.length; i++) {
41667 dragData.records.push(this.store.getAt(selectedIndices[i]));
41669 if (selNodes.length == 1) {
41670 dragData.ddel = target.cloneNode(true); // the div element
41672 var div = document.createElement('div'); // create the multi element drag "ghost"
41673 div.className = 'multi-proxy';
41674 for (var i = 0, len = selNodes.length; i < len; i++) {
41675 div.appendChild(selNodes[i].cloneNode(true));
41677 dragData.ddel = div;
41679 //console.log(dragData)
41680 //console.log(dragData.ddel.innerHTML)
41683 //console.log('nodragData')
41687 /** Specify to which ddGroup items in this DDView may be dragged. */
41688 setDraggable: function(ddGroup) {
41689 if (ddGroup instanceof Array) {
41690 Roo.each(ddGroup, this.setDraggable, this);
41693 if (this.dragZone) {
41694 this.dragZone.addToGroup(ddGroup);
41696 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
41697 containerScroll: true,
41701 // Draggability implies selection. DragZone's mousedown selects the element.
41702 if (!this.multiSelect) { this.singleSelect = true; }
41704 // Wire the DragZone's handlers up to methods in *this*
41705 this.dragZone.getDragData = this.getDragData.createDelegate(this);
41709 /** Specify from which ddGroup this DDView accepts drops. */
41710 setDroppable: function(ddGroup) {
41711 if (ddGroup instanceof Array) {
41712 Roo.each(ddGroup, this.setDroppable, this);
41715 if (this.dropZone) {
41716 this.dropZone.addToGroup(ddGroup);
41718 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
41719 containerScroll: true,
41723 // Wire the DropZone's handlers up to methods in *this*
41724 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
41725 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
41726 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
41727 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
41728 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
41732 /** Decide whether to drop above or below a View node. */
41733 getDropPoint : function(e, n, dd){
41734 if (n == this.el.dom) { return "above"; }
41735 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
41736 var c = t + (b - t) / 2;
41737 var y = Roo.lib.Event.getPageY(e);
41745 onNodeEnter : function(n, dd, e, data){
41749 onNodeOver : function(n, dd, e, data){
41750 var pt = this.getDropPoint(e, n, dd);
41751 // set the insert point style on the target node
41752 var dragElClass = this.dropNotAllowed;
41755 if (pt == "above"){
41756 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
41757 targetElClass = "x-view-drag-insert-above";
41759 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
41760 targetElClass = "x-view-drag-insert-below";
41762 if (this.lastInsertClass != targetElClass){
41763 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
41764 this.lastInsertClass = targetElClass;
41767 return dragElClass;
41770 onNodeOut : function(n, dd, e, data){
41771 this.removeDropIndicators(n);
41774 onNodeDrop : function(n, dd, e, data){
41775 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
41778 var pt = this.getDropPoint(e, n, dd);
41779 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
41780 if (pt == "below") { insertAt++; }
41781 for (var i = 0; i < data.records.length; i++) {
41782 var r = data.records[i];
41783 var dup = this.store.getById(r.id);
41784 if (dup && (dd != this.dragZone)) {
41785 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
41788 this.store.insert(insertAt++, r.copy());
41790 data.source.isDirtyFlag = true;
41792 this.store.insert(insertAt++, r);
41794 this.isDirtyFlag = true;
41797 this.dragZone.cachedTarget = null;
41801 removeDropIndicators : function(n){
41803 Roo.fly(n).removeClass([
41804 "x-view-drag-insert-above",
41805 "x-view-drag-insert-below"]);
41806 this.lastInsertClass = "_noclass";
41811 * Utility method. Add a delete option to the DDView's context menu.
41812 * @param {String} imageUrl The URL of the "delete" icon image.
41814 setDeletable: function(imageUrl) {
41815 if (!this.singleSelect && !this.multiSelect) {
41816 this.singleSelect = true;
41818 var c = this.getContextMenu();
41819 this.contextMenu.on("itemclick", function(item) {
41822 this.remove(this.getSelectedIndexes());
41826 this.contextMenu.add({
41833 /** Return the context menu for this DDView. */
41834 getContextMenu: function() {
41835 if (!this.contextMenu) {
41836 // Create the View's context menu
41837 this.contextMenu = new Roo.menu.Menu({
41838 id: this.id + "-contextmenu"
41840 this.el.on("contextmenu", this.showContextMenu, this);
41842 return this.contextMenu;
41845 disableContextMenu: function() {
41846 if (this.contextMenu) {
41847 this.el.un("contextmenu", this.showContextMenu, this);
41851 showContextMenu: function(e, item) {
41852 item = this.findItemFromChild(e.getTarget());
41855 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
41856 this.contextMenu.showAt(e.getXY());
41861 * Remove {@link Roo.data.Record}s at the specified indices.
41862 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
41864 remove: function(selectedIndices) {
41865 selectedIndices = [].concat(selectedIndices);
41866 for (var i = 0; i < selectedIndices.length; i++) {
41867 var rec = this.store.getAt(selectedIndices[i]);
41868 this.store.remove(rec);
41873 * Double click fires the event, but also, if this is draggable, and there is only one other
41874 * related DropZone, it transfers the selected node.
41876 onDblClick : function(e){
41877 var item = this.findItemFromChild(e.getTarget());
41879 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
41882 if (this.dragGroup) {
41883 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
41884 while (targets.indexOf(this.dropZone) > -1) {
41885 targets.remove(this.dropZone);
41887 if (targets.length == 1) {
41888 this.dragZone.cachedTarget = null;
41889 var el = Roo.get(targets[0].getEl());
41890 var box = el.getBox(true);
41891 targets[0].onNodeDrop(el.dom, {
41893 xy: [box.x, box.y + box.height - 1]
41894 }, null, this.getDragData(e));
41900 handleSelection: function(e) {
41901 this.dragZone.cachedTarget = null;
41902 var item = this.findItemFromChild(e.getTarget());
41904 this.clearSelections(true);
41907 if (item && (this.multiSelect || this.singleSelect)){
41908 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
41909 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
41910 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
41911 this.unselect(item);
41913 this.select(item, this.multiSelect && e.ctrlKey);
41914 this.lastSelection = item;
41919 onItemClick : function(item, index, e){
41920 if(this.fireEvent("beforeclick", this, index, item, e) === false){
41926 unselect : function(nodeInfo, suppressEvent){
41927 var node = this.getNode(nodeInfo);
41928 if(node && this.isSelected(node)){
41929 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
41930 Roo.fly(node).removeClass(this.selectedClass);
41931 this.selections.remove(node);
41932 if(!suppressEvent){
41933 this.fireEvent("selectionchange", this, this.selections);
41941 * Ext JS Library 1.1.1
41942 * Copyright(c) 2006-2007, Ext JS, LLC.
41944 * Originally Released Under LGPL - original licence link has changed is not relivant.
41947 * <script type="text/javascript">
41951 * @class Roo.LayoutManager
41952 * @extends Roo.util.Observable
41953 * Base class for layout managers.
41955 Roo.LayoutManager = function(container, config){
41956 Roo.LayoutManager.superclass.constructor.call(this);
41957 this.el = Roo.get(container);
41958 // ie scrollbar fix
41959 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
41960 document.body.scroll = "no";
41961 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
41962 this.el.position('relative');
41964 this.id = this.el.id;
41965 this.el.addClass("x-layout-container");
41966 /** false to disable window resize monitoring @type Boolean */
41967 this.monitorWindowResize = true;
41972 * Fires when a layout is performed.
41973 * @param {Roo.LayoutManager} this
41977 * @event regionresized
41978 * Fires when the user resizes a region.
41979 * @param {Roo.LayoutRegion} region The resized region
41980 * @param {Number} newSize The new size (width for east/west, height for north/south)
41982 "regionresized" : true,
41984 * @event regioncollapsed
41985 * Fires when a region is collapsed.
41986 * @param {Roo.LayoutRegion} region The collapsed region
41988 "regioncollapsed" : true,
41990 * @event regionexpanded
41991 * Fires when a region is expanded.
41992 * @param {Roo.LayoutRegion} region The expanded region
41994 "regionexpanded" : true
41996 this.updating = false;
41997 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
42000 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
42002 * Returns true if this layout is currently being updated
42003 * @return {Boolean}
42005 isUpdating : function(){
42006 return this.updating;
42010 * Suspend the LayoutManager from doing auto-layouts while
42011 * making multiple add or remove calls
42013 beginUpdate : function(){
42014 this.updating = true;
42018 * Restore auto-layouts and optionally disable the manager from performing a layout
42019 * @param {Boolean} noLayout true to disable a layout update
42021 endUpdate : function(noLayout){
42022 this.updating = false;
42028 layout: function(){
42032 onRegionResized : function(region, newSize){
42033 this.fireEvent("regionresized", region, newSize);
42037 onRegionCollapsed : function(region){
42038 this.fireEvent("regioncollapsed", region);
42041 onRegionExpanded : function(region){
42042 this.fireEvent("regionexpanded", region);
42046 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
42047 * performs box-model adjustments.
42048 * @return {Object} The size as an object {width: (the width), height: (the height)}
42050 getViewSize : function(){
42052 if(this.el.dom != document.body){
42053 size = this.el.getSize();
42055 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
42057 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
42058 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
42063 * Returns the Element this layout is bound to.
42064 * @return {Roo.Element}
42066 getEl : function(){
42071 * Returns the specified region.
42072 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
42073 * @return {Roo.LayoutRegion}
42075 getRegion : function(target){
42076 return this.regions[target.toLowerCase()];
42079 onWindowResize : function(){
42080 if(this.monitorWindowResize){
42086 * Ext JS Library 1.1.1
42087 * Copyright(c) 2006-2007, Ext JS, LLC.
42089 * Originally Released Under LGPL - original licence link has changed is not relivant.
42092 * <script type="text/javascript">
42095 * @class Roo.BorderLayout
42096 * @extends Roo.LayoutManager
42097 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
42098 * please see: <br><br>
42099 * <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>
42100 * <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>
42103 var layout = new Roo.BorderLayout(document.body, {
42137 preferredTabWidth: 150
42142 var CP = Roo.ContentPanel;
42144 layout.beginUpdate();
42145 layout.add("north", new CP("north", "North"));
42146 layout.add("south", new CP("south", {title: "South", closable: true}));
42147 layout.add("west", new CP("west", {title: "West"}));
42148 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
42149 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
42150 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
42151 layout.getRegion("center").showPanel("center1");
42152 layout.endUpdate();
42155 <b>The container the layout is rendered into can be either the body element or any other element.
42156 If it is not the body element, the container needs to either be an absolute positioned element,
42157 or you will need to add "position:relative" to the css of the container. You will also need to specify
42158 the container size if it is not the body element.</b>
42161 * Create a new BorderLayout
42162 * @param {String/HTMLElement/Element} container The container this layout is bound to
42163 * @param {Object} config Configuration options
42165 Roo.BorderLayout = function(container, config){
42166 config = config || {};
42167 Roo.BorderLayout.superclass.constructor.call(this, container, config);
42168 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
42169 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
42170 var target = this.factory.validRegions[i];
42171 if(config[target]){
42172 this.addRegion(target, config[target]);
42177 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
42179 * Creates and adds a new region if it doesn't already exist.
42180 * @param {String} target The target region key (north, south, east, west or center).
42181 * @param {Object} config The regions config object
42182 * @return {BorderLayoutRegion} The new region
42184 addRegion : function(target, config){
42185 if(!this.regions[target]){
42186 var r = this.factory.create(target, this, config);
42187 this.bindRegion(target, r);
42189 return this.regions[target];
42193 bindRegion : function(name, r){
42194 this.regions[name] = r;
42195 r.on("visibilitychange", this.layout, this);
42196 r.on("paneladded", this.layout, this);
42197 r.on("panelremoved", this.layout, this);
42198 r.on("invalidated", this.layout, this);
42199 r.on("resized", this.onRegionResized, this);
42200 r.on("collapsed", this.onRegionCollapsed, this);
42201 r.on("expanded", this.onRegionExpanded, this);
42205 * Performs a layout update.
42207 layout : function(){
42208 if(this.updating) return;
42209 var size = this.getViewSize();
42210 var w = size.width;
42211 var h = size.height;
42216 //var x = 0, y = 0;
42218 var rs = this.regions;
42219 var north = rs["north"];
42220 var south = rs["south"];
42221 var west = rs["west"];
42222 var east = rs["east"];
42223 var center = rs["center"];
42224 //if(this.hideOnLayout){ // not supported anymore
42225 //c.el.setStyle("display", "none");
42227 if(north && north.isVisible()){
42228 var b = north.getBox();
42229 var m = north.getMargins();
42230 b.width = w - (m.left+m.right);
42233 centerY = b.height + b.y + m.bottom;
42234 centerH -= centerY;
42235 north.updateBox(this.safeBox(b));
42237 if(south && south.isVisible()){
42238 var b = south.getBox();
42239 var m = south.getMargins();
42240 b.width = w - (m.left+m.right);
42242 var totalHeight = (b.height + m.top + m.bottom);
42243 b.y = h - totalHeight + m.top;
42244 centerH -= totalHeight;
42245 south.updateBox(this.safeBox(b));
42247 if(west && west.isVisible()){
42248 var b = west.getBox();
42249 var m = west.getMargins();
42250 b.height = centerH - (m.top+m.bottom);
42252 b.y = centerY + m.top;
42253 var totalWidth = (b.width + m.left + m.right);
42254 centerX += totalWidth;
42255 centerW -= totalWidth;
42256 west.updateBox(this.safeBox(b));
42258 if(east && east.isVisible()){
42259 var b = east.getBox();
42260 var m = east.getMargins();
42261 b.height = centerH - (m.top+m.bottom);
42262 var totalWidth = (b.width + m.left + m.right);
42263 b.x = w - totalWidth + m.left;
42264 b.y = centerY + m.top;
42265 centerW -= totalWidth;
42266 east.updateBox(this.safeBox(b));
42269 var m = center.getMargins();
42271 x: centerX + m.left,
42272 y: centerY + m.top,
42273 width: centerW - (m.left+m.right),
42274 height: centerH - (m.top+m.bottom)
42276 //if(this.hideOnLayout){
42277 //center.el.setStyle("display", "block");
42279 center.updateBox(this.safeBox(centerBox));
42282 this.fireEvent("layout", this);
42286 safeBox : function(box){
42287 box.width = Math.max(0, box.width);
42288 box.height = Math.max(0, box.height);
42293 * Adds a ContentPanel (or subclass) to this layout.
42294 * @param {String} target The target region key (north, south, east, west or center).
42295 * @param {Roo.ContentPanel} panel The panel to add
42296 * @return {Roo.ContentPanel} The added panel
42298 add : function(target, panel){
42300 target = target.toLowerCase();
42301 return this.regions[target].add(panel);
42305 * Remove a ContentPanel (or subclass) to this layout.
42306 * @param {String} target The target region key (north, south, east, west or center).
42307 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
42308 * @return {Roo.ContentPanel} The removed panel
42310 remove : function(target, panel){
42311 target = target.toLowerCase();
42312 return this.regions[target].remove(panel);
42316 * Searches all regions for a panel with the specified id
42317 * @param {String} panelId
42318 * @return {Roo.ContentPanel} The panel or null if it wasn't found
42320 findPanel : function(panelId){
42321 var rs = this.regions;
42322 for(var target in rs){
42323 if(typeof rs[target] != "function"){
42324 var p = rs[target].getPanel(panelId);
42334 * Searches all regions for a panel with the specified id and activates (shows) it.
42335 * @param {String/ContentPanel} panelId The panels id or the panel itself
42336 * @return {Roo.ContentPanel} The shown panel or null
42338 showPanel : function(panelId) {
42339 var rs = this.regions;
42340 for(var target in rs){
42341 var r = rs[target];
42342 if(typeof r != "function"){
42343 if(r.hasPanel(panelId)){
42344 return r.showPanel(panelId);
42352 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
42353 * @param {Roo.state.Provider} provider (optional) An alternate state provider
42355 restoreState : function(provider){
42357 provider = Roo.state.Manager;
42359 var sm = new Roo.LayoutStateManager();
42360 sm.init(this, provider);
42364 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
42365 * object should contain properties for each region to add ContentPanels to, and each property's value should be
42366 * a valid ContentPanel config object. Example:
42368 // Create the main layout
42369 var layout = new Roo.BorderLayout('main-ct', {
42380 // Create and add multiple ContentPanels at once via configs
42383 id: 'source-files',
42385 title:'Ext Source Files',
42398 * @param {Object} regions An object containing ContentPanel configs by region name
42400 batchAdd : function(regions){
42401 this.beginUpdate();
42402 for(var rname in regions){
42403 var lr = this.regions[rname];
42405 this.addTypedPanels(lr, regions[rname]);
42412 addTypedPanels : function(lr, ps){
42413 if(typeof ps == 'string'){
42414 lr.add(new Roo.ContentPanel(ps));
42416 else if(ps instanceof Array){
42417 for(var i =0, len = ps.length; i < len; i++){
42418 this.addTypedPanels(lr, ps[i]);
42421 else if(!ps.events){ // raw config?
42423 delete ps.el; // prevent conflict
42424 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
42426 else { // panel object assumed!
42431 * Adds a xtype elements to the layout.
42435 xtype : 'ContentPanel',
42442 xtype : 'NestedLayoutPanel',
42448 items : [ ... list of content panels or nested layout panels.. ]
42452 * @param {Object} cfg Xtype definition of item to add.
42454 addxtype : function(cfg)
42456 // basically accepts a pannel...
42457 // can accept a layout region..!?!?
42458 // console.log('BorderLayout add ' + cfg.xtype)
42460 if (!cfg.xtype.match(/Panel$/)) {
42464 var region = cfg.region;
42470 xitems = cfg.items;
42477 case 'ContentPanel': // ContentPanel (el, cfg)
42478 if(cfg.autoCreate) {
42479 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42481 var el = this.el.createChild();
42482 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
42485 this.add(region, ret);
42489 case 'TreePanel': // our new panel!
42490 cfg.el = this.el.createChild();
42491 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42492 this.add(region, ret);
42495 case 'NestedLayoutPanel':
42496 // create a new Layout (which is a Border Layout...
42497 var el = this.el.createChild();
42498 var clayout = cfg.layout;
42500 clayout.items = clayout.items || [];
42501 // replace this exitems with the clayout ones..
42502 xitems = clayout.items;
42505 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
42506 cfg.background = false;
42508 var layout = new Roo.BorderLayout(el, clayout);
42510 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
42511 //console.log('adding nested layout panel ' + cfg.toSource());
42512 this.add(region, ret);
42518 // needs grid and region
42520 //var el = this.getRegion(region).el.createChild();
42521 var el = this.el.createChild();
42522 // create the grid first...
42524 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
42526 if (region == 'center' && this.active ) {
42527 cfg.background = false;
42529 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
42531 this.add(region, ret);
42532 if (cfg.background) {
42533 ret.on('activate', function(gp) {
42534 if (!gp.grid.rendered) {
42547 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
42549 // GridPanel (grid, cfg)
42552 this.beginUpdate();
42554 Roo.each(xitems, function(i) {
42564 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
42565 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
42566 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
42567 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
42570 var CP = Roo.ContentPanel;
42572 var layout = Roo.BorderLayout.create({
42576 panels: [new CP("north", "North")]
42585 panels: [new CP("west", {title: "West"})]
42594 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
42603 panels: [new CP("south", {title: "South", closable: true})]
42610 preferredTabWidth: 150,
42612 new CP("center1", {title: "Close Me", closable: true}),
42613 new CP("center2", {title: "Center Panel", closable: false})
42618 layout.getRegion("center").showPanel("center1");
42623 Roo.BorderLayout.create = function(config, targetEl){
42624 var layout = new Roo.BorderLayout(targetEl || document.body, config);
42625 layout.beginUpdate();
42626 var regions = Roo.BorderLayout.RegionFactory.validRegions;
42627 for(var j = 0, jlen = regions.length; j < jlen; j++){
42628 var lr = regions[j];
42629 if(layout.regions[lr] && config[lr].panels){
42630 var r = layout.regions[lr];
42631 var ps = config[lr].panels;
42632 layout.addTypedPanels(r, ps);
42635 layout.endUpdate();
42640 Roo.BorderLayout.RegionFactory = {
42642 validRegions : ["north","south","east","west","center"],
42645 create : function(target, mgr, config){
42646 target = target.toLowerCase();
42647 if(config.lightweight || config.basic){
42648 return new Roo.BasicLayoutRegion(mgr, config, target);
42652 return new Roo.NorthLayoutRegion(mgr, config);
42654 return new Roo.SouthLayoutRegion(mgr, config);
42656 return new Roo.EastLayoutRegion(mgr, config);
42658 return new Roo.WestLayoutRegion(mgr, config);
42660 return new Roo.CenterLayoutRegion(mgr, config);
42662 throw 'Layout region "'+target+'" not supported.';
42666 * Ext JS Library 1.1.1
42667 * Copyright(c) 2006-2007, Ext JS, LLC.
42669 * Originally Released Under LGPL - original licence link has changed is not relivant.
42672 * <script type="text/javascript">
42676 * @class Roo.BasicLayoutRegion
42677 * @extends Roo.util.Observable
42678 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
42679 * and does not have a titlebar, tabs or any other features. All it does is size and position
42680 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
42682 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
42684 this.position = pos;
42687 * @scope Roo.BasicLayoutRegion
42691 * @event beforeremove
42692 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
42693 * @param {Roo.LayoutRegion} this
42694 * @param {Roo.ContentPanel} panel The panel
42695 * @param {Object} e The cancel event object
42697 "beforeremove" : true,
42699 * @event invalidated
42700 * Fires when the layout for this region is changed.
42701 * @param {Roo.LayoutRegion} this
42703 "invalidated" : true,
42705 * @event visibilitychange
42706 * Fires when this region is shown or hidden
42707 * @param {Roo.LayoutRegion} this
42708 * @param {Boolean} visibility true or false
42710 "visibilitychange" : true,
42712 * @event paneladded
42713 * Fires when a panel is added.
42714 * @param {Roo.LayoutRegion} this
42715 * @param {Roo.ContentPanel} panel The panel
42717 "paneladded" : true,
42719 * @event panelremoved
42720 * Fires when a panel is removed.
42721 * @param {Roo.LayoutRegion} this
42722 * @param {Roo.ContentPanel} panel The panel
42724 "panelremoved" : true,
42727 * Fires when this region is collapsed.
42728 * @param {Roo.LayoutRegion} this
42730 "collapsed" : true,
42733 * Fires when this region is expanded.
42734 * @param {Roo.LayoutRegion} this
42739 * Fires when this region is slid into view.
42740 * @param {Roo.LayoutRegion} this
42742 "slideshow" : true,
42745 * Fires when this region slides out of view.
42746 * @param {Roo.LayoutRegion} this
42748 "slidehide" : true,
42750 * @event panelactivated
42751 * Fires when a panel is activated.
42752 * @param {Roo.LayoutRegion} this
42753 * @param {Roo.ContentPanel} panel The activated panel
42755 "panelactivated" : true,
42758 * Fires when the user resizes this region.
42759 * @param {Roo.LayoutRegion} this
42760 * @param {Number} newSize The new size (width for east/west, height for north/south)
42764 /** A collection of panels in this region. @type Roo.util.MixedCollection */
42765 this.panels = new Roo.util.MixedCollection();
42766 this.panels.getKey = this.getPanelId.createDelegate(this);
42768 this.activePanel = null;
42769 // ensure listeners are added...
42771 if (config.listeners || config.events) {
42772 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
42773 listeners : config.listeners || {},
42774 events : config.events || {}
42778 if(skipConfig !== true){
42779 this.applyConfig(config);
42783 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
42784 getPanelId : function(p){
42788 applyConfig : function(config){
42789 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
42790 this.config = config;
42795 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
42796 * the width, for horizontal (north, south) the height.
42797 * @param {Number} newSize The new width or height
42799 resizeTo : function(newSize){
42800 var el = this.el ? this.el :
42801 (this.activePanel ? this.activePanel.getEl() : null);
42803 switch(this.position){
42806 el.setWidth(newSize);
42807 this.fireEvent("resized", this, newSize);
42811 el.setHeight(newSize);
42812 this.fireEvent("resized", this, newSize);
42818 getBox : function(){
42819 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
42822 getMargins : function(){
42823 return this.margins;
42826 updateBox : function(box){
42828 var el = this.activePanel.getEl();
42829 el.dom.style.left = box.x + "px";
42830 el.dom.style.top = box.y + "px";
42831 this.activePanel.setSize(box.width, box.height);
42835 * Returns the container element for this region.
42836 * @return {Roo.Element}
42838 getEl : function(){
42839 return this.activePanel;
42843 * Returns true if this region is currently visible.
42844 * @return {Boolean}
42846 isVisible : function(){
42847 return this.activePanel ? true : false;
42850 setActivePanel : function(panel){
42851 panel = this.getPanel(panel);
42852 if(this.activePanel && this.activePanel != panel){
42853 this.activePanel.setActiveState(false);
42854 this.activePanel.getEl().setLeftTop(-10000,-10000);
42856 this.activePanel = panel;
42857 panel.setActiveState(true);
42859 panel.setSize(this.box.width, this.box.height);
42861 this.fireEvent("panelactivated", this, panel);
42862 this.fireEvent("invalidated");
42866 * Show the specified panel.
42867 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
42868 * @return {Roo.ContentPanel} The shown panel or null
42870 showPanel : function(panel){
42871 if(panel = this.getPanel(panel)){
42872 this.setActivePanel(panel);
42878 * Get the active panel for this region.
42879 * @return {Roo.ContentPanel} The active panel or null
42881 getActivePanel : function(){
42882 return this.activePanel;
42886 * Add the passed ContentPanel(s)
42887 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
42888 * @return {Roo.ContentPanel} The panel added (if only one was added)
42890 add : function(panel){
42891 if(arguments.length > 1){
42892 for(var i = 0, len = arguments.length; i < len; i++) {
42893 this.add(arguments[i]);
42897 if(this.hasPanel(panel)){
42898 this.showPanel(panel);
42901 var el = panel.getEl();
42902 if(el.dom.parentNode != this.mgr.el.dom){
42903 this.mgr.el.dom.appendChild(el.dom);
42905 if(panel.setRegion){
42906 panel.setRegion(this);
42908 this.panels.add(panel);
42909 el.setStyle("position", "absolute");
42910 if(!panel.background){
42911 this.setActivePanel(panel);
42912 if(this.config.initialSize && this.panels.getCount()==1){
42913 this.resizeTo(this.config.initialSize);
42916 this.fireEvent("paneladded", this, panel);
42921 * Returns true if the panel is in this region.
42922 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
42923 * @return {Boolean}
42925 hasPanel : function(panel){
42926 if(typeof panel == "object"){ // must be panel obj
42927 panel = panel.getId();
42929 return this.getPanel(panel) ? true : false;
42933 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
42934 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
42935 * @param {Boolean} preservePanel Overrides the config preservePanel option
42936 * @return {Roo.ContentPanel} The panel that was removed
42938 remove : function(panel, preservePanel){
42939 panel = this.getPanel(panel);
42944 this.fireEvent("beforeremove", this, panel, e);
42945 if(e.cancel === true){
42948 var panelId = panel.getId();
42949 this.panels.removeKey(panelId);
42954 * Returns the panel specified or null if it's not in this region.
42955 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
42956 * @return {Roo.ContentPanel}
42958 getPanel : function(id){
42959 if(typeof id == "object"){ // must be panel obj
42962 return this.panels.get(id);
42966 * Returns this regions position (north/south/east/west/center).
42969 getPosition: function(){
42970 return this.position;
42974 * Ext JS Library 1.1.1
42975 * Copyright(c) 2006-2007, Ext JS, LLC.
42977 * Originally Released Under LGPL - original licence link has changed is not relivant.
42980 * <script type="text/javascript">
42984 * @class Roo.LayoutRegion
42985 * @extends Roo.BasicLayoutRegion
42986 * This class represents a region in a layout manager.
42987 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
42988 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
42989 * @cfg {Boolean} floatable False to disable floating (defaults to true)
42990 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
42991 * @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})
42992 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
42993 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
42994 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
42995 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
42996 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
42997 * @cfg {String} title The title for the region (overrides panel titles)
42998 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
42999 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
43000 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
43001 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
43002 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
43003 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
43004 * the space available, similar to FireFox 1.5 tabs (defaults to false)
43005 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
43006 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
43007 * @cfg {Boolean} showPin True to show a pin button
43008 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
43009 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
43010 * @cfg {Boolean} disableTabTips True to disable tab tooltips
43011 * @cfg {Number} width For East/West panels
43012 * @cfg {Number} height For North/South panels
43013 * @cfg {Boolean} split To show the splitter
43015 Roo.LayoutRegion = function(mgr, config, pos){
43016 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
43017 var dh = Roo.DomHelper;
43018 /** This region's container element
43019 * @type Roo.Element */
43020 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
43021 /** This region's title element
43022 * @type Roo.Element */
43024 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
43025 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
43026 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
43028 this.titleEl.enableDisplayMode();
43029 /** This region's title text element
43030 * @type HTMLElement */
43031 this.titleTextEl = this.titleEl.dom.firstChild;
43032 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
43033 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
43034 this.closeBtn.enableDisplayMode();
43035 this.closeBtn.on("click", this.closeClicked, this);
43036 this.closeBtn.hide();
43038 this.createBody(config);
43039 this.visible = true;
43040 this.collapsed = false;
43042 if(config.hideWhenEmpty){
43044 this.on("paneladded", this.validateVisibility, this);
43045 this.on("panelremoved", this.validateVisibility, this);
43047 this.applyConfig(config);
43050 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
43052 createBody : function(){
43053 /** This region's body element
43054 * @type Roo.Element */
43055 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
43058 applyConfig : function(c){
43059 if(c.collapsible && this.position != "center" && !this.collapsedEl){
43060 var dh = Roo.DomHelper;
43061 if(c.titlebar !== false){
43062 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
43063 this.collapseBtn.on("click", this.collapse, this);
43064 this.collapseBtn.enableDisplayMode();
43066 if(c.showPin === true || this.showPin){
43067 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
43068 this.stickBtn.enableDisplayMode();
43069 this.stickBtn.on("click", this.expand, this);
43070 this.stickBtn.hide();
43073 /** This region's collapsed element
43074 * @type Roo.Element */
43075 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
43076 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
43078 if(c.floatable !== false){
43079 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
43080 this.collapsedEl.on("click", this.collapseClick, this);
43083 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
43084 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
43085 id: "message", unselectable: "on", style:{"float":"left"}});
43086 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
43088 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
43089 this.expandBtn.on("click", this.expand, this);
43091 if(this.collapseBtn){
43092 this.collapseBtn.setVisible(c.collapsible == true);
43094 this.cmargins = c.cmargins || this.cmargins ||
43095 (this.position == "west" || this.position == "east" ?
43096 {top: 0, left: 2, right:2, bottom: 0} :
43097 {top: 2, left: 0, right:0, bottom: 2});
43098 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43099 this.bottomTabs = c.tabPosition != "top";
43100 this.autoScroll = c.autoScroll || false;
43101 if(this.autoScroll){
43102 this.bodyEl.setStyle("overflow", "auto");
43104 this.bodyEl.setStyle("overflow", "hidden");
43106 //if(c.titlebar !== false){
43107 if((!c.titlebar && !c.title) || c.titlebar === false){
43108 this.titleEl.hide();
43110 this.titleEl.show();
43112 this.titleTextEl.innerHTML = c.title;
43116 this.duration = c.duration || .30;
43117 this.slideDuration = c.slideDuration || .45;
43120 this.collapse(true);
43127 * Returns true if this region is currently visible.
43128 * @return {Boolean}
43130 isVisible : function(){
43131 return this.visible;
43135 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
43136 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
43138 setCollapsedTitle : function(title){
43139 title = title || " ";
43140 if(this.collapsedTitleTextEl){
43141 this.collapsedTitleTextEl.innerHTML = title;
43145 getBox : function(){
43147 if(!this.collapsed){
43148 b = this.el.getBox(false, true);
43150 b = this.collapsedEl.getBox(false, true);
43155 getMargins : function(){
43156 return this.collapsed ? this.cmargins : this.margins;
43159 highlight : function(){
43160 this.el.addClass("x-layout-panel-dragover");
43163 unhighlight : function(){
43164 this.el.removeClass("x-layout-panel-dragover");
43167 updateBox : function(box){
43169 if(!this.collapsed){
43170 this.el.dom.style.left = box.x + "px";
43171 this.el.dom.style.top = box.y + "px";
43172 this.updateBody(box.width, box.height);
43174 this.collapsedEl.dom.style.left = box.x + "px";
43175 this.collapsedEl.dom.style.top = box.y + "px";
43176 this.collapsedEl.setSize(box.width, box.height);
43179 this.tabs.autoSizeTabs();
43183 updateBody : function(w, h){
43185 this.el.setWidth(w);
43186 w -= this.el.getBorderWidth("rl");
43187 if(this.config.adjustments){
43188 w += this.config.adjustments[0];
43192 this.el.setHeight(h);
43193 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
43194 h -= this.el.getBorderWidth("tb");
43195 if(this.config.adjustments){
43196 h += this.config.adjustments[1];
43198 this.bodyEl.setHeight(h);
43200 h = this.tabs.syncHeight(h);
43203 if(this.panelSize){
43204 w = w !== null ? w : this.panelSize.width;
43205 h = h !== null ? h : this.panelSize.height;
43207 if(this.activePanel){
43208 var el = this.activePanel.getEl();
43209 w = w !== null ? w : el.getWidth();
43210 h = h !== null ? h : el.getHeight();
43211 this.panelSize = {width: w, height: h};
43212 this.activePanel.setSize(w, h);
43214 if(Roo.isIE && this.tabs){
43215 this.tabs.el.repaint();
43220 * Returns the container element for this region.
43221 * @return {Roo.Element}
43223 getEl : function(){
43228 * Hides this region.
43231 if(!this.collapsed){
43232 this.el.dom.style.left = "-2000px";
43235 this.collapsedEl.dom.style.left = "-2000px";
43236 this.collapsedEl.hide();
43238 this.visible = false;
43239 this.fireEvent("visibilitychange", this, false);
43243 * Shows this region if it was previously hidden.
43246 if(!this.collapsed){
43249 this.collapsedEl.show();
43251 this.visible = true;
43252 this.fireEvent("visibilitychange", this, true);
43255 closeClicked : function(){
43256 if(this.activePanel){
43257 this.remove(this.activePanel);
43261 collapseClick : function(e){
43263 e.stopPropagation();
43266 e.stopPropagation();
43272 * Collapses this region.
43273 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
43275 collapse : function(skipAnim){
43276 if(this.collapsed) return;
43277 this.collapsed = true;
43279 this.split.el.hide();
43281 if(this.config.animate && skipAnim !== true){
43282 this.fireEvent("invalidated", this);
43283 this.animateCollapse();
43285 this.el.setLocation(-20000,-20000);
43287 this.collapsedEl.show();
43288 this.fireEvent("collapsed", this);
43289 this.fireEvent("invalidated", this);
43293 animateCollapse : function(){
43298 * Expands this region if it was previously collapsed.
43299 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
43300 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
43302 expand : function(e, skipAnim){
43303 if(e) e.stopPropagation();
43304 if(!this.collapsed || this.el.hasActiveFx()) return;
43306 this.afterSlideIn();
43309 this.collapsed = false;
43310 if(this.config.animate && skipAnim !== true){
43311 this.animateExpand();
43315 this.split.el.show();
43317 this.collapsedEl.setLocation(-2000,-2000);
43318 this.collapsedEl.hide();
43319 this.fireEvent("invalidated", this);
43320 this.fireEvent("expanded", this);
43324 animateExpand : function(){
43328 initTabs : function(){
43329 this.bodyEl.setStyle("overflow", "hidden");
43330 var ts = new Roo.TabPanel(this.bodyEl.dom, {
43331 tabPosition: this.bottomTabs ? 'bottom' : 'top',
43332 disableTooltips: this.config.disableTabTips
43334 if(this.config.hideTabs){
43335 ts.stripWrap.setDisplayed(false);
43338 ts.resizeTabs = this.config.resizeTabs === true;
43339 ts.minTabWidth = this.config.minTabWidth || 40;
43340 ts.maxTabWidth = this.config.maxTabWidth || 250;
43341 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
43342 ts.monitorResize = false;
43343 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43344 ts.bodyEl.addClass('x-layout-tabs-body');
43345 this.panels.each(this.initPanelAsTab, this);
43348 initPanelAsTab : function(panel){
43349 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
43350 this.config.closeOnTab && panel.isClosable());
43351 if(panel.tabTip !== undefined){
43352 ti.setTooltip(panel.tabTip);
43354 ti.on("activate", function(){
43355 this.setActivePanel(panel);
43357 if(this.config.closeOnTab){
43358 ti.on("beforeclose", function(t, e){
43360 this.remove(panel);
43366 updatePanelTitle : function(panel, title){
43367 if(this.activePanel == panel){
43368 this.updateTitle(title);
43371 var ti = this.tabs.getTab(panel.getEl().id);
43373 if(panel.tabTip !== undefined){
43374 ti.setTooltip(panel.tabTip);
43379 updateTitle : function(title){
43380 if(this.titleTextEl && !this.config.title){
43381 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
43385 setActivePanel : function(panel){
43386 panel = this.getPanel(panel);
43387 if(this.activePanel && this.activePanel != panel){
43388 this.activePanel.setActiveState(false);
43390 this.activePanel = panel;
43391 panel.setActiveState(true);
43392 if(this.panelSize){
43393 panel.setSize(this.panelSize.width, this.panelSize.height);
43396 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
43398 this.updateTitle(panel.getTitle());
43400 this.fireEvent("invalidated", this);
43402 this.fireEvent("panelactivated", this, panel);
43406 * Shows the specified panel.
43407 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
43408 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
43410 showPanel : function(panel){
43411 if(panel = this.getPanel(panel)){
43413 var tab = this.tabs.getTab(panel.getEl().id);
43414 if(tab.isHidden()){
43415 this.tabs.unhideTab(tab.id);
43419 this.setActivePanel(panel);
43426 * Get the active panel for this region.
43427 * @return {Roo.ContentPanel} The active panel or null
43429 getActivePanel : function(){
43430 return this.activePanel;
43433 validateVisibility : function(){
43434 if(this.panels.getCount() < 1){
43435 this.updateTitle(" ");
43436 this.closeBtn.hide();
43439 if(!this.isVisible()){
43446 * Adds the passed ContentPanel(s) to this region.
43447 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43448 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
43450 add : function(panel){
43451 if(arguments.length > 1){
43452 for(var i = 0, len = arguments.length; i < len; i++) {
43453 this.add(arguments[i]);
43457 if(this.hasPanel(panel)){
43458 this.showPanel(panel);
43461 panel.setRegion(this);
43462 this.panels.add(panel);
43463 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
43464 this.bodyEl.dom.appendChild(panel.getEl().dom);
43465 if(panel.background !== true){
43466 this.setActivePanel(panel);
43468 this.fireEvent("paneladded", this, panel);
43474 this.initPanelAsTab(panel);
43476 if(panel.background !== true){
43477 this.tabs.activate(panel.getEl().id);
43479 this.fireEvent("paneladded", this, panel);
43484 * Hides the tab for the specified panel.
43485 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43487 hidePanel : function(panel){
43488 if(this.tabs && (panel = this.getPanel(panel))){
43489 this.tabs.hideTab(panel.getEl().id);
43494 * Unhides the tab for a previously hidden panel.
43495 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43497 unhidePanel : function(panel){
43498 if(this.tabs && (panel = this.getPanel(panel))){
43499 this.tabs.unhideTab(panel.getEl().id);
43503 clearPanels : function(){
43504 while(this.panels.getCount() > 0){
43505 this.remove(this.panels.first());
43510 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
43511 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43512 * @param {Boolean} preservePanel Overrides the config preservePanel option
43513 * @return {Roo.ContentPanel} The panel that was removed
43515 remove : function(panel, preservePanel){
43516 panel = this.getPanel(panel);
43521 this.fireEvent("beforeremove", this, panel, e);
43522 if(e.cancel === true){
43525 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
43526 var panelId = panel.getId();
43527 this.panels.removeKey(panelId);
43529 document.body.appendChild(panel.getEl().dom);
43532 this.tabs.removeTab(panel.getEl().id);
43533 }else if (!preservePanel){
43534 this.bodyEl.dom.removeChild(panel.getEl().dom);
43536 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
43537 var p = this.panels.first();
43538 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
43539 tempEl.appendChild(p.getEl().dom);
43540 this.bodyEl.update("");
43541 this.bodyEl.dom.appendChild(p.getEl().dom);
43543 this.updateTitle(p.getTitle());
43545 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43546 this.setActivePanel(p);
43548 panel.setRegion(null);
43549 if(this.activePanel == panel){
43550 this.activePanel = null;
43552 if(this.config.autoDestroy !== false && preservePanel !== true){
43553 try{panel.destroy();}catch(e){}
43555 this.fireEvent("panelremoved", this, panel);
43560 * Returns the TabPanel component used by this region
43561 * @return {Roo.TabPanel}
43563 getTabs : function(){
43567 createTool : function(parentEl, className){
43568 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
43569 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
43570 btn.addClassOnOver("x-layout-tools-button-over");
43575 * Ext JS Library 1.1.1
43576 * Copyright(c) 2006-2007, Ext JS, LLC.
43578 * Originally Released Under LGPL - original licence link has changed is not relivant.
43581 * <script type="text/javascript">
43587 * @class Roo.SplitLayoutRegion
43588 * @extends Roo.LayoutRegion
43589 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
43591 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
43592 this.cursor = cursor;
43593 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
43596 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
43597 splitTip : "Drag to resize.",
43598 collapsibleSplitTip : "Drag to resize. Double click to hide.",
43599 useSplitTips : false,
43601 applyConfig : function(config){
43602 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
43605 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
43606 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
43607 /** The SplitBar for this region
43608 * @type Roo.SplitBar */
43609 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
43610 this.split.on("moved", this.onSplitMove, this);
43611 this.split.useShim = config.useShim === true;
43612 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
43613 if(this.useSplitTips){
43614 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
43616 if(config.collapsible){
43617 this.split.el.on("dblclick", this.collapse, this);
43620 if(typeof config.minSize != "undefined"){
43621 this.split.minSize = config.minSize;
43623 if(typeof config.maxSize != "undefined"){
43624 this.split.maxSize = config.maxSize;
43626 if(config.hideWhenEmpty || config.hidden || config.collapsed){
43627 this.hideSplitter();
43632 getHMaxSize : function(){
43633 var cmax = this.config.maxSize || 10000;
43634 var center = this.mgr.getRegion("center");
43635 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
43638 getVMaxSize : function(){
43639 var cmax = this.config.maxSize || 10000;
43640 var center = this.mgr.getRegion("center");
43641 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
43644 onSplitMove : function(split, newSize){
43645 this.fireEvent("resized", this, newSize);
43649 * Returns the {@link Roo.SplitBar} for this region.
43650 * @return {Roo.SplitBar}
43652 getSplitBar : function(){
43657 this.hideSplitter();
43658 Roo.SplitLayoutRegion.superclass.hide.call(this);
43661 hideSplitter : function(){
43663 this.split.el.setLocation(-2000,-2000);
43664 this.split.el.hide();
43670 this.split.el.show();
43672 Roo.SplitLayoutRegion.superclass.show.call(this);
43675 beforeSlide: function(){
43676 if(Roo.isGecko){// firefox overflow auto bug workaround
43677 this.bodyEl.clip();
43678 if(this.tabs) this.tabs.bodyEl.clip();
43679 if(this.activePanel){
43680 this.activePanel.getEl().clip();
43682 if(this.activePanel.beforeSlide){
43683 this.activePanel.beforeSlide();
43689 afterSlide : function(){
43690 if(Roo.isGecko){// firefox overflow auto bug workaround
43691 this.bodyEl.unclip();
43692 if(this.tabs) this.tabs.bodyEl.unclip();
43693 if(this.activePanel){
43694 this.activePanel.getEl().unclip();
43695 if(this.activePanel.afterSlide){
43696 this.activePanel.afterSlide();
43702 initAutoHide : function(){
43703 if(this.autoHide !== false){
43704 if(!this.autoHideHd){
43705 var st = new Roo.util.DelayedTask(this.slideIn, this);
43706 this.autoHideHd = {
43707 "mouseout": function(e){
43708 if(!e.within(this.el, true)){
43712 "mouseover" : function(e){
43718 this.el.on(this.autoHideHd);
43722 clearAutoHide : function(){
43723 if(this.autoHide !== false){
43724 this.el.un("mouseout", this.autoHideHd.mouseout);
43725 this.el.un("mouseover", this.autoHideHd.mouseover);
43729 clearMonitor : function(){
43730 Roo.get(document).un("click", this.slideInIf, this);
43733 // these names are backwards but not changed for compat
43734 slideOut : function(){
43735 if(this.isSlid || this.el.hasActiveFx()){
43738 this.isSlid = true;
43739 if(this.collapseBtn){
43740 this.collapseBtn.hide();
43742 this.closeBtnState = this.closeBtn.getStyle('display');
43743 this.closeBtn.hide();
43745 this.stickBtn.show();
43748 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
43749 this.beforeSlide();
43750 this.el.setStyle("z-index", 10001);
43751 this.el.slideIn(this.getSlideAnchor(), {
43752 callback: function(){
43754 this.initAutoHide();
43755 Roo.get(document).on("click", this.slideInIf, this);
43756 this.fireEvent("slideshow", this);
43763 afterSlideIn : function(){
43764 this.clearAutoHide();
43765 this.isSlid = false;
43766 this.clearMonitor();
43767 this.el.setStyle("z-index", "");
43768 if(this.collapseBtn){
43769 this.collapseBtn.show();
43771 this.closeBtn.setStyle('display', this.closeBtnState);
43773 this.stickBtn.hide();
43775 this.fireEvent("slidehide", this);
43778 slideIn : function(cb){
43779 if(!this.isSlid || this.el.hasActiveFx()){
43783 this.isSlid = false;
43784 this.beforeSlide();
43785 this.el.slideOut(this.getSlideAnchor(), {
43786 callback: function(){
43787 this.el.setLeftTop(-10000, -10000);
43789 this.afterSlideIn();
43797 slideInIf : function(e){
43798 if(!e.within(this.el)){
43803 animateCollapse : function(){
43804 this.beforeSlide();
43805 this.el.setStyle("z-index", 20000);
43806 var anchor = this.getSlideAnchor();
43807 this.el.slideOut(anchor, {
43808 callback : function(){
43809 this.el.setStyle("z-index", "");
43810 this.collapsedEl.slideIn(anchor, {duration:.3});
43812 this.el.setLocation(-10000,-10000);
43814 this.fireEvent("collapsed", this);
43821 animateExpand : function(){
43822 this.beforeSlide();
43823 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
43824 this.el.setStyle("z-index", 20000);
43825 this.collapsedEl.hide({
43828 this.el.slideIn(this.getSlideAnchor(), {
43829 callback : function(){
43830 this.el.setStyle("z-index", "");
43833 this.split.el.show();
43835 this.fireEvent("invalidated", this);
43836 this.fireEvent("expanded", this);
43864 getAnchor : function(){
43865 return this.anchors[this.position];
43868 getCollapseAnchor : function(){
43869 return this.canchors[this.position];
43872 getSlideAnchor : function(){
43873 return this.sanchors[this.position];
43876 getAlignAdj : function(){
43877 var cm = this.cmargins;
43878 switch(this.position){
43894 getExpandAdj : function(){
43895 var c = this.collapsedEl, cm = this.cmargins;
43896 switch(this.position){
43898 return [-(cm.right+c.getWidth()+cm.left), 0];
43901 return [cm.right+c.getWidth()+cm.left, 0];
43904 return [0, -(cm.top+cm.bottom+c.getHeight())];
43907 return [0, cm.top+cm.bottom+c.getHeight()];
43913 * Ext JS Library 1.1.1
43914 * Copyright(c) 2006-2007, Ext JS, LLC.
43916 * Originally Released Under LGPL - original licence link has changed is not relivant.
43919 * <script type="text/javascript">
43922 * These classes are private internal classes
43924 Roo.CenterLayoutRegion = function(mgr, config){
43925 Roo.LayoutRegion.call(this, mgr, config, "center");
43926 this.visible = true;
43927 this.minWidth = config.minWidth || 20;
43928 this.minHeight = config.minHeight || 20;
43931 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
43933 // center panel can't be hidden
43937 // center panel can't be hidden
43940 getMinWidth: function(){
43941 return this.minWidth;
43944 getMinHeight: function(){
43945 return this.minHeight;
43950 Roo.NorthLayoutRegion = function(mgr, config){
43951 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
43953 this.split.placement = Roo.SplitBar.TOP;
43954 this.split.orientation = Roo.SplitBar.VERTICAL;
43955 this.split.el.addClass("x-layout-split-v");
43957 var size = config.initialSize || config.height;
43958 if(typeof size != "undefined"){
43959 this.el.setHeight(size);
43962 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
43963 orientation: Roo.SplitBar.VERTICAL,
43964 getBox : function(){
43965 if(this.collapsed){
43966 return this.collapsedEl.getBox();
43968 var box = this.el.getBox();
43970 box.height += this.split.el.getHeight();
43975 updateBox : function(box){
43976 if(this.split && !this.collapsed){
43977 box.height -= this.split.el.getHeight();
43978 this.split.el.setLeft(box.x);
43979 this.split.el.setTop(box.y+box.height);
43980 this.split.el.setWidth(box.width);
43982 if(this.collapsed){
43983 this.updateBody(box.width, null);
43985 Roo.LayoutRegion.prototype.updateBox.call(this, box);
43989 Roo.SouthLayoutRegion = function(mgr, config){
43990 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
43992 this.split.placement = Roo.SplitBar.BOTTOM;
43993 this.split.orientation = Roo.SplitBar.VERTICAL;
43994 this.split.el.addClass("x-layout-split-v");
43996 var size = config.initialSize || config.height;
43997 if(typeof size != "undefined"){
43998 this.el.setHeight(size);
44001 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
44002 orientation: Roo.SplitBar.VERTICAL,
44003 getBox : function(){
44004 if(this.collapsed){
44005 return this.collapsedEl.getBox();
44007 var box = this.el.getBox();
44009 var sh = this.split.el.getHeight();
44016 updateBox : function(box){
44017 if(this.split && !this.collapsed){
44018 var sh = this.split.el.getHeight();
44021 this.split.el.setLeft(box.x);
44022 this.split.el.setTop(box.y-sh);
44023 this.split.el.setWidth(box.width);
44025 if(this.collapsed){
44026 this.updateBody(box.width, null);
44028 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44032 Roo.EastLayoutRegion = function(mgr, config){
44033 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
44035 this.split.placement = Roo.SplitBar.RIGHT;
44036 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44037 this.split.el.addClass("x-layout-split-h");
44039 var size = config.initialSize || config.width;
44040 if(typeof size != "undefined"){
44041 this.el.setWidth(size);
44044 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
44045 orientation: Roo.SplitBar.HORIZONTAL,
44046 getBox : function(){
44047 if(this.collapsed){
44048 return this.collapsedEl.getBox();
44050 var box = this.el.getBox();
44052 var sw = this.split.el.getWidth();
44059 updateBox : function(box){
44060 if(this.split && !this.collapsed){
44061 var sw = this.split.el.getWidth();
44063 this.split.el.setLeft(box.x);
44064 this.split.el.setTop(box.y);
44065 this.split.el.setHeight(box.height);
44068 if(this.collapsed){
44069 this.updateBody(null, box.height);
44071 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44075 Roo.WestLayoutRegion = function(mgr, config){
44076 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
44078 this.split.placement = Roo.SplitBar.LEFT;
44079 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44080 this.split.el.addClass("x-layout-split-h");
44082 var size = config.initialSize || config.width;
44083 if(typeof size != "undefined"){
44084 this.el.setWidth(size);
44087 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
44088 orientation: Roo.SplitBar.HORIZONTAL,
44089 getBox : function(){
44090 if(this.collapsed){
44091 return this.collapsedEl.getBox();
44093 var box = this.el.getBox();
44095 box.width += this.split.el.getWidth();
44100 updateBox : function(box){
44101 if(this.split && !this.collapsed){
44102 var sw = this.split.el.getWidth();
44104 this.split.el.setLeft(box.x+box.width);
44105 this.split.el.setTop(box.y);
44106 this.split.el.setHeight(box.height);
44108 if(this.collapsed){
44109 this.updateBody(null, box.height);
44111 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44116 * Ext JS Library 1.1.1
44117 * Copyright(c) 2006-2007, Ext JS, LLC.
44119 * Originally Released Under LGPL - original licence link has changed is not relivant.
44122 * <script type="text/javascript">
44127 * Private internal class for reading and applying state
44129 Roo.LayoutStateManager = function(layout){
44130 // default empty state
44139 Roo.LayoutStateManager.prototype = {
44140 init : function(layout, provider){
44141 this.provider = provider;
44142 var state = provider.get(layout.id+"-layout-state");
44144 var wasUpdating = layout.isUpdating();
44146 layout.beginUpdate();
44148 for(var key in state){
44149 if(typeof state[key] != "function"){
44150 var rstate = state[key];
44151 var r = layout.getRegion(key);
44154 r.resizeTo(rstate.size);
44156 if(rstate.collapsed == true){
44159 r.expand(null, true);
44165 layout.endUpdate();
44167 this.state = state;
44169 this.layout = layout;
44170 layout.on("regionresized", this.onRegionResized, this);
44171 layout.on("regioncollapsed", this.onRegionCollapsed, this);
44172 layout.on("regionexpanded", this.onRegionExpanded, this);
44175 storeState : function(){
44176 this.provider.set(this.layout.id+"-layout-state", this.state);
44179 onRegionResized : function(region, newSize){
44180 this.state[region.getPosition()].size = newSize;
44184 onRegionCollapsed : function(region){
44185 this.state[region.getPosition()].collapsed = true;
44189 onRegionExpanded : function(region){
44190 this.state[region.getPosition()].collapsed = false;
44195 * Ext JS Library 1.1.1
44196 * Copyright(c) 2006-2007, Ext JS, LLC.
44198 * Originally Released Under LGPL - original licence link has changed is not relivant.
44201 * <script type="text/javascript">
44204 * @class Roo.ContentPanel
44205 * @extends Roo.util.Observable
44206 * A basic ContentPanel element.
44207 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
44208 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
44209 * @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
44210 * @cfg {Boolean} closable True if the panel can be closed/removed
44211 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
44212 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
44213 * @cfg {Toolbar} toolbar A toolbar for this panel
44214 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
44215 * @cfg {String} title The title for this panel
44216 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
44217 * @cfg {String} url Calls {@link #setUrl} with this value
44218 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
44219 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
44221 * Create a new ContentPanel.
44222 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
44223 * @param {String/Object} config A string to set only the title or a config object
44224 * @param {String} content (optional) Set the HTML content for this panel
44225 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
44227 Roo.ContentPanel = function(el, config, content){
44231 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
44235 if (config && config.parentLayout) {
44236 el = config.parentLayout.el.createChild();
44239 if(el.autoCreate){ // xtype is available if this is called from factory
44243 this.el = Roo.get(el);
44244 if(!this.el && config && config.autoCreate){
44245 if(typeof config.autoCreate == "object"){
44246 if(!config.autoCreate.id){
44247 config.autoCreate.id = config.id||el;
44249 this.el = Roo.DomHelper.append(document.body,
44250 config.autoCreate, true);
44252 this.el = Roo.DomHelper.append(document.body,
44253 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
44256 this.closable = false;
44257 this.loaded = false;
44258 this.active = false;
44259 if(typeof config == "string"){
44260 this.title = config;
44262 Roo.apply(this, config);
44265 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
44266 this.wrapEl = this.el.wrap();
44267 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
44274 this.resizeEl = Roo.get(this.resizeEl, true);
44276 this.resizeEl = this.el;
44281 * Fires when this panel is activated.
44282 * @param {Roo.ContentPanel} this
44286 * @event deactivate
44287 * Fires when this panel is activated.
44288 * @param {Roo.ContentPanel} this
44290 "deactivate" : true,
44294 * Fires when this panel is resized if fitToFrame is true.
44295 * @param {Roo.ContentPanel} this
44296 * @param {Number} width The width after any component adjustments
44297 * @param {Number} height The height after any component adjustments
44301 if(this.autoScroll){
44302 this.resizeEl.setStyle("overflow", "auto");
44304 content = content || this.content;
44306 this.setContent(content);
44308 if(config && config.url){
44309 this.setUrl(this.url, this.params, this.loadOnce);
44314 Roo.ContentPanel.superclass.constructor.call(this);
44317 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
44319 setRegion : function(region){
44320 this.region = region;
44322 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
44324 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
44329 * Returns the toolbar for this Panel if one was configured.
44330 * @return {Roo.Toolbar}
44332 getToolbar : function(){
44333 return this.toolbar;
44336 setActiveState : function(active){
44337 this.active = active;
44339 this.fireEvent("deactivate", this);
44341 this.fireEvent("activate", this);
44345 * Updates this panel's element
44346 * @param {String} content The new content
44347 * @param {Boolean} loadScripts (optional) true to look for and process scripts
44349 setContent : function(content, loadScripts){
44350 this.el.update(content, loadScripts);
44353 ignoreResize : function(w, h){
44354 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
44357 this.lastSize = {width: w, height: h};
44362 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
44363 * @return {Roo.UpdateManager} The UpdateManager
44365 getUpdateManager : function(){
44366 return this.el.getUpdateManager();
44369 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
44370 * @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:
44373 url: "your-url.php",
44374 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
44375 callback: yourFunction,
44376 scope: yourObject, //(optional scope)
44379 text: "Loading...",
44384 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
44385 * 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.
44386 * @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}
44387 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
44388 * @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.
44389 * @return {Roo.ContentPanel} this
44392 var um = this.el.getUpdateManager();
44393 um.update.apply(um, arguments);
44399 * 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.
44400 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
44401 * @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)
44402 * @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)
44403 * @return {Roo.UpdateManager} The UpdateManager
44405 setUrl : function(url, params, loadOnce){
44406 if(this.refreshDelegate){
44407 this.removeListener("activate", this.refreshDelegate);
44409 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
44410 this.on("activate", this.refreshDelegate);
44411 return this.el.getUpdateManager();
44414 _handleRefresh : function(url, params, loadOnce){
44415 if(!loadOnce || !this.loaded){
44416 var updater = this.el.getUpdateManager();
44417 updater.update(url, params, this._setLoaded.createDelegate(this));
44421 _setLoaded : function(){
44422 this.loaded = true;
44426 * Returns this panel's id
44429 getId : function(){
44434 * Returns this panel's element - used by regiosn to add.
44435 * @return {Roo.Element}
44437 getEl : function(){
44438 return this.wrapEl || this.el;
44441 adjustForComponents : function(width, height){
44442 if(this.resizeEl != this.el){
44443 width -= this.el.getFrameWidth('lr');
44444 height -= this.el.getFrameWidth('tb');
44447 var te = this.toolbar.getEl();
44448 height -= te.getHeight();
44449 te.setWidth(width);
44451 if(this.adjustments){
44452 width += this.adjustments[0];
44453 height += this.adjustments[1];
44455 return {"width": width, "height": height};
44458 setSize : function(width, height){
44459 if(this.fitToFrame && !this.ignoreResize(width, height)){
44460 if(this.fitContainer && this.resizeEl != this.el){
44461 this.el.setSize(width, height);
44463 var size = this.adjustForComponents(width, height);
44464 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
44465 this.fireEvent('resize', this, size.width, size.height);
44470 * Returns this panel's title
44473 getTitle : function(){
44478 * Set this panel's title
44479 * @param {String} title
44481 setTitle : function(title){
44482 this.title = title;
44484 this.region.updatePanelTitle(this, title);
44489 * Returns true is this panel was configured to be closable
44490 * @return {Boolean}
44492 isClosable : function(){
44493 return this.closable;
44496 beforeSlide : function(){
44498 this.resizeEl.clip();
44501 afterSlide : function(){
44503 this.resizeEl.unclip();
44507 * Force a content refresh from the URL specified in the {@link #setUrl} method.
44508 * Will fail silently if the {@link #setUrl} method has not been called.
44509 * This does not activate the panel, just updates its content.
44511 refresh : function(){
44512 if(this.refreshDelegate){
44513 this.loaded = false;
44514 this.refreshDelegate();
44519 * Destroys this panel
44521 destroy : function(){
44522 this.el.removeAllListeners();
44523 var tempEl = document.createElement("span");
44524 tempEl.appendChild(this.el.dom);
44525 tempEl.innerHTML = "";
44531 * Adds a xtype elements to the panel - currently only supports Forms.
44541 * @param {Object} cfg Xtype definition of item to add.
44544 addxtype : function(cfg) {
44546 if (!cfg.xtype.match(/^Form$/)) {
44549 var el = this.el.createChild();
44551 this.form = new Roo.form.Form(cfg);
44554 if ( this.form.allItems.length) this.form.render(el.dom);
44561 * @class Roo.GridPanel
44562 * @extends Roo.ContentPanel
44564 * Create a new GridPanel.
44565 * @param {Roo.grid.Grid} grid The grid for this panel
44566 * @param {String/Object} config A string to set only the panel's title, or a config object
44568 Roo.GridPanel = function(grid, config){
44571 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
44572 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
44574 this.wrapper.dom.appendChild(grid.getGridEl().dom);
44576 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
44579 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
44581 // xtype created footer. - not sure if will work as we normally have to render first..
44582 if (this.footer && !this.footer.el && this.footer.xtype) {
44584 this.footer.container = this.grid.getView().getFooterPanel(true);
44585 this.footer.dataSource = this.grid.dataSource;
44586 this.footer = Roo.factory(this.footer, Roo);
44590 grid.monitorWindowResize = false; // turn off autosizing
44591 grid.autoHeight = false;
44592 grid.autoWidth = false;
44594 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
44597 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
44598 getId : function(){
44599 return this.grid.id;
44603 * Returns the grid for this panel
44604 * @return {Roo.grid.Grid}
44606 getGrid : function(){
44610 setSize : function(width, height){
44611 if(!this.ignoreResize(width, height)){
44612 var grid = this.grid;
44613 var size = this.adjustForComponents(width, height);
44614 grid.getGridEl().setSize(size.width, size.height);
44619 beforeSlide : function(){
44620 this.grid.getView().scroller.clip();
44623 afterSlide : function(){
44624 this.grid.getView().scroller.unclip();
44627 destroy : function(){
44628 this.grid.destroy();
44630 Roo.GridPanel.superclass.destroy.call(this);
44636 * @class Roo.NestedLayoutPanel
44637 * @extends Roo.ContentPanel
44639 * Create a new NestedLayoutPanel.
44642 * @param {Roo.BorderLayout} layout The layout for this panel
44643 * @param {String/Object} config A string to set only the title or a config object
44645 Roo.NestedLayoutPanel = function(layout, config)
44647 // construct with only one argument..
44648 /* FIXME - implement nicer consturctors
44649 if (layout.layout) {
44651 layout = config.layout;
44652 delete config.layout;
44654 if (layout.xtype && !layout.getEl) {
44655 // then layout needs constructing..
44656 layout = Roo.factory(layout, Roo);
44660 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
44662 layout.monitorWindowResize = false; // turn off autosizing
44663 this.layout = layout;
44664 this.layout.getEl().addClass("x-layout-nested-layout");
44670 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
44672 setSize : function(width, height){
44673 if(!this.ignoreResize(width, height)){
44674 var size = this.adjustForComponents(width, height);
44675 var el = this.layout.getEl();
44676 el.setSize(size.width, size.height);
44677 var touch = el.dom.offsetWidth;
44678 this.layout.layout();
44679 // ie requires a double layout on the first pass
44680 if(Roo.isIE && !this.initialized){
44681 this.initialized = true;
44682 this.layout.layout();
44687 // activate all subpanels if not currently active..
44689 setActiveState : function(active){
44690 this.active = active;
44692 this.fireEvent("deactivate", this);
44696 this.fireEvent("activate", this);
44697 // not sure if this should happen before or after..
44698 if (!this.layout) {
44699 return; // should not happen..
44702 for (var r in this.layout.regions) {
44703 reg = this.layout.getRegion(r);
44704 if (reg.getActivePanel()) {
44705 //reg.showPanel(reg.getActivePanel()); // force it to activate..
44706 reg.setActivePanel(reg.getActivePanel());
44709 if (!reg.panels.length) {
44712 reg.showPanel(reg.getPanel(0));
44721 * Returns the nested BorderLayout for this panel
44722 * @return {Roo.BorderLayout}
44724 getLayout : function(){
44725 return this.layout;
44729 * Adds a xtype elements to the layout of the nested panel
44733 xtype : 'ContentPanel',
44740 xtype : 'NestedLayoutPanel',
44746 items : [ ... list of content panels or nested layout panels.. ]
44750 * @param {Object} cfg Xtype definition of item to add.
44752 addxtype : function(cfg) {
44753 return this.layout.addxtype(cfg);
44758 Roo.ScrollPanel = function(el, config, content){
44759 config = config || {};
44760 config.fitToFrame = true;
44761 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
44763 this.el.dom.style.overflow = "hidden";
44764 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
44765 this.el.removeClass("x-layout-inactive-content");
44766 this.el.on("mousewheel", this.onWheel, this);
44768 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
44769 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
44770 up.unselectable(); down.unselectable();
44771 up.on("click", this.scrollUp, this);
44772 down.on("click", this.scrollDown, this);
44773 up.addClassOnOver("x-scroller-btn-over");
44774 down.addClassOnOver("x-scroller-btn-over");
44775 up.addClassOnClick("x-scroller-btn-click");
44776 down.addClassOnClick("x-scroller-btn-click");
44777 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
44779 this.resizeEl = this.el;
44780 this.el = wrap; this.up = up; this.down = down;
44783 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
44785 wheelIncrement : 5,
44786 scrollUp : function(){
44787 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
44790 scrollDown : function(){
44791 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
44794 afterScroll : function(){
44795 var el = this.resizeEl;
44796 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
44797 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44798 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44801 setSize : function(){
44802 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
44803 this.afterScroll();
44806 onWheel : function(e){
44807 var d = e.getWheelDelta();
44808 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
44809 this.afterScroll();
44813 setContent : function(content, loadScripts){
44814 this.resizeEl.update(content, loadScripts);
44828 * @class Roo.TreePanel
44829 * @extends Roo.ContentPanel
44831 * Create a new TreePanel.
44832 * @param {String/Object} config A string to set only the panel's title, or a config object
44833 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
44835 Roo.TreePanel = function(config){
44836 var el = config.el;
44837 var tree = config.tree;
44838 delete config.tree;
44839 delete config.el; // hopefull!
44840 Roo.TreePanel.superclass.constructor.call(this, el, config);
44841 var treeEl = el.createChild();
44842 this.tree = new Roo.tree.TreePanel(treeEl , tree);
44843 //console.log(tree);
44844 this.on('activate', function()
44846 if (this.tree.rendered) {
44849 //console.log('render tree');
44850 this.tree.render();
44853 this.on('resize', function (cp, w, h) {
44854 this.tree.innerCt.setWidth(w);
44855 this.tree.innerCt.setHeight(h);
44856 this.tree.innerCt.setStyle('overflow-y', 'auto');
44863 Roo.extend(Roo.TreePanel, Roo.ContentPanel);
44877 * Ext JS Library 1.1.1
44878 * Copyright(c) 2006-2007, Ext JS, LLC.
44880 * Originally Released Under LGPL - original licence link has changed is not relivant.
44883 * <script type="text/javascript">
44888 * @class Roo.ReaderLayout
44889 * @extends Roo.BorderLayout
44890 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
44891 * center region containing two nested regions (a top one for a list view and one for item preview below),
44892 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
44893 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
44894 * expedites the setup of the overall layout and regions for this common application style.
44897 var reader = new Roo.ReaderLayout();
44898 var CP = Roo.ContentPanel; // shortcut for adding
44900 reader.beginUpdate();
44901 reader.add("north", new CP("north", "North"));
44902 reader.add("west", new CP("west", {title: "West"}));
44903 reader.add("east", new CP("east", {title: "East"}));
44905 reader.regions.listView.add(new CP("listView", "List"));
44906 reader.regions.preview.add(new CP("preview", "Preview"));
44907 reader.endUpdate();
44910 * Create a new ReaderLayout
44911 * @param {Object} config Configuration options
44912 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
44913 * document.body if omitted)
44915 Roo.ReaderLayout = function(config, renderTo){
44916 var c = config || {size:{}};
44917 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
44918 north: c.north !== false ? Roo.apply({
44922 }, c.north) : false,
44923 west: c.west !== false ? Roo.apply({
44931 margins:{left:5,right:0,bottom:5,top:5},
44932 cmargins:{left:5,right:5,bottom:5,top:5}
44933 }, c.west) : false,
44934 east: c.east !== false ? Roo.apply({
44942 margins:{left:0,right:5,bottom:5,top:5},
44943 cmargins:{left:5,right:5,bottom:5,top:5}
44944 }, c.east) : false,
44945 center: Roo.apply({
44946 tabPosition: 'top',
44950 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
44954 this.el.addClass('x-reader');
44956 this.beginUpdate();
44958 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
44959 south: c.preview !== false ? Roo.apply({
44966 cmargins:{top:5,left:0, right:0, bottom:0}
44967 }, c.preview) : false,
44968 center: Roo.apply({
44974 this.add('center', new Roo.NestedLayoutPanel(inner,
44975 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
44979 this.regions.preview = inner.getRegion('south');
44980 this.regions.listView = inner.getRegion('center');
44983 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
44985 * Ext JS Library 1.1.1
44986 * Copyright(c) 2006-2007, Ext JS, LLC.
44988 * Originally Released Under LGPL - original licence link has changed is not relivant.
44991 * <script type="text/javascript">
44995 * @class Roo.grid.Grid
44996 * @extends Roo.util.Observable
44997 * This class represents the primary interface of a component based grid control.
44998 * <br><br>Usage:<pre><code>
44999 var grid = new Roo.grid.Grid("my-container-id", {
45002 selModel: mySelectionModel,
45003 autoSizeColumns: true,
45004 monitorWindowResize: false,
45005 trackMouseOver: true
45010 * <b>Common Problems:</b><br/>
45011 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
45012 * element will correct this<br/>
45013 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
45014 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
45015 * are unpredictable.<br/>
45016 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
45017 * grid to calculate dimensions/offsets.<br/>
45019 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
45020 * The container MUST have some type of size defined for the grid to fill. The container will be
45021 * automatically set to position relative if it isn't already.
45022 * @param {Object} config A config object that sets properties on this grid.
45024 Roo.grid.Grid = function(container, config){
45025 // initialize the container
45026 this.container = Roo.get(container);
45027 this.container.update("");
45028 this.container.setStyle("overflow", "hidden");
45029 this.container.addClass('x-grid-container');
45031 this.id = this.container.id;
45033 Roo.apply(this, config);
45034 // check and correct shorthanded configs
45036 this.dataSource = this.ds;
45040 this.colModel = this.cm;
45044 this.selModel = this.sm;
45048 if (this.selModel) {
45049 this.selModel = Roo.factory(this.selModel, Roo.grid);
45050 this.sm = this.selModel;
45051 this.sm.xmodule = this.xmodule || false;
45053 if (typeof(this.colModel.config) == 'undefined') {
45054 this.colModel = new Roo.grid.ColumnModel(this.colModel);
45055 this.cm = this.colModel;
45056 this.cm.xmodule = this.xmodule || false;
45058 if (this.dataSource) {
45059 this.dataSource= Roo.factory(this.dataSource, Roo.data);
45060 this.ds = this.dataSource;
45061 this.ds.xmodule = this.xmodule || false;
45068 this.container.setWidth(this.width);
45072 this.container.setHeight(this.height);
45079 * The raw click event for the entire grid.
45080 * @param {Roo.EventObject} e
45085 * The raw dblclick event for the entire grid.
45086 * @param {Roo.EventObject} e
45090 * @event contextmenu
45091 * The raw contextmenu event for the entire grid.
45092 * @param {Roo.EventObject} e
45094 "contextmenu" : true,
45097 * The raw mousedown event for the entire grid.
45098 * @param {Roo.EventObject} e
45100 "mousedown" : true,
45103 * The raw mouseup event for the entire grid.
45104 * @param {Roo.EventObject} e
45109 * The raw mouseover event for the entire grid.
45110 * @param {Roo.EventObject} e
45112 "mouseover" : true,
45115 * The raw mouseout event for the entire grid.
45116 * @param {Roo.EventObject} e
45121 * The raw keypress event for the entire grid.
45122 * @param {Roo.EventObject} e
45127 * The raw keydown event for the entire grid.
45128 * @param {Roo.EventObject} e
45136 * Fires when a cell is clicked
45137 * @param {Grid} this
45138 * @param {Number} rowIndex
45139 * @param {Number} columnIndex
45140 * @param {Roo.EventObject} e
45142 "cellclick" : true,
45144 * @event celldblclick
45145 * Fires when a cell is double clicked
45146 * @param {Grid} this
45147 * @param {Number} rowIndex
45148 * @param {Number} columnIndex
45149 * @param {Roo.EventObject} e
45151 "celldblclick" : true,
45154 * Fires when a row is clicked
45155 * @param {Grid} this
45156 * @param {Number} rowIndex
45157 * @param {Roo.EventObject} e
45161 * @event rowdblclick
45162 * Fires when a row is double clicked
45163 * @param {Grid} this
45164 * @param {Number} rowIndex
45165 * @param {Roo.EventObject} e
45167 "rowdblclick" : true,
45169 * @event headerclick
45170 * Fires when a header is clicked
45171 * @param {Grid} this
45172 * @param {Number} columnIndex
45173 * @param {Roo.EventObject} e
45175 "headerclick" : true,
45177 * @event headerdblclick
45178 * Fires when a header cell is double clicked
45179 * @param {Grid} this
45180 * @param {Number} columnIndex
45181 * @param {Roo.EventObject} e
45183 "headerdblclick" : true,
45185 * @event rowcontextmenu
45186 * Fires when a row is right clicked
45187 * @param {Grid} this
45188 * @param {Number} rowIndex
45189 * @param {Roo.EventObject} e
45191 "rowcontextmenu" : true,
45193 * @event cellcontextmenu
45194 * Fires when a cell is right clicked
45195 * @param {Grid} this
45196 * @param {Number} rowIndex
45197 * @param {Number} cellIndex
45198 * @param {Roo.EventObject} e
45200 "cellcontextmenu" : true,
45202 * @event headercontextmenu
45203 * Fires when a header is right clicked
45204 * @param {Grid} this
45205 * @param {Number} columnIndex
45206 * @param {Roo.EventObject} e
45208 "headercontextmenu" : true,
45210 * @event bodyscroll
45211 * Fires when the body element is scrolled
45212 * @param {Number} scrollLeft
45213 * @param {Number} scrollTop
45215 "bodyscroll" : true,
45217 * @event columnresize
45218 * Fires when the user resizes a column
45219 * @param {Number} columnIndex
45220 * @param {Number} newSize
45222 "columnresize" : true,
45224 * @event columnmove
45225 * Fires when the user moves a column
45226 * @param {Number} oldIndex
45227 * @param {Number} newIndex
45229 "columnmove" : true,
45232 * Fires when row(s) start being dragged
45233 * @param {Grid} this
45234 * @param {Roo.GridDD} dd The drag drop object
45235 * @param {event} e The raw browser event
45237 "startdrag" : true,
45240 * Fires when a drag operation is complete
45241 * @param {Grid} this
45242 * @param {Roo.GridDD} dd The drag drop object
45243 * @param {event} e The raw browser event
45248 * Fires when dragged row(s) are dropped on a valid DD target
45249 * @param {Grid} this
45250 * @param {Roo.GridDD} dd The drag drop object
45251 * @param {String} targetId The target drag drop object
45252 * @param {event} e The raw browser event
45257 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
45258 * @param {Grid} this
45259 * @param {Roo.GridDD} dd The drag drop object
45260 * @param {String} targetId The target drag drop object
45261 * @param {event} e The raw browser event
45266 * Fires when the dragged row(s) first cross another DD target while being dragged
45267 * @param {Grid} this
45268 * @param {Roo.GridDD} dd The drag drop object
45269 * @param {String} targetId The target drag drop object
45270 * @param {event} e The raw browser event
45272 "dragenter" : true,
45275 * Fires when the dragged row(s) leave another DD target while being dragged
45276 * @param {Grid} this
45277 * @param {Roo.GridDD} dd The drag drop object
45278 * @param {String} targetId The target drag drop object
45279 * @param {event} e The raw browser event
45284 * Fires when the grid is rendered
45285 * @param {Grid} grid
45290 Roo.grid.Grid.superclass.constructor.call(this);
45292 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
45294 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
45296 minColumnWidth : 25,
45299 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
45300 * <b>on initial render.</b> It is more efficient to explicitly size the columns
45301 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
45303 autoSizeColumns : false,
45306 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
45308 autoSizeHeaders : true,
45311 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
45313 monitorWindowResize : true,
45316 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
45317 * rows measured to get a columns size. Default is 0 (all rows).
45319 maxRowsToMeasure : 0,
45322 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
45324 trackMouseOver : true,
45327 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
45329 enableDragDrop : false,
45332 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
45334 enableColumnMove : true,
45337 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
45339 enableColumnHide : true,
45342 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
45344 enableRowHeightSync : false,
45347 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
45352 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
45354 autoHeight : false,
45357 * @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.
45359 autoExpandColumn : false,
45362 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
45365 autoExpandMin : 50,
45368 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
45370 autoExpandMax : 1000,
45373 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
45378 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
45386 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
45387 * of a fixed width. Default is false.
45390 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
45393 * Called once after all setup has been completed and the grid is ready to be rendered.
45394 * @return {Roo.grid.Grid} this
45396 render : function(){
45397 var c = this.container;
45398 // try to detect autoHeight/width mode
45399 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
45400 this.autoHeight = true;
45402 var view = this.getView();
45405 c.on("click", this.onClick, this);
45406 c.on("dblclick", this.onDblClick, this);
45407 c.on("contextmenu", this.onContextMenu, this);
45408 c.on("keydown", this.onKeyDown, this);
45410 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
45412 this.getSelectionModel().init(this);
45417 this.loadMask = new Roo.LoadMask(this.container,
45418 Roo.apply({store:this.dataSource}, this.loadMask));
45422 if (this.toolbar && this.toolbar.xtype) {
45423 this.toolbar.container = this.getView().getHeaderPanel(true);
45424 this.toolbar = new Ext.Toolbar(this.toolbar);
45426 if (this.footer && this.footer.xtype) {
45427 this.footer.dataSource = this.getDataSource();
45428 this.footer.container = this.getView().getFooterPanel(true);
45429 this.footer = Roo.factory(this.footer, Roo);
45431 this.rendered = true;
45432 this.fireEvent('render', this);
45437 * Reconfigures the grid to use a different Store and Column Model.
45438 * The View will be bound to the new objects and refreshed.
45439 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
45440 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
45442 reconfigure : function(dataSource, colModel){
45444 this.loadMask.destroy();
45445 this.loadMask = new Roo.LoadMask(this.container,
45446 Roo.apply({store:dataSource}, this.loadMask));
45448 this.view.bind(dataSource, colModel);
45449 this.dataSource = dataSource;
45450 this.colModel = colModel;
45451 this.view.refresh(true);
45455 onKeyDown : function(e){
45456 this.fireEvent("keydown", e);
45460 * Destroy this grid.
45461 * @param {Boolean} removeEl True to remove the element
45463 destroy : function(removeEl, keepListeners){
45465 this.loadMask.destroy();
45467 var c = this.container;
45468 c.removeAllListeners();
45469 this.view.destroy();
45470 this.colModel.purgeListeners();
45471 if(!keepListeners){
45472 this.purgeListeners();
45475 if(removeEl === true){
45481 processEvent : function(name, e){
45482 this.fireEvent(name, e);
45483 var t = e.getTarget();
45485 var header = v.findHeaderIndex(t);
45486 if(header !== false){
45487 this.fireEvent("header" + name, this, header, e);
45489 var row = v.findRowIndex(t);
45490 var cell = v.findCellIndex(t);
45492 this.fireEvent("row" + name, this, row, e);
45493 if(cell !== false){
45494 this.fireEvent("cell" + name, this, row, cell, e);
45501 onClick : function(e){
45502 this.processEvent("click", e);
45506 onContextMenu : function(e, t){
45507 this.processEvent("contextmenu", e);
45511 onDblClick : function(e){
45512 this.processEvent("dblclick", e);
45516 walkCells : function(row, col, step, fn, scope){
45517 var cm = this.colModel, clen = cm.getColumnCount();
45518 var ds = this.dataSource, rlen = ds.getCount(), first = true;
45530 if(fn.call(scope || this, row, col, cm) === true){
45548 if(fn.call(scope || this, row, col, cm) === true){
45560 getSelections : function(){
45561 return this.selModel.getSelections();
45565 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
45566 * but if manual update is required this method will initiate it.
45568 autoSize : function(){
45570 this.view.layout();
45571 if(this.view.adjustForScroll){
45572 this.view.adjustForScroll();
45578 * Returns the grid's underlying element.
45579 * @return {Element} The element
45581 getGridEl : function(){
45582 return this.container;
45585 // private for compatibility, overridden by editor grid
45586 stopEditing : function(){},
45589 * Returns the grid's SelectionModel.
45590 * @return {SelectionModel}
45592 getSelectionModel : function(){
45593 if(!this.selModel){
45594 this.selModel = new Roo.grid.RowSelectionModel();
45596 return this.selModel;
45600 * Returns the grid's DataSource.
45601 * @return {DataSource}
45603 getDataSource : function(){
45604 return this.dataSource;
45608 * Returns the grid's ColumnModel.
45609 * @return {ColumnModel}
45611 getColumnModel : function(){
45612 return this.colModel;
45616 * Returns the grid's GridView object.
45617 * @return {GridView}
45619 getView : function(){
45621 this.view = new Roo.grid.GridView(this.viewConfig);
45626 * Called to get grid's drag proxy text, by default returns this.ddText.
45629 getDragDropText : function(){
45630 var count = this.selModel.getCount();
45631 return String.format(this.ddText, count, count == 1 ? '' : 's');
45635 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
45636 * %0 is replaced with the number of selected rows.
45639 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
45641 * Ext JS Library 1.1.1
45642 * Copyright(c) 2006-2007, Ext JS, LLC.
45644 * Originally Released Under LGPL - original licence link has changed is not relivant.
45647 * <script type="text/javascript">
45650 Roo.grid.AbstractGridView = function(){
45654 "beforerowremoved" : true,
45655 "beforerowsinserted" : true,
45656 "beforerefresh" : true,
45657 "rowremoved" : true,
45658 "rowsinserted" : true,
45659 "rowupdated" : true,
45662 Roo.grid.AbstractGridView.superclass.constructor.call(this);
45665 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
45666 rowClass : "x-grid-row",
45667 cellClass : "x-grid-cell",
45668 tdClass : "x-grid-td",
45669 hdClass : "x-grid-hd",
45670 splitClass : "x-grid-hd-split",
45672 init: function(grid){
45674 var cid = this.grid.getGridEl().id;
45675 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
45676 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
45677 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
45678 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
45681 getColumnRenderers : function(){
45682 var renderers = [];
45683 var cm = this.grid.colModel;
45684 var colCount = cm.getColumnCount();
45685 for(var i = 0; i < colCount; i++){
45686 renderers[i] = cm.getRenderer(i);
45691 getColumnIds : function(){
45693 var cm = this.grid.colModel;
45694 var colCount = cm.getColumnCount();
45695 for(var i = 0; i < colCount; i++){
45696 ids[i] = cm.getColumnId(i);
45701 getDataIndexes : function(){
45702 if(!this.indexMap){
45703 this.indexMap = this.buildIndexMap();
45705 return this.indexMap.colToData;
45708 getColumnIndexByDataIndex : function(dataIndex){
45709 if(!this.indexMap){
45710 this.indexMap = this.buildIndexMap();
45712 return this.indexMap.dataToCol[dataIndex];
45716 * Set a css style for a column dynamically.
45717 * @param {Number} colIndex The index of the column
45718 * @param {String} name The css property name
45719 * @param {String} value The css value
45721 setCSSStyle : function(colIndex, name, value){
45722 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
45723 Roo.util.CSS.updateRule(selector, name, value);
45726 generateRules : function(cm){
45727 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
45728 Roo.util.CSS.removeStyleSheet(rulesId);
45729 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
45730 var cid = cm.getColumnId(i);
45731 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
45732 this.tdSelector, cid, " {\n}\n",
45733 this.hdSelector, cid, " {\n}\n",
45734 this.splitSelector, cid, " {\n}\n");
45736 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
45740 * Ext JS Library 1.1.1
45741 * Copyright(c) 2006-2007, Ext JS, LLC.
45743 * Originally Released Under LGPL - original licence link has changed is not relivant.
45746 * <script type="text/javascript">
45750 // This is a support class used internally by the Grid components
45751 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
45753 this.view = grid.getView();
45754 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45755 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
45757 this.setHandleElId(Roo.id(hd));
45758 this.setOuterHandleElId(Roo.id(hd2));
45760 this.scroll = false;
45762 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
45764 getDragData : function(e){
45765 var t = Roo.lib.Event.getTarget(e);
45766 var h = this.view.findHeaderCell(t);
45768 return {ddel: h.firstChild, header:h};
45773 onInitDrag : function(e){
45774 this.view.headersDisabled = true;
45775 var clone = this.dragData.ddel.cloneNode(true);
45776 clone.id = Roo.id();
45777 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
45778 this.proxy.update(clone);
45782 afterValidDrop : function(){
45784 setTimeout(function(){
45785 v.headersDisabled = false;
45789 afterInvalidDrop : function(){
45791 setTimeout(function(){
45792 v.headersDisabled = false;
45798 * Ext JS Library 1.1.1
45799 * Copyright(c) 2006-2007, Ext JS, LLC.
45801 * Originally Released Under LGPL - original licence link has changed is not relivant.
45804 * <script type="text/javascript">
45807 // This is a support class used internally by the Grid components
45808 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
45810 this.view = grid.getView();
45811 // split the proxies so they don't interfere with mouse events
45812 this.proxyTop = Roo.DomHelper.append(document.body, {
45813 cls:"col-move-top", html:" "
45815 this.proxyBottom = Roo.DomHelper.append(document.body, {
45816 cls:"col-move-bottom", html:" "
45818 this.proxyTop.hide = this.proxyBottom.hide = function(){
45819 this.setLeftTop(-100,-100);
45820 this.setStyle("visibility", "hidden");
45822 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45823 // temporarily disabled
45824 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
45825 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
45827 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
45828 proxyOffsets : [-4, -9],
45829 fly: Roo.Element.fly,
45831 getTargetFromEvent : function(e){
45832 var t = Roo.lib.Event.getTarget(e);
45833 var cindex = this.view.findCellIndex(t);
45834 if(cindex !== false){
45835 return this.view.getHeaderCell(cindex);
45839 nextVisible : function(h){
45840 var v = this.view, cm = this.grid.colModel;
45843 if(!cm.isHidden(v.getCellIndex(h))){
45851 prevVisible : function(h){
45852 var v = this.view, cm = this.grid.colModel;
45855 if(!cm.isHidden(v.getCellIndex(h))){
45863 positionIndicator : function(h, n, e){
45864 var x = Roo.lib.Event.getPageX(e);
45865 var r = Roo.lib.Dom.getRegion(n.firstChild);
45866 var px, pt, py = r.top + this.proxyOffsets[1];
45867 if((r.right - x) <= (r.right-r.left)/2){
45868 px = r.right+this.view.borderWidth;
45874 var oldIndex = this.view.getCellIndex(h);
45875 var newIndex = this.view.getCellIndex(n);
45877 if(this.grid.colModel.isFixed(newIndex)){
45881 var locked = this.grid.colModel.isLocked(newIndex);
45886 if(oldIndex < newIndex){
45889 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
45892 px += this.proxyOffsets[0];
45893 this.proxyTop.setLeftTop(px, py);
45894 this.proxyTop.show();
45895 if(!this.bottomOffset){
45896 this.bottomOffset = this.view.mainHd.getHeight();
45898 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
45899 this.proxyBottom.show();
45903 onNodeEnter : function(n, dd, e, data){
45904 if(data.header != n){
45905 this.positionIndicator(data.header, n, e);
45909 onNodeOver : function(n, dd, e, data){
45910 var result = false;
45911 if(data.header != n){
45912 result = this.positionIndicator(data.header, n, e);
45915 this.proxyTop.hide();
45916 this.proxyBottom.hide();
45918 return result ? this.dropAllowed : this.dropNotAllowed;
45921 onNodeOut : function(n, dd, e, data){
45922 this.proxyTop.hide();
45923 this.proxyBottom.hide();
45926 onNodeDrop : function(n, dd, e, data){
45927 var h = data.header;
45929 var cm = this.grid.colModel;
45930 var x = Roo.lib.Event.getPageX(e);
45931 var r = Roo.lib.Dom.getRegion(n.firstChild);
45932 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
45933 var oldIndex = this.view.getCellIndex(h);
45934 var newIndex = this.view.getCellIndex(n);
45935 var locked = cm.isLocked(newIndex);
45939 if(oldIndex < newIndex){
45942 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
45945 cm.setLocked(oldIndex, locked, true);
45946 cm.moveColumn(oldIndex, newIndex);
45947 this.grid.fireEvent("columnmove", oldIndex, newIndex);
45955 * Ext JS Library 1.1.1
45956 * Copyright(c) 2006-2007, Ext JS, LLC.
45958 * Originally Released Under LGPL - original licence link has changed is not relivant.
45961 * <script type="text/javascript">
45965 * @class Roo.grid.GridView
45966 * @extends Roo.util.Observable
45969 * @param {Object} config
45971 Roo.grid.GridView = function(config){
45972 Roo.grid.GridView.superclass.constructor.call(this);
45975 Roo.apply(this, config);
45978 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
45981 * Override this function to apply custom css classes to rows during rendering
45982 * @param {Record} record The record
45983 * @param {Number} index
45984 * @method getRowClass
45986 rowClass : "x-grid-row",
45988 cellClass : "x-grid-col",
45990 tdClass : "x-grid-td",
45992 hdClass : "x-grid-hd",
45994 splitClass : "x-grid-split",
45996 sortClasses : ["sort-asc", "sort-desc"],
45998 enableMoveAnim : false,
46002 dh : Roo.DomHelper,
46004 fly : Roo.Element.fly,
46006 css : Roo.util.CSS,
46012 scrollIncrement : 22,
46014 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
46016 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
46018 bind : function(ds, cm){
46020 this.ds.un("load", this.onLoad, this);
46021 this.ds.un("datachanged", this.onDataChange, this);
46022 this.ds.un("add", this.onAdd, this);
46023 this.ds.un("remove", this.onRemove, this);
46024 this.ds.un("update", this.onUpdate, this);
46025 this.ds.un("clear", this.onClear, this);
46028 ds.on("load", this.onLoad, this);
46029 ds.on("datachanged", this.onDataChange, this);
46030 ds.on("add", this.onAdd, this);
46031 ds.on("remove", this.onRemove, this);
46032 ds.on("update", this.onUpdate, this);
46033 ds.on("clear", this.onClear, this);
46038 this.cm.un("widthchange", this.onColWidthChange, this);
46039 this.cm.un("headerchange", this.onHeaderChange, this);
46040 this.cm.un("hiddenchange", this.onHiddenChange, this);
46041 this.cm.un("columnmoved", this.onColumnMove, this);
46042 this.cm.un("columnlockchange", this.onColumnLock, this);
46045 this.generateRules(cm);
46046 cm.on("widthchange", this.onColWidthChange, this);
46047 cm.on("headerchange", this.onHeaderChange, this);
46048 cm.on("hiddenchange", this.onHiddenChange, this);
46049 cm.on("columnmoved", this.onColumnMove, this);
46050 cm.on("columnlockchange", this.onColumnLock, this);
46055 init: function(grid){
46056 Roo.grid.GridView.superclass.init.call(this, grid);
46058 this.bind(grid.dataSource, grid.colModel);
46060 grid.on("headerclick", this.handleHeaderClick, this);
46062 if(grid.trackMouseOver){
46063 grid.on("mouseover", this.onRowOver, this);
46064 grid.on("mouseout", this.onRowOut, this);
46066 grid.cancelTextSelection = function(){};
46067 this.gridId = grid.id;
46069 var tpls = this.templates || {};
46072 tpls.master = new Roo.Template(
46073 '<div class="x-grid" hidefocus="true">',
46074 '<div class="x-grid-topbar"></div>',
46075 '<div class="x-grid-scroller"><div></div></div>',
46076 '<div class="x-grid-locked">',
46077 '<div class="x-grid-header">{lockedHeader}</div>',
46078 '<div class="x-grid-body">{lockedBody}</div>',
46080 '<div class="x-grid-viewport">',
46081 '<div class="x-grid-header">{header}</div>',
46082 '<div class="x-grid-body">{body}</div>',
46084 '<div class="x-grid-bottombar"></div>',
46085 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
46086 '<div class="x-grid-resize-proxy"> </div>',
46089 tpls.master.disableformats = true;
46093 tpls.header = new Roo.Template(
46094 '<table border="0" cellspacing="0" cellpadding="0">',
46095 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
46098 tpls.header.disableformats = true;
46100 tpls.header.compile();
46103 tpls.hcell = new Roo.Template(
46104 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
46105 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
46108 tpls.hcell.disableFormats = true;
46110 tpls.hcell.compile();
46113 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
46114 tpls.hsplit.disableFormats = true;
46116 tpls.hsplit.compile();
46119 tpls.body = new Roo.Template(
46120 '<table border="0" cellspacing="0" cellpadding="0">',
46121 "<tbody>{rows}</tbody>",
46124 tpls.body.disableFormats = true;
46126 tpls.body.compile();
46129 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
46130 tpls.row.disableFormats = true;
46132 tpls.row.compile();
46135 tpls.cell = new Roo.Template(
46136 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
46137 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
46140 tpls.cell.disableFormats = true;
46142 tpls.cell.compile();
46144 this.templates = tpls;
46147 // remap these for backwards compat
46148 onColWidthChange : function(){
46149 this.updateColumns.apply(this, arguments);
46151 onHeaderChange : function(){
46152 this.updateHeaders.apply(this, arguments);
46154 onHiddenChange : function(){
46155 this.handleHiddenChange.apply(this, arguments);
46157 onColumnMove : function(){
46158 this.handleColumnMove.apply(this, arguments);
46160 onColumnLock : function(){
46161 this.handleLockChange.apply(this, arguments);
46164 onDataChange : function(){
46166 this.updateHeaderSortState();
46169 onClear : function(){
46173 onUpdate : function(ds, record){
46174 this.refreshRow(record);
46177 refreshRow : function(record){
46178 var ds = this.ds, index;
46179 if(typeof record == 'number'){
46181 record = ds.getAt(index);
46183 index = ds.indexOf(record);
46185 this.insertRows(ds, index, index, true);
46186 this.onRemove(ds, record, index+1, true);
46187 this.syncRowHeights(index, index);
46189 this.fireEvent("rowupdated", this, index, record);
46192 onAdd : function(ds, records, index){
46193 this.insertRows(ds, index, index + (records.length-1));
46196 onRemove : function(ds, record, index, isUpdate){
46197 if(isUpdate !== true){
46198 this.fireEvent("beforerowremoved", this, index, record);
46200 var bt = this.getBodyTable(), lt = this.getLockedTable();
46201 if(bt.rows[index]){
46202 bt.firstChild.removeChild(bt.rows[index]);
46204 if(lt.rows[index]){
46205 lt.firstChild.removeChild(lt.rows[index]);
46207 if(isUpdate !== true){
46208 this.stripeRows(index);
46209 this.syncRowHeights(index, index);
46211 this.fireEvent("rowremoved", this, index, record);
46215 onLoad : function(){
46216 this.scrollToTop();
46220 * Scrolls the grid to the top
46222 scrollToTop : function(){
46224 this.scroller.dom.scrollTop = 0;
46230 * Gets a panel in the header of the grid that can be used for toolbars etc.
46231 * After modifying the contents of this panel a call to grid.autoSize() may be
46232 * required to register any changes in size.
46233 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
46234 * @return Roo.Element
46236 getHeaderPanel : function(doShow){
46238 this.headerPanel.show();
46240 return this.headerPanel;
46244 * Gets a panel in the footer of the grid that can be used for toolbars etc.
46245 * After modifying the contents of this panel a call to grid.autoSize() may be
46246 * required to register any changes in size.
46247 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
46248 * @return Roo.Element
46250 getFooterPanel : function(doShow){
46252 this.footerPanel.show();
46254 return this.footerPanel;
46257 initElements : function(){
46258 var E = Roo.Element;
46259 var el = this.grid.getGridEl().dom.firstChild;
46260 var cs = el.childNodes;
46262 this.el = new E(el);
46263 this.headerPanel = new E(el.firstChild);
46264 this.headerPanel.enableDisplayMode("block");
46266 this.scroller = new E(cs[1]);
46267 this.scrollSizer = new E(this.scroller.dom.firstChild);
46269 this.lockedWrap = new E(cs[2]);
46270 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
46271 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
46273 this.mainWrap = new E(cs[3]);
46274 this.mainHd = new E(this.mainWrap.dom.firstChild);
46275 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
46277 this.footerPanel = new E(cs[4]);
46278 this.footerPanel.enableDisplayMode("block");
46280 this.focusEl = new E(cs[5]);
46281 this.focusEl.swallowEvent("click", true);
46282 this.resizeProxy = new E(cs[6]);
46284 this.headerSelector = String.format(
46285 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
46286 this.lockedHd.id, this.mainHd.id
46289 this.splitterSelector = String.format(
46290 '#{0} div.x-grid-split, #{1} div.x-grid-split',
46291 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
46294 idToCssName : function(s)
46296 return s.replace(/[^a-z0-9]+/ig, '-');
46299 getHeaderCell : function(index){
46300 return Roo.DomQuery.select(this.headerSelector)[index];
46303 getHeaderCellMeasure : function(index){
46304 return this.getHeaderCell(index).firstChild;
46307 getHeaderCellText : function(index){
46308 return this.getHeaderCell(index).firstChild.firstChild;
46311 getLockedTable : function(){
46312 return this.lockedBody.dom.firstChild;
46315 getBodyTable : function(){
46316 return this.mainBody.dom.firstChild;
46319 getLockedRow : function(index){
46320 return this.getLockedTable().rows[index];
46323 getRow : function(index){
46324 return this.getBodyTable().rows[index];
46327 getRowComposite : function(index){
46329 this.rowEl = new Roo.CompositeElementLite();
46331 var els = [], lrow, mrow;
46332 if(lrow = this.getLockedRow(index)){
46335 if(mrow = this.getRow(index)){
46338 this.rowEl.elements = els;
46342 getCell : function(rowIndex, colIndex){
46343 var locked = this.cm.getLockedCount();
46345 if(colIndex < locked){
46346 source = this.lockedBody.dom.firstChild;
46348 source = this.mainBody.dom.firstChild;
46349 colIndex -= locked;
46351 return source.rows[rowIndex].childNodes[colIndex];
46354 getCellText : function(rowIndex, colIndex){
46355 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
46358 getCellBox : function(cell){
46359 var b = this.fly(cell).getBox();
46360 if(Roo.isOpera){ // opera fails to report the Y
46361 b.y = cell.offsetTop + this.mainBody.getY();
46366 getCellIndex : function(cell){
46367 var id = String(cell.className).match(this.cellRE);
46369 return parseInt(id[1], 10);
46374 findHeaderIndex : function(n){
46375 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46376 return r ? this.getCellIndex(r) : false;
46379 findHeaderCell : function(n){
46380 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46381 return r ? r : false;
46384 findRowIndex : function(n){
46388 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
46389 return r ? r.rowIndex : false;
46392 findCellIndex : function(node){
46393 var stop = this.el.dom;
46394 while(node && node != stop){
46395 if(this.findRE.test(node.className)){
46396 return this.getCellIndex(node);
46398 node = node.parentNode;
46403 getColumnId : function(index){
46404 return this.cm.getColumnId(index);
46407 getSplitters : function(){
46408 if(this.splitterSelector){
46409 return Roo.DomQuery.select(this.splitterSelector);
46415 getSplitter : function(index){
46416 return this.getSplitters()[index];
46419 onRowOver : function(e, t){
46421 if((row = this.findRowIndex(t)) !== false){
46422 this.getRowComposite(row).addClass("x-grid-row-over");
46426 onRowOut : function(e, t){
46428 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
46429 this.getRowComposite(row).removeClass("x-grid-row-over");
46433 renderHeaders : function(){
46435 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
46436 var cb = [], lb = [], sb = [], lsb = [], p = {};
46437 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46438 p.cellId = "x-grid-hd-0-" + i;
46439 p.splitId = "x-grid-csplit-0-" + i;
46440 p.id = cm.getColumnId(i);
46441 p.title = cm.getColumnTooltip(i) || "";
46442 p.value = cm.getColumnHeader(i) || "";
46443 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
46444 if(!cm.isLocked(i)){
46445 cb[cb.length] = ct.apply(p);
46446 sb[sb.length] = st.apply(p);
46448 lb[lb.length] = ct.apply(p);
46449 lsb[lsb.length] = st.apply(p);
46452 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
46453 ht.apply({cells: cb.join(""), splits:sb.join("")})];
46456 updateHeaders : function(){
46457 var html = this.renderHeaders();
46458 this.lockedHd.update(html[0]);
46459 this.mainHd.update(html[1]);
46463 * Focuses the specified row.
46464 * @param {Number} row The row index
46466 focusRow : function(row){
46467 var x = this.scroller.dom.scrollLeft;
46468 this.focusCell(row, 0, false);
46469 this.scroller.dom.scrollLeft = x;
46473 * Focuses the specified cell.
46474 * @param {Number} row The row index
46475 * @param {Number} col The column index
46476 * @param {Boolean} hscroll false to disable horizontal scrolling
46478 focusCell : function(row, col, hscroll){
46479 var el = this.ensureVisible(row, col, hscroll);
46480 this.focusEl.alignTo(el, "tl-tl");
46482 this.focusEl.focus();
46484 this.focusEl.focus.defer(1, this.focusEl);
46489 * Scrolls the specified cell into view
46490 * @param {Number} row The row index
46491 * @param {Number} col The column index
46492 * @param {Boolean} hscroll false to disable horizontal scrolling
46494 ensureVisible : function(row, col, hscroll){
46495 if(typeof row != "number"){
46496 row = row.rowIndex;
46498 if(row < 0 && row >= this.ds.getCount()){
46501 col = (col !== undefined ? col : 0);
46502 var cm = this.grid.colModel;
46503 while(cm.isHidden(col)){
46507 var el = this.getCell(row, col);
46511 var c = this.scroller.dom;
46513 var ctop = parseInt(el.offsetTop, 10);
46514 var cleft = parseInt(el.offsetLeft, 10);
46515 var cbot = ctop + el.offsetHeight;
46516 var cright = cleft + el.offsetWidth;
46518 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
46519 var stop = parseInt(c.scrollTop, 10);
46520 var sleft = parseInt(c.scrollLeft, 10);
46521 var sbot = stop + ch;
46522 var sright = sleft + c.clientWidth;
46525 c.scrollTop = ctop;
46526 }else if(cbot > sbot){
46527 c.scrollTop = cbot-ch;
46530 if(hscroll !== false){
46532 c.scrollLeft = cleft;
46533 }else if(cright > sright){
46534 c.scrollLeft = cright-c.clientWidth;
46540 updateColumns : function(){
46541 this.grid.stopEditing();
46542 var cm = this.grid.colModel, colIds = this.getColumnIds();
46543 //var totalWidth = cm.getTotalWidth();
46545 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46546 //if(cm.isHidden(i)) continue;
46547 var w = cm.getColumnWidth(i);
46548 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46549 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46551 this.updateSplitters();
46554 generateRules : function(cm){
46555 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
46556 Roo.util.CSS.removeStyleSheet(rulesId);
46557 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46558 var cid = cm.getColumnId(i);
46560 if(cm.config[i].align){
46561 align = 'text-align:'+cm.config[i].align+';';
46564 if(cm.isHidden(i)){
46565 hidden = 'display:none;';
46567 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
46569 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
46570 this.hdSelector, cid, " {\n", align, width, "}\n",
46571 this.tdSelector, cid, " {\n",hidden,"\n}\n",
46572 this.splitSelector, cid, " {\n", hidden , "\n}\n");
46574 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46577 updateSplitters : function(){
46578 var cm = this.cm, s = this.getSplitters();
46579 if(s){ // splitters not created yet
46580 var pos = 0, locked = true;
46581 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46582 if(cm.isHidden(i)) continue;
46583 var w = cm.getColumnWidth(i);
46584 if(!cm.isLocked(i) && locked){
46589 s[i].style.left = (pos-this.splitOffset) + "px";
46594 handleHiddenChange : function(colModel, colIndex, hidden){
46596 this.hideColumn(colIndex);
46598 this.unhideColumn(colIndex);
46602 hideColumn : function(colIndex){
46603 var cid = this.getColumnId(colIndex);
46604 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
46605 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
46607 this.updateHeaders();
46609 this.updateSplitters();
46613 unhideColumn : function(colIndex){
46614 var cid = this.getColumnId(colIndex);
46615 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
46616 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
46619 this.updateHeaders();
46621 this.updateSplitters();
46625 insertRows : function(dm, firstRow, lastRow, isUpdate){
46626 if(firstRow == 0 && lastRow == dm.getCount()-1){
46630 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
46632 var s = this.getScrollState();
46633 var markup = this.renderRows(firstRow, lastRow);
46634 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
46635 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
46636 this.restoreScroll(s);
46638 this.fireEvent("rowsinserted", this, firstRow, lastRow);
46639 this.syncRowHeights(firstRow, lastRow);
46640 this.stripeRows(firstRow);
46646 bufferRows : function(markup, target, index){
46647 var before = null, trows = target.rows, tbody = target.tBodies[0];
46648 if(index < trows.length){
46649 before = trows[index];
46651 var b = document.createElement("div");
46652 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
46653 var rows = b.firstChild.rows;
46654 for(var i = 0, len = rows.length; i < len; i++){
46656 tbody.insertBefore(rows[0], before);
46658 tbody.appendChild(rows[0]);
46665 deleteRows : function(dm, firstRow, lastRow){
46666 if(dm.getRowCount()<1){
46667 this.fireEvent("beforerefresh", this);
46668 this.mainBody.update("");
46669 this.lockedBody.update("");
46670 this.fireEvent("refresh", this);
46672 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
46673 var bt = this.getBodyTable();
46674 var tbody = bt.firstChild;
46675 var rows = bt.rows;
46676 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
46677 tbody.removeChild(rows[firstRow]);
46679 this.stripeRows(firstRow);
46680 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
46684 updateRows : function(dataSource, firstRow, lastRow){
46685 var s = this.getScrollState();
46687 this.restoreScroll(s);
46690 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
46694 this.updateHeaderSortState();
46697 getScrollState : function(){
46698 var sb = this.scroller.dom;
46699 return {left: sb.scrollLeft, top: sb.scrollTop};
46702 stripeRows : function(startRow){
46703 if(!this.grid.stripeRows || this.ds.getCount() < 1){
46706 startRow = startRow || 0;
46707 var rows = this.getBodyTable().rows;
46708 var lrows = this.getLockedTable().rows;
46709 var cls = ' x-grid-row-alt ';
46710 for(var i = startRow, len = rows.length; i < len; i++){
46711 var row = rows[i], lrow = lrows[i];
46712 var isAlt = ((i+1) % 2 == 0);
46713 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
46714 if(isAlt == hasAlt){
46718 row.className += " x-grid-row-alt";
46720 row.className = row.className.replace("x-grid-row-alt", "");
46723 lrow.className = row.className;
46728 restoreScroll : function(state){
46729 var sb = this.scroller.dom;
46730 sb.scrollLeft = state.left;
46731 sb.scrollTop = state.top;
46735 syncScroll : function(){
46736 var sb = this.scroller.dom;
46737 var sh = this.mainHd.dom;
46738 var bs = this.mainBody.dom;
46739 var lv = this.lockedBody.dom;
46740 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
46741 lv.scrollTop = bs.scrollTop = sb.scrollTop;
46744 handleScroll : function(e){
46746 var sb = this.scroller.dom;
46747 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
46751 handleWheel : function(e){
46752 var d = e.getWheelDelta();
46753 this.scroller.dom.scrollTop -= d*22;
46754 // set this here to prevent jumpy scrolling on large tables
46755 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
46759 renderRows : function(startRow, endRow){
46760 // pull in all the crap needed to render rows
46761 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
46762 var colCount = cm.getColumnCount();
46764 if(ds.getCount() < 1){
46768 // build a map for all the columns
46770 for(var i = 0; i < colCount; i++){
46771 var name = cm.getDataIndex(i);
46773 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
46774 renderer : cm.getRenderer(i),
46775 id : cm.getColumnId(i),
46776 locked : cm.isLocked(i)
46780 startRow = startRow || 0;
46781 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
46783 // records to render
46784 var rs = ds.getRange(startRow, endRow);
46786 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
46789 // As much as I hate to duplicate code, this was branched because FireFox really hates
46790 // [].join("") on strings. The performance difference was substantial enough to
46791 // branch this function
46792 doRender : Roo.isGecko ?
46793 function(cs, rs, ds, startRow, colCount, stripe){
46794 var ts = this.templates, ct = ts.cell, rt = ts.row;
46796 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
46797 for(var j = 0, len = rs.length; j < len; j++){
46798 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
46799 for(var i = 0; i < colCount; i++){
46801 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
46803 p.css = p.attr = "";
46804 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
46805 if(p.value == undefined || p.value === "") p.value = " ";
46806 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
46807 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
46809 var markup = ct.apply(p);
46817 if(stripe && ((rowIndex+1) % 2 == 0)){
46818 alt[0] = "x-grid-row-alt";
46821 alt[1] = " x-grid-dirty-row";
46824 if(this.getRowClass){
46825 alt[2] = this.getRowClass(r, rowIndex);
46827 rp.alt = alt.join(" ");
46828 lbuf+= rt.apply(rp);
46830 buf+= rt.apply(rp);
46832 return [lbuf, buf];
46834 function(cs, rs, ds, startRow, colCount, stripe){
46835 var ts = this.templates, ct = ts.cell, rt = ts.row;
46837 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
46838 for(var j = 0, len = rs.length; j < len; j++){
46839 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
46840 for(var i = 0; i < colCount; i++){
46842 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
46844 p.css = p.attr = "";
46845 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
46846 if(p.value == undefined || p.value === "") p.value = " ";
46847 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
46848 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
46850 var markup = ct.apply(p);
46852 cb[cb.length] = markup;
46854 lcb[lcb.length] = markup;
46858 if(stripe && ((rowIndex+1) % 2 == 0)){
46859 alt[0] = "x-grid-row-alt";
46862 alt[1] = " x-grid-dirty-row";
46865 if(this.getRowClass){
46866 alt[2] = this.getRowClass(r, rowIndex);
46868 rp.alt = alt.join(" ");
46869 rp.cells = lcb.join("");
46870 lbuf[lbuf.length] = rt.apply(rp);
46871 rp.cells = cb.join("");
46872 buf[buf.length] = rt.apply(rp);
46874 return [lbuf.join(""), buf.join("")];
46877 renderBody : function(){
46878 var markup = this.renderRows();
46879 var bt = this.templates.body;
46880 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
46884 * Refreshes the grid
46885 * @param {Boolean} headersToo
46887 refresh : function(headersToo){
46888 this.fireEvent("beforerefresh", this);
46889 this.grid.stopEditing();
46890 var result = this.renderBody();
46891 this.lockedBody.update(result[0]);
46892 this.mainBody.update(result[1]);
46893 if(headersToo === true){
46894 this.updateHeaders();
46895 this.updateColumns();
46896 this.updateSplitters();
46897 this.updateHeaderSortState();
46899 this.syncRowHeights();
46901 this.fireEvent("refresh", this);
46904 handleColumnMove : function(cm, oldIndex, newIndex){
46905 this.indexMap = null;
46906 var s = this.getScrollState();
46907 this.refresh(true);
46908 this.restoreScroll(s);
46909 this.afterMove(newIndex);
46912 afterMove : function(colIndex){
46913 if(this.enableMoveAnim && Roo.enableFx){
46914 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
46918 updateCell : function(dm, rowIndex, dataIndex){
46919 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
46920 if(typeof colIndex == "undefined"){ // not present in grid
46923 var cm = this.grid.colModel;
46924 var cell = this.getCell(rowIndex, colIndex);
46925 var cellText = this.getCellText(rowIndex, colIndex);
46928 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
46929 id : cm.getColumnId(colIndex),
46930 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
46932 var renderer = cm.getRenderer(colIndex);
46933 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
46934 if(typeof val == "undefined" || val === "") val = " ";
46935 cellText.innerHTML = val;
46936 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
46937 this.syncRowHeights(rowIndex, rowIndex);
46940 calcColumnWidth : function(colIndex, maxRowsToMeasure){
46942 if(this.grid.autoSizeHeaders){
46943 var h = this.getHeaderCellMeasure(colIndex);
46944 maxWidth = Math.max(maxWidth, h.scrollWidth);
46947 if(this.cm.isLocked(colIndex)){
46948 tb = this.getLockedTable();
46951 tb = this.getBodyTable();
46952 index = colIndex - this.cm.getLockedCount();
46955 var rows = tb.rows;
46956 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
46957 for(var i = 0; i < stopIndex; i++){
46958 var cell = rows[i].childNodes[index].firstChild;
46959 maxWidth = Math.max(maxWidth, cell.scrollWidth);
46962 return maxWidth + /*margin for error in IE*/ 5;
46965 * Autofit a column to its content.
46966 * @param {Number} colIndex
46967 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
46969 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
46970 if(this.cm.isHidden(colIndex)){
46971 return; // can't calc a hidden column
46974 var cid = this.cm.getColumnId(colIndex);
46975 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
46976 if(this.grid.autoSizeHeaders){
46977 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
46980 var newWidth = this.calcColumnWidth(colIndex);
46981 this.cm.setColumnWidth(colIndex,
46982 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
46983 if(!suppressEvent){
46984 this.grid.fireEvent("columnresize", colIndex, newWidth);
46989 * Autofits all columns to their content and then expands to fit any extra space in the grid
46991 autoSizeColumns : function(){
46992 var cm = this.grid.colModel;
46993 var colCount = cm.getColumnCount();
46994 for(var i = 0; i < colCount; i++){
46995 this.autoSizeColumn(i, true, true);
46997 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
47000 this.updateColumns();
47006 * Autofits all columns to the grid's width proportionate with their current size
47007 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
47009 fitColumns : function(reserveScrollSpace){
47010 var cm = this.grid.colModel;
47011 var colCount = cm.getColumnCount();
47015 for (i = 0; i < colCount; i++){
47016 if(!cm.isHidden(i) && !cm.isFixed(i)){
47017 w = cm.getColumnWidth(i);
47023 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
47024 if(reserveScrollSpace){
47027 var frac = (avail - cm.getTotalWidth())/width;
47028 while (cols.length){
47031 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
47033 this.updateColumns();
47037 onRowSelect : function(rowIndex){
47038 var row = this.getRowComposite(rowIndex);
47039 row.addClass("x-grid-row-selected");
47042 onRowDeselect : function(rowIndex){
47043 var row = this.getRowComposite(rowIndex);
47044 row.removeClass("x-grid-row-selected");
47047 onCellSelect : function(row, col){
47048 var cell = this.getCell(row, col);
47050 Roo.fly(cell).addClass("x-grid-cell-selected");
47054 onCellDeselect : function(row, col){
47055 var cell = this.getCell(row, col);
47057 Roo.fly(cell).removeClass("x-grid-cell-selected");
47061 updateHeaderSortState : function(){
47062 var state = this.ds.getSortState();
47066 this.sortState = state;
47067 var sortColumn = this.cm.findColumnIndex(state.field);
47068 if(sortColumn != -1){
47069 var sortDir = state.direction;
47070 var sc = this.sortClasses;
47071 var hds = this.el.select(this.headerSelector).removeClass(sc);
47072 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
47076 handleHeaderClick : function(g, index){
47077 if(this.headersDisabled){
47080 var dm = g.dataSource, cm = g.colModel;
47081 if(!cm.isSortable(index)){
47085 dm.sort(cm.getDataIndex(index));
47089 destroy : function(){
47091 this.colMenu.removeAll();
47092 Roo.menu.MenuMgr.unregister(this.colMenu);
47093 this.colMenu.getEl().remove();
47094 delete this.colMenu;
47097 this.hmenu.removeAll();
47098 Roo.menu.MenuMgr.unregister(this.hmenu);
47099 this.hmenu.getEl().remove();
47102 if(this.grid.enableColumnMove){
47103 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47105 for(var dd in dds){
47106 if(!dds[dd].config.isTarget && dds[dd].dragElId){
47107 var elid = dds[dd].dragElId;
47109 Roo.get(elid).remove();
47110 } else if(dds[dd].config.isTarget){
47111 dds[dd].proxyTop.remove();
47112 dds[dd].proxyBottom.remove();
47115 if(Roo.dd.DDM.locationCache[dd]){
47116 delete Roo.dd.DDM.locationCache[dd];
47119 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47122 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
47123 this.bind(null, null);
47124 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
47127 handleLockChange : function(){
47128 this.refresh(true);
47131 onDenyColumnLock : function(){
47135 onDenyColumnHide : function(){
47139 handleHdMenuClick : function(item){
47140 var index = this.hdCtxIndex;
47141 var cm = this.cm, ds = this.ds;
47144 ds.sort(cm.getDataIndex(index), "ASC");
47147 ds.sort(cm.getDataIndex(index), "DESC");
47150 var lc = cm.getLockedCount();
47151 if(cm.getColumnCount(true) <= lc+1){
47152 this.onDenyColumnLock();
47156 cm.setLocked(index, true, true);
47157 cm.moveColumn(index, lc);
47158 this.grid.fireEvent("columnmove", index, lc);
47160 cm.setLocked(index, true);
47164 var lc = cm.getLockedCount();
47165 if((lc-1) != index){
47166 cm.setLocked(index, false, true);
47167 cm.moveColumn(index, lc-1);
47168 this.grid.fireEvent("columnmove", index, lc-1);
47170 cm.setLocked(index, false);
47174 index = cm.getIndexById(item.id.substr(4));
47176 if(item.checked && cm.getColumnCount(true) <= 1){
47177 this.onDenyColumnHide();
47180 cm.setHidden(index, item.checked);
47186 beforeColMenuShow : function(){
47187 var cm = this.cm, colCount = cm.getColumnCount();
47188 this.colMenu.removeAll();
47189 for(var i = 0; i < colCount; i++){
47190 this.colMenu.add(new Roo.menu.CheckItem({
47191 id: "col-"+cm.getColumnId(i),
47192 text: cm.getColumnHeader(i),
47193 checked: !cm.isHidden(i),
47199 handleHdCtx : function(g, index, e){
47201 var hd = this.getHeaderCell(index);
47202 this.hdCtxIndex = index;
47203 var ms = this.hmenu.items, cm = this.cm;
47204 ms.get("asc").setDisabled(!cm.isSortable(index));
47205 ms.get("desc").setDisabled(!cm.isSortable(index));
47206 if(this.grid.enableColLock !== false){
47207 ms.get("lock").setDisabled(cm.isLocked(index));
47208 ms.get("unlock").setDisabled(!cm.isLocked(index));
47210 this.hmenu.show(hd, "tl-bl");
47213 handleHdOver : function(e){
47214 var hd = this.findHeaderCell(e.getTarget());
47215 if(hd && !this.headersDisabled){
47216 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
47217 this.fly(hd).addClass("x-grid-hd-over");
47222 handleHdOut : function(e){
47223 var hd = this.findHeaderCell(e.getTarget());
47225 this.fly(hd).removeClass("x-grid-hd-over");
47229 handleSplitDblClick : function(e, t){
47230 var i = this.getCellIndex(t);
47231 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
47232 this.autoSizeColumn(i, true);
47237 render : function(){
47240 var colCount = cm.getColumnCount();
47242 if(this.grid.monitorWindowResize === true){
47243 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47245 var header = this.renderHeaders();
47246 var body = this.templates.body.apply({rows:""});
47247 var html = this.templates.master.apply({
47250 lockedHeader: header[0],
47254 //this.updateColumns();
47256 this.grid.getGridEl().dom.innerHTML = html;
47258 this.initElements();
47260 this.scroller.on("scroll", this.handleScroll, this);
47261 this.lockedBody.on("mousewheel", this.handleWheel, this);
47262 this.mainBody.on("mousewheel", this.handleWheel, this);
47264 this.mainHd.on("mouseover", this.handleHdOver, this);
47265 this.mainHd.on("mouseout", this.handleHdOut, this);
47266 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
47267 {delegate: "."+this.splitClass});
47269 this.lockedHd.on("mouseover", this.handleHdOver, this);
47270 this.lockedHd.on("mouseout", this.handleHdOut, this);
47271 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
47272 {delegate: "."+this.splitClass});
47274 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
47275 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47278 this.updateSplitters();
47280 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
47281 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47282 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47285 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
47286 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
47288 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
47289 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
47291 if(this.grid.enableColLock !== false){
47292 this.hmenu.add('-',
47293 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
47294 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
47297 if(this.grid.enableColumnHide !== false){
47299 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
47300 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
47301 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
47303 this.hmenu.add('-',
47304 {id:"columns", text: this.columnsText, menu: this.colMenu}
47307 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
47309 this.grid.on("headercontextmenu", this.handleHdCtx, this);
47312 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
47313 this.dd = new Roo.grid.GridDragZone(this.grid, {
47314 ddGroup : this.grid.ddGroup || 'GridDD'
47319 for(var i = 0; i < colCount; i++){
47320 if(cm.isHidden(i)){
47321 this.hideColumn(i);
47323 if(cm.config[i].align){
47324 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
47325 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
47329 this.updateHeaderSortState();
47331 this.beforeInitialResize();
47334 // two part rendering gives faster view to the user
47335 this.renderPhase2.defer(1, this);
47338 renderPhase2 : function(){
47339 // render the rows now
47341 if(this.grid.autoSizeColumns){
47342 this.autoSizeColumns();
47346 beforeInitialResize : function(){
47350 onColumnSplitterMoved : function(i, w){
47351 this.userResized = true;
47352 var cm = this.grid.colModel;
47353 cm.setColumnWidth(i, w, true);
47354 var cid = cm.getColumnId(i);
47355 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47356 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47357 this.updateSplitters();
47359 this.grid.fireEvent("columnresize", i, w);
47362 syncRowHeights : function(startIndex, endIndex){
47363 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
47364 startIndex = startIndex || 0;
47365 var mrows = this.getBodyTable().rows;
47366 var lrows = this.getLockedTable().rows;
47367 var len = mrows.length-1;
47368 endIndex = Math.min(endIndex || len, len);
47369 for(var i = startIndex; i <= endIndex; i++){
47370 var m = mrows[i], l = lrows[i];
47371 var h = Math.max(m.offsetHeight, l.offsetHeight);
47372 m.style.height = l.style.height = h + "px";
47377 layout : function(initialRender, is2ndPass){
47379 var auto = g.autoHeight;
47380 var scrollOffset = 16;
47381 var c = g.getGridEl(), cm = this.cm,
47382 expandCol = g.autoExpandColumn,
47384 //c.beginMeasure();
47386 if(!c.dom.offsetWidth){ // display:none?
47388 this.lockedWrap.show();
47389 this.mainWrap.show();
47394 var hasLock = this.cm.isLocked(0);
47396 var tbh = this.headerPanel.getHeight();
47397 var bbh = this.footerPanel.getHeight();
47400 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
47401 var newHeight = ch + c.getBorderWidth("tb");
47403 newHeight = Math.min(g.maxHeight, newHeight);
47405 c.setHeight(newHeight);
47409 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
47412 var s = this.scroller;
47414 var csize = c.getSize(true);
47416 this.el.setSize(csize.width, csize.height);
47418 this.headerPanel.setWidth(csize.width);
47419 this.footerPanel.setWidth(csize.width);
47421 var hdHeight = this.mainHd.getHeight();
47422 var vw = csize.width;
47423 var vh = csize.height - (tbh + bbh);
47427 var bt = this.getBodyTable();
47428 var ltWidth = hasLock ?
47429 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
47431 var scrollHeight = bt.offsetHeight;
47432 var scrollWidth = ltWidth + bt.offsetWidth;
47433 var vscroll = false, hscroll = false;
47435 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
47437 var lw = this.lockedWrap, mw = this.mainWrap;
47438 var lb = this.lockedBody, mb = this.mainBody;
47440 setTimeout(function(){
47441 var t = s.dom.offsetTop;
47442 var w = s.dom.clientWidth,
47443 h = s.dom.clientHeight;
47446 lw.setSize(ltWidth, h);
47448 mw.setLeftTop(ltWidth, t);
47449 mw.setSize(w-ltWidth, h);
47451 lb.setHeight(h-hdHeight);
47452 mb.setHeight(h-hdHeight);
47454 if(is2ndPass !== true && !gv.userResized && expandCol){
47455 // high speed resize without full column calculation
47457 var ci = cm.getIndexById(expandCol);
47459 ci = cm.findColumnIndex(expandCol);
47461 ci = Math.max(0, ci); // make sure it's got at least the first col.
47462 var expandId = cm.getColumnId(ci);
47463 var tw = cm.getTotalWidth(false);
47464 var currentWidth = cm.getColumnWidth(ci);
47465 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
47466 if(currentWidth != cw){
47467 cm.setColumnWidth(ci, cw, true);
47468 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47469 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47470 gv.updateSplitters();
47471 gv.layout(false, true);
47483 onWindowResize : function(){
47484 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
47490 appendFooter : function(parentEl){
47494 sortAscText : "Sort Ascending",
47495 sortDescText : "Sort Descending",
47496 lockText : "Lock Column",
47497 unlockText : "Unlock Column",
47498 columnsText : "Columns"
47502 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
47503 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
47504 this.proxy.el.addClass('x-grid3-col-dd');
47507 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
47508 handleMouseDown : function(e){
47512 callHandleMouseDown : function(e){
47513 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);