4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
90 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
93 enableGarbageCollector : true,
96 * True to automatically purge event listeners after uncaching an element (defaults to false).
97 * Note: this only happens if enableGarbageCollector is true.
100 enableListenerCollection:false,
103 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
104 * the IE insecure content warning (defaults to javascript:false).
107 SSL_SECURE_URL : "javascript:false",
110 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
111 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
114 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
116 emptyFn : function(){},
119 * Copies all the properties of config to obj if they don't already exist.
120 * @param {Object} obj The receiver of the properties
121 * @param {Object} config The source of the properties
122 * @return {Object} returns obj
124 applyIf : function(o, c){
127 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134 * Applies event listeners to elements by selectors when the document is ready.
135 * The event name is specified with an @ suffix.
138 // add a listener for click on all anchors in element with id foo
139 '#foo a@click' : function(e, t){
143 // add the same listener to multiple selectors (separated by comma BEFORE the @)
144 '#foo a, #bar span.some-class@mouseover' : function(){
149 * @param {Object} obj The list of behaviors to apply
151 addBehaviors : function(o){
153 Roo.onReady(function(){
158 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
160 var parts = b.split('@');
161 if(parts[1]){ // for Object prototype breakers
164 cache[s] = Roo.select(s);
166 cache[s].on(parts[1], o[b]);
173 * Generates unique ids. If the element already has an id, it is unchanged
174 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
175 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
176 * @return {String} The generated Id.
178 id : function(el, prefix){
179 prefix = prefix || "roo-gen";
181 var id = prefix + (++idSeed);
182 return el ? (el.id ? el.id : (el.id = id)) : id;
187 * Extends one class with another class and optionally overrides members with the passed literal. This class
188 * also adds the function "override()" to the class that can be used to override
189 * members on an instance.
190 * @param {Object} subclass The class inheriting the functionality
191 * @param {Object} superclass The class being extended
192 * @param {Object} overrides (optional) A literal with members
197 var io = function(o){
202 return function(sb, sp, overrides){
203 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
206 sb = function(){sp.apply(this, arguments);};
208 var F = function(){}, sbp, spp = sp.prototype;
210 sbp = sb.prototype = new F();
214 if(spp.constructor == Object.prototype.constructor){
219 sb.override = function(o){
223 Roo.override(sb, overrides);
229 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
231 Roo.override(MyClass, {
232 newMethod1: function(){
235 newMethod2: function(foo){
240 * @param {Object} origclass The class to override
241 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
242 * containing one or more methods.
245 override : function(origclass, overrides){
247 var p = origclass.prototype;
248 for(var method in overrides){
249 p[method] = overrides[method];
254 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
256 Roo.namespace('Company', 'Company.data');
257 Company.Widget = function() { ... }
258 Company.data.CustomStore = function(config) { ... }
260 * @param {String} namespace1
261 * @param {String} namespace2
262 * @param {String} etc
265 namespace : function(){
266 var a=arguments, o=null, i, j, d, rt;
267 for (i=0; i<a.length; ++i) {
271 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
272 for (j=1; j<d.length; ++j) {
273 o[d[j]]=o[d[j]] || {};
279 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
281 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
282 Roo.factory(conf, Roo.data);
284 * @param {String} classname
285 * @param {String} namespace (optional)
289 factory : function(c, ns)
291 // no xtype, no ns or c.xns - or forced off by c.xns
292 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
295 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
296 if (c.constructor == ns[c.xtype]) {// already created...
300 console.log("Roo.Factory(" + c.xtype + ")");
301 var ret = new ns[c.xtype](c);
305 c.xns = false; // prevent recursion..
310 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
314 urlEncode : function(o){
320 var ov = o[key], k = encodeURIComponent(key);
321 var type = typeof ov;
322 if(type == 'undefined'){
324 }else if(type != "function" && type != "object"){
325 buf.push(k, "=", encodeURIComponent(ov), "&");
326 }else if(ov instanceof Array){
328 for(var i = 0, len = ov.length; i < len; i++) {
329 buf.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
341 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
342 * @param {String} string
343 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
344 * @return {Object} A literal with members
346 urlDecode : function(string, overwrite){
347 if(!string || !string.length){
351 var pairs = string.split('&');
352 var pair, name, value;
353 for(var i = 0, len = pairs.length; i < len; i++){
354 pair = pairs[i].split('=');
355 name = decodeURIComponent(pair[0]);
356 value = decodeURIComponent(pair[1]);
357 if(overwrite !== true){
358 if(typeof obj[name] == "undefined"){
360 }else if(typeof obj[name] == "string"){
361 obj[name] = [obj[name]];
362 obj[name].push(value);
364 obj[name].push(value);
374 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
375 * passed array is not really an array, your function is called once with it.
376 * The supplied function is called with (Object item, Number index, Array allItems).
377 * @param {Array/NodeList/Mixed} array
378 * @param {Function} fn
379 * @param {Object} scope
381 each : function(array, fn, scope){
382 if(typeof array.length == "undefined" || typeof array == "string"){
385 for(var i = 0, len = array.length; i < len; i++){
386 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
391 combine : function(){
392 var as = arguments, l = as.length, r = [];
393 for(var i = 0; i < l; i++){
395 if(a instanceof Array){
397 }else if(a.length !== undefined && !a.substr){
398 r = r.concat(Array.prototype.slice.call(a, 0));
407 * Escapes the passed string for use in a regular expression
408 * @param {String} str
411 escapeRe : function(s) {
412 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
416 callback : function(cb, scope, args, delay){
417 if(typeof cb == "function"){
419 cb.defer(delay, scope, args || []);
421 cb.apply(scope, args || []);
427 * Return the dom node for the passed string (id), dom node, or Roo.Element
428 * @param {String/HTMLElement/Roo.Element} el
429 * @return HTMLElement
431 getDom : function(el){
435 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
439 * Shorthand for {@link Roo.ComponentMgr#get}
441 * @return Roo.Component
443 getCmp : function(id){
444 return Roo.ComponentMgr.get(id);
447 num : function(v, defaultValue){
448 if(typeof v != 'number'){
454 destroy : function(){
455 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
459 as.removeAllListeners();
463 if(typeof as.purgeListeners == 'function'){
466 if(typeof as.destroy == 'function'){
473 // inpired by a similar function in mootools library
475 * Returns the type of object that is passed in. If the object passed in is null or undefined it
476 * return false otherwise it returns one of the following values:<ul>
477 * <li><b>string</b>: If the object passed is a string</li>
478 * <li><b>number</b>: If the object passed is a number</li>
479 * <li><b>boolean</b>: If the object passed is a boolean value</li>
480 * <li><b>function</b>: If the object passed is a function reference</li>
481 * <li><b>object</b>: If the object passed is an object</li>
482 * <li><b>array</b>: If the object passed is an array</li>
483 * <li><b>regexp</b>: If the object passed is a regular expression</li>
484 * <li><b>element</b>: If the object passed is a DOM Element</li>
485 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
486 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
487 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
488 * @param {Mixed} object
492 if(o === undefined || o === null){
499 if(t == 'object' && o.nodeName) {
501 case 1: return 'element';
502 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
505 if(t == 'object' || t == 'function') {
506 switch(o.constructor) {
507 case Array: return 'array';
508 case RegExp: return 'regexp';
510 if(typeof o.length == 'number' && typeof o.item == 'function') {
518 * Returns true if the passed value is null, undefined or an empty string (optional).
519 * @param {Mixed} value The value to test
520 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
523 isEmpty : function(v, allowBlank){
524 return v === null || v === undefined || (!allowBlank ? v === '' : false);
538 isBorderBox : isBorderBox,
540 isWindows : isWindows,
547 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
548 * you may want to set this to true.
551 useShims : ((isIE && !isIE7) || (isGecko && isMac))
557 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
558 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
561 * Ext JS Library 1.1.1
562 * Copyright(c) 2006-2007, Ext JS, LLC.
564 * Originally Released Under LGPL - original licence link has changed is not relivant.
567 * <script type="text/javascript">
571 // wrappedn so fnCleanup is not in global scope...
573 function fnCleanUp() {
574 var p = Function.prototype;
575 delete p.createSequence;
577 delete p.createDelegate;
578 delete p.createCallback;
579 delete p.createInterceptor;
581 window.detachEvent("onunload", fnCleanUp);
583 window.attachEvent("onunload", fnCleanUp);
590 * These functions are available on every Function object (any JavaScript function).
592 Roo.apply(Function.prototype, {
594 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
595 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
596 * Will create a function that is bound to those 2 args.
597 * @return {Function} The new function
599 createCallback : function(/*args...*/){
600 // make args available, in function below
601 var args = arguments;
604 return method.apply(window, args);
609 * Creates a delegate (callback) that sets the scope to obj.
610 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
611 * Will create a function that is automatically scoped to this.
612 * @param {Object} obj (optional) The object for which the scope is set
613 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
614 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
615 * if a number the args are inserted at the specified position
616 * @return {Function} The new function
618 createDelegate : function(obj, args, appendArgs){
621 var callArgs = args || arguments;
622 if(appendArgs === true){
623 callArgs = Array.prototype.slice.call(arguments, 0);
624 callArgs = callArgs.concat(args);
625 }else if(typeof appendArgs == "number"){
626 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
627 var applyArgs = [appendArgs, 0].concat(args); // create method call params
628 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
630 return method.apply(obj || window, callArgs);
635 * Calls this function after the number of millseconds specified.
636 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
637 * @param {Object} obj (optional) The object for which the scope is set
638 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
639 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
640 * if a number the args are inserted at the specified position
641 * @return {Number} The timeout id that can be used with clearTimeout
643 defer : function(millis, obj, args, appendArgs){
644 var fn = this.createDelegate(obj, args, appendArgs);
646 return setTimeout(fn, millis);
652 * Create a combined function call sequence of the original function + the passed function.
653 * The resulting function returns the results of the original function.
654 * The passed fcn is called with the parameters of the original function
655 * @param {Function} fcn The function to sequence
656 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
657 * @return {Function} The new function
659 createSequence : function(fcn, scope){
660 if(typeof fcn != "function"){
665 var retval = method.apply(this || window, arguments);
666 fcn.apply(scope || this || window, arguments);
672 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
673 * The resulting function returns the results of the original function.
674 * The passed fcn is called with the parameters of the original function.
676 * @param {Function} fcn The function to call before the original
677 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
678 * @return {Function} The new function
680 createInterceptor : function(fcn, scope){
681 if(typeof fcn != "function"){
688 if(fcn.apply(scope || this || window, arguments) === false){
691 return method.apply(this || window, arguments);
697 * Ext JS Library 1.1.1
698 * Copyright(c) 2006-2007, Ext JS, LLC.
700 * Originally Released Under LGPL - original licence link has changed is not relivant.
703 * <script type="text/javascript">
706 Roo.applyIf(String, {
711 * Escapes the passed string for ' and \
712 * @param {String} string The string to escape
713 * @return {String} The escaped string
716 escape : function(string) {
717 return string.replace(/('|\\)/g, "\\$1");
721 * Pads the left side of a string with a specified character. This is especially useful
722 * for normalizing number and date strings. Example usage:
724 var s = String.leftPad('123', 5, '0');
725 // s now contains the string: '00123'
727 * @param {String} string The original string
728 * @param {Number} size The total length of the output string
729 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
730 * @return {String} The padded string
733 leftPad : function (val, size, ch) {
734 var result = new String(val);
735 if(ch === null || ch === undefined || ch === '') {
738 while (result.length < size) {
739 result = ch + result;
745 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
746 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
748 var cls = 'my-class', text = 'Some text';
749 var s = String.format('<div class="{0}">{1}</div>', cls, text);
750 // s now contains the string: '<div class="my-class">Some text</div>'
752 * @param {String} string The tokenized string to be formatted
753 * @param {String} value1 The value to replace token {0}
754 * @param {String} value2 Etc...
755 * @return {String} The formatted string
758 format : function(format){
759 var args = Array.prototype.slice.call(arguments, 1);
760 return format.replace(/\{(\d+)\}/g, function(m, i){
761 return Roo.util.Format.htmlEncode(args[i]);
767 * Utility function that allows you to easily switch a string between two alternating values. The passed value
768 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
769 * they are already different, the first value passed in is returned. Note that this method returns the new value
770 * but does not change the current string.
772 // alternate sort directions
773 sort = sort.toggle('ASC', 'DESC');
775 // instead of conditional logic:
776 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
778 * @param {String} value The value to compare to the current string
779 * @param {String} other The new value to use if the string already equals the first value passed in
780 * @return {String} The new value
783 String.prototype.toggle = function(value, other){
784 return this == value ? other : value;
787 * Ext JS Library 1.1.1
788 * Copyright(c) 2006-2007, Ext JS, LLC.
790 * Originally Released Under LGPL - original licence link has changed is not relivant.
793 * <script type="text/javascript">
799 Roo.applyIf(Number.prototype, {
801 * Checks whether or not the current number is within a desired range. If the number is already within the
802 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
803 * exceeded. Note that this method returns the constrained value but does not change the current number.
804 * @param {Number} min The minimum number in the range
805 * @param {Number} max The maximum number in the range
806 * @return {Number} The constrained value if outside the range, otherwise the current value
808 constrain : function(min, max){
809 return Math.min(Math.max(this, min), max);
813 * Ext JS Library 1.1.1
814 * Copyright(c) 2006-2007, Ext JS, LLC.
816 * Originally Released Under LGPL - original licence link has changed is not relivant.
819 * <script type="text/javascript">
824 Roo.applyIf(Array.prototype, {
826 * Checks whether or not the specified object exists in the array.
827 * @param {Object} o The object to check for
828 * @return {Number} The index of o in the array (or -1 if it is not found)
830 indexOf : function(o){
831 for (var i = 0, len = this.length; i < len; i++){
832 if(this[i] == o) return i;
838 * Removes the specified object from the array. If the object is not found nothing happens.
839 * @param {Object} o The object to remove
841 remove : function(o){
842 var index = this.indexOf(o);
844 this.splice(index, 1);
849 * Ext JS Library 1.1.1
850 * Copyright(c) 2006-2007, Ext JS, LLC.
852 * Originally Released Under LGPL - original licence link has changed is not relivant.
855 * <script type="text/javascript">
861 * The date parsing and format syntax is a subset of
862 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
863 * supported will provide results equivalent to their PHP versions.
865 * Following is the list of all currently supported formats:
868 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
870 Format Output Description
871 ------ ---------- --------------------------------------------------------------
872 d 10 Day of the month, 2 digits with leading zeros
873 D Wed A textual representation of a day, three letters
874 j 10 Day of the month without leading zeros
875 l Wednesday A full textual representation of the day of the week
876 S th English ordinal day of month suffix, 2 chars (use with j)
877 w 3 Numeric representation of the day of the week
878 z 9 The julian date, or day of the year (0-365)
879 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
880 F January A full textual representation of the month
881 m 01 Numeric representation of a month, with leading zeros
882 M Jan Month name abbreviation, three letters
883 n 1 Numeric representation of a month, without leading zeros
884 t 31 Number of days in the given month
885 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
886 Y 2007 A full numeric representation of a year, 4 digits
887 y 07 A two digit representation of a year
888 a pm Lowercase Ante meridiem and Post meridiem
889 A PM Uppercase Ante meridiem and Post meridiem
890 g 3 12-hour format of an hour without leading zeros
891 G 15 24-hour format of an hour without leading zeros
892 h 03 12-hour format of an hour with leading zeros
893 H 15 24-hour format of an hour with leading zeros
894 i 05 Minutes with leading zeros
895 s 01 Seconds, with leading zeros
896 O -0600 Difference to Greenwich time (GMT) in hours
897 T CST Timezone setting of the machine running the code
898 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
901 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
903 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
904 document.write(dt.format('Y-m-d')); //2007-01-10
905 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
906 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
909 * Here are some standard date/time patterns that you might find helpful. They
910 * are not part of the source of Date.js, but to use them you can simply copy this
911 * block of code into any script that is included after Date.js and they will also become
912 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
915 ISO8601Long:"Y-m-d H:i:s",
916 ISO8601Short:"Y-m-d",
918 LongDate: "l, F d, Y",
919 FullDateTime: "l, F d, Y g:i:s A",
923 SortableDateTime: "Y-m-d\\TH:i:s",
924 UniversalSortableDateTime: "Y-m-d H:i:sO",
932 document.write(dt.format(Date.patterns.ShortDate));
937 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
938 * They generate precompiled functions from date formats instead of parsing and
939 * processing the pattern every time you format a date. These functions are available
940 * on every Date object (any javascript function).
942 * The original article and download are here:
943 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
950 Returns the number of milliseconds between this date and date
951 @param {Date} date (optional) Defaults to now
952 @return {Number} The diff in milliseconds
953 @member Date getElapsed
955 Date.prototype.getElapsed = function(date) {
956 return Math.abs((date || new Date()).getTime()-this.getTime());
958 // was in date file..
962 Date.parseFunctions = {count:0};
964 Date.parseRegexes = [];
966 Date.formatFunctions = {count:0};
969 Date.prototype.dateFormat = function(format) {
970 if (Date.formatFunctions[format] == null) {
971 Date.createNewFormat(format);
973 var func = Date.formatFunctions[format];
979 * Formats a date given the supplied format string
980 * @param {String} format The format string
981 * @return {String} The formatted date
984 Date.prototype.format = Date.prototype.dateFormat;
987 Date.createNewFormat = function(format) {
988 var funcName = "format" + Date.formatFunctions.count++;
989 Date.formatFunctions[format] = funcName;
990 var code = "Date.prototype." + funcName + " = function(){return ";
993 for (var i = 0; i < format.length; ++i) {
994 ch = format.charAt(i);
995 if (!special && ch == "\\") {
1000 code += "'" + String.escape(ch) + "' + ";
1003 code += Date.getFormatCode(ch);
1006 /** eval:var:zzzzzzzzzzzzz */
1007 eval(code.substring(0, code.length - 3) + ";}");
1011 Date.getFormatCode = function(character) {
1012 switch (character) {
1014 return "String.leftPad(this.getDate(), 2, '0') + ";
1016 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1018 return "this.getDate() + ";
1020 return "Date.dayNames[this.getDay()] + ";
1022 return "this.getSuffix() + ";
1024 return "this.getDay() + ";
1026 return "this.getDayOfYear() + ";
1028 return "this.getWeekOfYear() + ";
1030 return "Date.monthNames[this.getMonth()] + ";
1032 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1034 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1036 return "(this.getMonth() + 1) + ";
1038 return "this.getDaysInMonth() + ";
1040 return "(this.isLeapYear() ? 1 : 0) + ";
1042 return "this.getFullYear() + ";
1044 return "('' + this.getFullYear()).substring(2, 4) + ";
1046 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1048 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1050 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1052 return "this.getHours() + ";
1054 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1056 return "String.leftPad(this.getHours(), 2, '0') + ";
1058 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1060 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1062 return "this.getGMTOffset() + ";
1064 return "this.getTimezone() + ";
1066 return "(this.getTimezoneOffset() * -60) + ";
1068 return "'" + String.escape(character) + "' + ";
1073 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1074 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1075 * the date format that is not specified will default to the current date value for that part. Time parts can also
1076 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1077 * string or the parse operation will fail.
1080 //dt = Fri May 25 2007 (current date)
1081 var dt = new Date();
1083 //dt = Thu May 25 2006 (today's month/day in 2006)
1084 dt = Date.parseDate("2006", "Y");
1086 //dt = Sun Jan 15 2006 (all date parts specified)
1087 dt = Date.parseDate("2006-1-15", "Y-m-d");
1089 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1090 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1092 * @param {String} input The unparsed date as a string
1093 * @param {String} format The format the date is in
1094 * @return {Date} The parsed date
1097 Date.parseDate = function(input, format) {
1098 if (Date.parseFunctions[format] == null) {
1099 Date.createParser(format);
1101 var func = Date.parseFunctions[format];
1102 return Date[func](input);
1106 Date.createParser = function(format) {
1107 var funcName = "parse" + Date.parseFunctions.count++;
1108 var regexNum = Date.parseRegexes.length;
1109 var currentGroup = 1;
1110 Date.parseFunctions[format] = funcName;
1112 var code = "Date." + funcName + " = function(input){\n"
1113 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1114 + "var d = new Date();\n"
1115 + "y = d.getFullYear();\n"
1116 + "m = d.getMonth();\n"
1117 + "d = d.getDate();\n"
1118 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1119 + "if (results && results.length > 0) {";
1122 var special = false;
1124 for (var i = 0; i < format.length; ++i) {
1125 ch = format.charAt(i);
1126 if (!special && ch == "\\") {
1131 regex += String.escape(ch);
1134 var obj = Date.formatCodeToRegex(ch, currentGroup);
1135 currentGroup += obj.g;
1137 if (obj.g && obj.c) {
1143 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1144 + "{v = new Date(y, m, d, h, i, s);}\n"
1145 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1146 + "{v = new Date(y, m, d, h, i);}\n"
1147 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1148 + "{v = new Date(y, m, d, h);}\n"
1149 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1150 + "{v = new Date(y, m, d);}\n"
1151 + "else if (y >= 0 && m >= 0)\n"
1152 + "{v = new Date(y, m);}\n"
1153 + "else if (y >= 0)\n"
1154 + "{v = new Date(y);}\n"
1155 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1156 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1157 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1160 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1161 /** eval:var:zzzzzzzzzzzzz */
1166 Date.formatCodeToRegex = function(character, currentGroup) {
1167 switch (character) {
1171 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1174 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1175 s:"(\\d{1,2})"}; // day of month without leading zeroes
1178 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1179 s:"(\\d{2})"}; // day of month with leading zeroes
1183 s:"(?:" + Date.dayNames.join("|") + ")"};
1187 s:"(?:st|nd|rd|th)"};
1202 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1203 s:"(" + Date.monthNames.join("|") + ")"};
1206 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1207 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1210 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1211 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1214 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1215 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1226 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1230 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1231 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1235 c:"if (results[" + currentGroup + "] == 'am') {\n"
1236 + "if (h == 12) { h = 0; }\n"
1237 + "} else { if (h < 12) { h += 12; }}",
1241 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1242 + "if (h == 12) { h = 0; }\n"
1243 + "} else { if (h < 12) { h += 12; }}",
1248 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1249 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1253 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1254 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1257 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1261 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1266 "o = results[", currentGroup, "];\n",
1267 "var sn = o.substring(0,1);\n", // get + / - sign
1268 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1269 "var mn = o.substring(3,5) % 60;\n", // get minutes
1270 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1271 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1277 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1280 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1281 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1282 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1286 s:String.escape(character)};
1291 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1292 * @return {String} The abbreviated timezone name (e.g. 'CST')
1294 Date.prototype.getTimezone = function() {
1295 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1299 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1300 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1302 Date.prototype.getGMTOffset = function() {
1303 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1304 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1305 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1309 * Get the numeric day number of the year, adjusted for leap year.
1310 * @return {Number} 0 through 364 (365 in leap years)
1312 Date.prototype.getDayOfYear = function() {
1314 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1315 for (var i = 0; i < this.getMonth(); ++i) {
1316 num += Date.daysInMonth[i];
1318 return num + this.getDate() - 1;
1322 * Get the string representation of the numeric week number of the year
1323 * (equivalent to the format specifier 'W').
1324 * @return {String} '00' through '52'
1326 Date.prototype.getWeekOfYear = function() {
1327 // Skip to Thursday of this week
1328 var now = this.getDayOfYear() + (4 - this.getDay());
1329 // Find the first Thursday of the year
1330 var jan1 = new Date(this.getFullYear(), 0, 1);
1331 var then = (7 - jan1.getDay() + 4);
1332 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1336 * Whether or not the current date is in a leap year.
1337 * @return {Boolean} True if the current date is in a leap year, else false
1339 Date.prototype.isLeapYear = function() {
1340 var year = this.getFullYear();
1341 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1345 * Get the first day of the current month, adjusted for leap year. The returned value
1346 * is the numeric day index within the week (0-6) which can be used in conjunction with
1347 * the {@link #monthNames} array to retrieve the textual day name.
1350 var dt = new Date('1/10/2007');
1351 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1353 * @return {Number} The day number (0-6)
1355 Date.prototype.getFirstDayOfMonth = function() {
1356 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1357 return (day < 0) ? (day + 7) : day;
1361 * Get the last day of the current month, adjusted for leap year. The returned value
1362 * is the numeric day index within the week (0-6) which can be used in conjunction with
1363 * the {@link #monthNames} array to retrieve the textual day name.
1366 var dt = new Date('1/10/2007');
1367 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1369 * @return {Number} The day number (0-6)
1371 Date.prototype.getLastDayOfMonth = function() {
1372 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1373 return (day < 0) ? (day + 7) : day;
1378 * Get the first date of this date's month
1381 Date.prototype.getFirstDateOfMonth = function() {
1382 return new Date(this.getFullYear(), this.getMonth(), 1);
1386 * Get the last date of this date's month
1389 Date.prototype.getLastDateOfMonth = function() {
1390 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1393 * Get the number of days in the current month, adjusted for leap year.
1394 * @return {Number} The number of days in the month
1396 Date.prototype.getDaysInMonth = function() {
1397 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1398 return Date.daysInMonth[this.getMonth()];
1402 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1403 * @return {String} 'st, 'nd', 'rd' or 'th'
1405 Date.prototype.getSuffix = function() {
1406 switch (this.getDate()) {
1423 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1426 * An array of textual month names.
1427 * Override these values for international dates, for example...
1428 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1447 * An array of textual day names.
1448 * Override these values for international dates, for example...
1449 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1465 Date.monthNumbers = {
1480 * Creates and returns a new Date instance with the exact same date value as the called instance.
1481 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1482 * variable will also be changed. When the intention is to create a new variable that will not
1483 * modify the original instance, you should create a clone.
1485 * Example of correctly cloning a date:
1488 var orig = new Date('10/1/2006');
1491 document.write(orig); //returns 'Thu Oct 05 2006'!
1494 var orig = new Date('10/1/2006');
1495 var copy = orig.clone();
1497 document.write(orig); //returns 'Thu Oct 01 2006'
1499 * @return {Date} The new Date instance
1501 Date.prototype.clone = function() {
1502 return new Date(this.getTime());
1506 * Clears any time information from this date
1507 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1508 @return {Date} this or the clone
1510 Date.prototype.clearTime = function(clone){
1512 return this.clone().clearTime();
1517 this.setMilliseconds(0);
1522 // safari setMonth is broken
1524 Date.brokenSetMonth = Date.prototype.setMonth;
1525 Date.prototype.setMonth = function(num){
1527 var n = Math.ceil(-num);
1528 var back_year = Math.ceil(n/12);
1529 var month = (n % 12) ? 12 - n % 12 : 0 ;
1530 this.setFullYear(this.getFullYear() - back_year);
1531 return Date.brokenSetMonth.call(this, month);
1533 return Date.brokenSetMonth.apply(this, arguments);
1538 /** Date interval constant
1542 /** Date interval constant
1546 /** Date interval constant
1550 /** Date interval constant
1554 /** Date interval constant
1558 /** Date interval constant
1562 /** Date interval constant
1568 * Provides a convenient method of performing basic date arithmetic. This method
1569 * does not modify the Date instance being called - it creates and returns
1570 * a new Date instance containing the resulting date value.
1575 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1576 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1578 //Negative values will subtract correctly:
1579 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1580 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1582 //You can even chain several calls together in one line!
1583 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1584 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1587 * @param {String} interval A valid date interval enum value
1588 * @param {Number} value The amount to add to the current date
1589 * @return {Date} The new Date instance
1591 Date.prototype.add = function(interval, value){
1592 var d = this.clone();
1593 if (!interval || value === 0) return d;
1594 switch(interval.toLowerCase()){
1596 d.setMilliseconds(this.getMilliseconds() + value);
1599 d.setSeconds(this.getSeconds() + value);
1602 d.setMinutes(this.getMinutes() + value);
1605 d.setHours(this.getHours() + value);
1608 d.setDate(this.getDate() + value);
1611 var day = this.getDate();
1613 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1616 d.setMonth(this.getMonth() + value);
1619 d.setFullYear(this.getFullYear() + value);
1625 * Ext JS Library 1.1.1
1626 * Copyright(c) 2006-2007, Ext JS, LLC.
1628 * Originally Released Under LGPL - original licence link has changed is not relivant.
1631 * <script type="text/javascript">
1635 getViewWidth : function(full) {
1636 return full ? this.getDocumentWidth() : this.getViewportWidth();
1639 getViewHeight : function(full) {
1640 return full ? this.getDocumentHeight() : this.getViewportHeight();
1643 getDocumentHeight: function() {
1644 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1645 return Math.max(scrollHeight, this.getViewportHeight());
1648 getDocumentWidth: function() {
1649 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1650 return Math.max(scrollWidth, this.getViewportWidth());
1653 getViewportHeight: function() {
1654 var height = self.innerHeight;
1655 var mode = document.compatMode;
1657 if ((mode || Roo.isIE) && !Roo.isOpera) {
1658 height = (mode == "CSS1Compat") ?
1659 document.documentElement.clientHeight :
1660 document.body.clientHeight;
1666 getViewportWidth: function() {
1667 var width = self.innerWidth;
1668 var mode = document.compatMode;
1670 if (mode || Roo.isIE) {
1671 width = (mode == "CSS1Compat") ?
1672 document.documentElement.clientWidth :
1673 document.body.clientWidth;
1678 isAncestor : function(p, c) {
1685 if (p.contains && !Roo.isSafari) {
1686 return p.contains(c);
1687 } else if (p.compareDocumentPosition) {
1688 return !!(p.compareDocumentPosition(c) & 16);
1690 var parent = c.parentNode;
1695 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1698 parent = parent.parentNode;
1704 getRegion : function(el) {
1705 return Roo.lib.Region.getRegion(el);
1708 getY : function(el) {
1709 return this.getXY(el)[1];
1712 getX : function(el) {
1713 return this.getXY(el)[0];
1716 getXY : function(el) {
1717 var p, pe, b, scroll, bd = document.body;
1718 el = Roo.getDom(el);
1719 var fly = Roo.lib.AnimBase.fly;
1720 if (el.getBoundingClientRect) {
1721 b = el.getBoundingClientRect();
1722 scroll = fly(document).getScroll();
1723 return [b.left + scroll.left, b.top + scroll.top];
1729 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1736 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1743 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1744 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1751 if (p != el && pe.getStyle('overflow') != 'visible') {
1759 if (Roo.isSafari && hasAbsolute) {
1764 if (Roo.isGecko && !hasAbsolute) {
1766 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1767 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1771 while (p && p != bd) {
1772 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1784 setXY : function(el, xy) {
1785 el = Roo.fly(el, '_setXY');
1787 var pts = el.translatePoints(xy);
1788 if (xy[0] !== false) {
1789 el.dom.style.left = pts.left + "px";
1791 if (xy[1] !== false) {
1792 el.dom.style.top = pts.top + "px";
1796 setX : function(el, x) {
1797 this.setXY(el, [x, false]);
1800 setY : function(el, y) {
1801 this.setXY(el, [false, y]);
1805 * Portions of this file are based on pieces of Yahoo User Interface Library
1806 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1807 * YUI licensed under the BSD License:
1808 * http://developer.yahoo.net/yui/license.txt
1809 * <script type="text/javascript">
1813 Roo.lib.Event = function() {
1814 var loadComplete = false;
1816 var unloadListeners = [];
1818 var onAvailStack = [];
1820 var lastError = null;
1833 startInterval: function() {
1834 if (!this._interval) {
1836 var callback = function() {
1837 self._tryPreloadAttach();
1839 this._interval = setInterval(callback, this.POLL_INTERVAL);
1844 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1845 onAvailStack.push({ id: p_id,
1848 override: p_override,
1849 checkReady: false });
1851 retryCount = this.POLL_RETRYS;
1852 this.startInterval();
1856 addListener: function(el, eventName, fn) {
1857 el = Roo.getDom(el);
1862 if ("unload" == eventName) {
1863 unloadListeners[unloadListeners.length] =
1864 [el, eventName, fn];
1868 var wrappedFn = function(e) {
1869 return fn(Roo.lib.Event.getEvent(e));
1872 var li = [el, eventName, fn, wrappedFn];
1874 var index = listeners.length;
1875 listeners[index] = li;
1877 this.doAdd(el, eventName, wrappedFn, false);
1883 removeListener: function(el, eventName, fn) {
1886 el = Roo.getDom(el);
1889 return this.purgeElement(el, false, eventName);
1893 if ("unload" == eventName) {
1895 for (i = 0,len = unloadListeners.length; i < len; i++) {
1896 var li = unloadListeners[i];
1899 li[1] == eventName &&
1901 unloadListeners.splice(i, 1);
1909 var cacheItem = null;
1912 var index = arguments[3];
1914 if ("undefined" == typeof index) {
1915 index = this._getCacheIndex(el, eventName, fn);
1919 cacheItem = listeners[index];
1922 if (!el || !cacheItem) {
1926 this.doRemove(el, eventName, cacheItem[this.WFN], false);
1928 delete listeners[index][this.WFN];
1929 delete listeners[index][this.FN];
1930 listeners.splice(index, 1);
1937 getTarget: function(ev, resolveTextNode) {
1938 ev = ev.browserEvent || ev;
1939 var t = ev.target || ev.srcElement;
1940 return this.resolveTextNode(t);
1944 resolveTextNode: function(node) {
1945 if (Roo.isSafari && node && 3 == node.nodeType) {
1946 return node.parentNode;
1953 getPageX: function(ev) {
1954 ev = ev.browserEvent || ev;
1956 if (!x && 0 !== x) {
1957 x = ev.clientX || 0;
1960 x += this.getScroll()[1];
1968 getPageY: function(ev) {
1969 ev = ev.browserEvent || ev;
1971 if (!y && 0 !== y) {
1972 y = ev.clientY || 0;
1975 y += this.getScroll()[0];
1984 getXY: function(ev) {
1985 ev = ev.browserEvent || ev;
1986 return [this.getPageX(ev), this.getPageY(ev)];
1990 getRelatedTarget: function(ev) {
1991 ev = ev.browserEvent || ev;
1992 var t = ev.relatedTarget;
1994 if (ev.type == "mouseout") {
1996 } else if (ev.type == "mouseover") {
2001 return this.resolveTextNode(t);
2005 getTime: function(ev) {
2006 ev = ev.browserEvent || ev;
2008 var t = new Date().getTime();
2012 this.lastError = ex;
2021 stopEvent: function(ev) {
2022 this.stopPropagation(ev);
2023 this.preventDefault(ev);
2027 stopPropagation: function(ev) {
2028 ev = ev.browserEvent || ev;
2029 if (ev.stopPropagation) {
2030 ev.stopPropagation();
2032 ev.cancelBubble = true;
2037 preventDefault: function(ev) {
2038 ev = ev.browserEvent || ev;
2039 if(ev.preventDefault) {
2040 ev.preventDefault();
2042 ev.returnValue = false;
2047 getEvent: function(e) {
2048 var ev = e || window.event;
2050 var c = this.getEvent.caller;
2052 ev = c.arguments[0];
2053 if (ev && Event == ev.constructor) {
2063 getCharCode: function(ev) {
2064 ev = ev.browserEvent || ev;
2065 return ev.charCode || ev.keyCode || 0;
2069 _getCacheIndex: function(el, eventName, fn) {
2070 for (var i = 0,len = listeners.length; i < len; ++i) {
2071 var li = listeners[i];
2073 li[this.FN] == fn &&
2074 li[this.EL] == el &&
2075 li[this.TYPE] == eventName) {
2087 getEl: function(id) {
2088 return document.getElementById(id);
2092 clearCache: function() {
2096 _load: function(e) {
2097 loadComplete = true;
2098 var EU = Roo.lib.Event;
2102 EU.doRemove(window, "load", EU._load);
2107 _tryPreloadAttach: function() {
2116 var tryAgain = !loadComplete;
2118 tryAgain = (retryCount > 0);
2123 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2124 var item = onAvailStack[i];
2126 var el = this.getEl(item.id);
2129 if (!item.checkReady ||
2132 (document && document.body)) {
2135 if (item.override) {
2136 if (item.override === true) {
2139 scope = item.override;
2142 item.fn.call(scope, item.obj);
2143 onAvailStack[i] = null;
2146 notAvail.push(item);
2151 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2155 this.startInterval();
2157 clearInterval(this._interval);
2158 this._interval = null;
2161 this.locked = false;
2168 purgeElement: function(el, recurse, eventName) {
2169 var elListeners = this.getListeners(el, eventName);
2171 for (var i = 0,len = elListeners.length; i < len; ++i) {
2172 var l = elListeners[i];
2173 this.removeListener(el, l.type, l.fn);
2177 if (recurse && el && el.childNodes) {
2178 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2179 this.purgeElement(el.childNodes[i], recurse, eventName);
2185 getListeners: function(el, eventName) {
2186 var results = [], searchLists;
2188 searchLists = [listeners, unloadListeners];
2189 } else if (eventName == "unload") {
2190 searchLists = [unloadListeners];
2192 searchLists = [listeners];
2195 for (var j = 0; j < searchLists.length; ++j) {
2196 var searchList = searchLists[j];
2197 if (searchList && searchList.length > 0) {
2198 for (var i = 0,len = searchList.length; i < len; ++i) {
2199 var l = searchList[i];
2200 if (l && l[this.EL] === el &&
2201 (!eventName || eventName === l[this.TYPE])) {
2206 adjust: l[this.ADJ_SCOPE],
2214 return (results.length) ? results : null;
2218 _unload: function(e) {
2220 var EU = Roo.lib.Event, i, j, l, len, index;
2222 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2223 l = unloadListeners[i];
2226 if (l[EU.ADJ_SCOPE]) {
2227 if (l[EU.ADJ_SCOPE] === true) {
2230 scope = l[EU.ADJ_SCOPE];
2233 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2234 unloadListeners[i] = null;
2240 unloadListeners = null;
2242 if (listeners && listeners.length > 0) {
2243 j = listeners.length;
2246 l = listeners[index];
2248 EU.removeListener(l[EU.EL], l[EU.TYPE],
2258 EU.doRemove(window, "unload", EU._unload);
2263 getScroll: function() {
2264 var dd = document.documentElement, db = document.body;
2265 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2266 return [dd.scrollTop, dd.scrollLeft];
2268 return [db.scrollTop, db.scrollLeft];
2275 doAdd: function () {
2276 if (window.addEventListener) {
2277 return function(el, eventName, fn, capture) {
2278 el.addEventListener(eventName, fn, (capture));
2280 } else if (window.attachEvent) {
2281 return function(el, eventName, fn, capture) {
2282 el.attachEvent("on" + eventName, fn);
2291 doRemove: function() {
2292 if (window.removeEventListener) {
2293 return function (el, eventName, fn, capture) {
2294 el.removeEventListener(eventName, fn, (capture));
2296 } else if (window.detachEvent) {
2297 return function (el, eventName, fn) {
2298 el.detachEvent("on" + eventName, fn);
2310 var E = Roo.lib.Event;
2311 E.on = E.addListener;
2312 E.un = E.removeListener;
2314 if (document && document.body) {
2317 E.doAdd(window, "load", E._load);
2319 E.doAdd(window, "unload", E._unload);
2320 E._tryPreloadAttach();
2324 * Portions of this file are based on pieces of Yahoo User Interface Library
2325 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2326 * YUI licensed under the BSD License:
2327 * http://developer.yahoo.net/yui/license.txt
2328 * <script type="text/javascript">
2335 request : function(method, uri, cb, data, options) {
2337 var hs = options.headers;
2340 if(hs.hasOwnProperty(h)){
2341 this.initHeader(h, hs[h], false);
2345 if(options.xmlData){
2346 this.initHeader('Content-Type', 'text/xml', false);
2348 data = options.xmlData;
2352 return this.asyncRequest(method, uri, cb, data);
2355 serializeForm : function(form) {
2356 if(typeof form == 'string') {
2357 form = (document.getElementById(form) || document.forms[form]);
2360 var el, name, val, disabled, data = '', hasSubmit = false;
2361 for (var i = 0; i < form.elements.length; i++) {
2362 el = form.elements[i];
2363 disabled = form.elements[i].disabled;
2364 name = form.elements[i].name;
2365 val = form.elements[i].value;
2367 if (!disabled && name){
2371 case 'select-multiple':
2372 for (var j = 0; j < el.options.length; j++) {
2373 if (el.options[j].selected) {
2375 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2378 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2386 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2399 if(hasSubmit == false) {
2400 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2405 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2410 data = data.substr(0, data.length - 1);
2418 useDefaultHeader:true,
2420 defaultPostHeader:'application/x-www-form-urlencoded',
2422 useDefaultXhrHeader:true,
2424 defaultXhrHeader:'XMLHttpRequest',
2426 hasDefaultHeaders:true,
2438 setProgId:function(id)
2440 this.activeX.unshift(id);
2443 setDefaultPostHeader:function(b)
2445 this.useDefaultHeader = b;
2448 setDefaultXhrHeader:function(b)
2450 this.useDefaultXhrHeader = b;
2453 setPollingInterval:function(i)
2455 if (typeof i == 'number' && isFinite(i)) {
2456 this.pollInterval = i;
2460 createXhrObject:function(transactionId)
2466 http = new XMLHttpRequest();
2468 obj = { conn:http, tId:transactionId };
2472 for (var i = 0; i < this.activeX.length; ++i) {
2476 http = new ActiveXObject(this.activeX[i]);
2478 obj = { conn:http, tId:transactionId };
2491 getConnectionObject:function()
2494 var tId = this.transactionId;
2498 o = this.createXhrObject(tId);
2500 this.transactionId++;
2511 asyncRequest:function(method, uri, callback, postData)
2513 var o = this.getConnectionObject();
2519 o.conn.open(method, uri, true);
2521 if (this.useDefaultXhrHeader) {
2522 if (!this.defaultHeaders['X-Requested-With']) {
2523 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2527 if(postData && this.useDefaultHeader){
2528 this.initHeader('Content-Type', this.defaultPostHeader);
2531 if (this.hasDefaultHeaders || this.hasHeaders) {
2535 this.handleReadyState(o, callback);
2536 o.conn.send(postData || null);
2542 handleReadyState:function(o, callback)
2546 if (callback && callback.timeout) {
2547 this.timeout[o.tId] = window.setTimeout(function() {
2548 oConn.abort(o, callback, true);
2549 }, callback.timeout);
2552 this.poll[o.tId] = window.setInterval(
2554 if (o.conn && o.conn.readyState == 4) {
2555 window.clearInterval(oConn.poll[o.tId]);
2556 delete oConn.poll[o.tId];
2558 if(callback && callback.timeout) {
2559 window.clearTimeout(oConn.timeout[o.tId]);
2560 delete oConn.timeout[o.tId];
2563 oConn.handleTransactionResponse(o, callback);
2566 , this.pollInterval);
2569 handleTransactionResponse:function(o, callback, isAbort)
2573 this.releaseObject(o);
2577 var httpStatus, responseObject;
2581 if (o.conn.status !== undefined && o.conn.status != 0) {
2582 httpStatus = o.conn.status;
2594 if (httpStatus >= 200 && httpStatus < 300) {
2595 responseObject = this.createResponseObject(o, callback.argument);
2596 if (callback.success) {
2597 if (!callback.scope) {
2598 callback.success(responseObject);
2603 callback.success.apply(callback.scope, [responseObject]);
2608 switch (httpStatus) {
2616 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2617 if (callback.failure) {
2618 if (!callback.scope) {
2619 callback.failure(responseObject);
2622 callback.failure.apply(callback.scope, [responseObject]);
2627 responseObject = this.createResponseObject(o, callback.argument);
2628 if (callback.failure) {
2629 if (!callback.scope) {
2630 callback.failure(responseObject);
2633 callback.failure.apply(callback.scope, [responseObject]);
2639 this.releaseObject(o);
2640 responseObject = null;
2643 createResponseObject:function(o, callbackArg)
2650 var headerStr = o.conn.getAllResponseHeaders();
2651 var header = headerStr.split('\n');
2652 for (var i = 0; i < header.length; i++) {
2653 var delimitPos = header[i].indexOf(':');
2654 if (delimitPos != -1) {
2655 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2663 obj.status = o.conn.status;
2664 obj.statusText = o.conn.statusText;
2665 obj.getResponseHeader = headerObj;
2666 obj.getAllResponseHeaders = headerStr;
2667 obj.responseText = o.conn.responseText;
2668 obj.responseXML = o.conn.responseXML;
2670 if (typeof callbackArg !== undefined) {
2671 obj.argument = callbackArg;
2677 createExceptionObject:function(tId, callbackArg, isAbort)
2680 var COMM_ERROR = 'communication failure';
2681 var ABORT_CODE = -1;
2682 var ABORT_ERROR = 'transaction aborted';
2688 obj.status = ABORT_CODE;
2689 obj.statusText = ABORT_ERROR;
2692 obj.status = COMM_CODE;
2693 obj.statusText = COMM_ERROR;
2697 obj.argument = callbackArg;
2703 initHeader:function(label, value, isDefault)
2705 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2707 if (headerObj[label] === undefined) {
2708 headerObj[label] = value;
2713 headerObj[label] = value + "," + headerObj[label];
2717 this.hasDefaultHeaders = true;
2720 this.hasHeaders = true;
2725 setHeader:function(o)
2727 if (this.hasDefaultHeaders) {
2728 for (var prop in this.defaultHeaders) {
2729 if (this.defaultHeaders.hasOwnProperty(prop)) {
2730 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2735 if (this.hasHeaders) {
2736 for (var prop in this.headers) {
2737 if (this.headers.hasOwnProperty(prop)) {
2738 o.conn.setRequestHeader(prop, this.headers[prop]);
2742 this.hasHeaders = false;
2746 resetDefaultHeaders:function() {
2747 delete this.defaultHeaders;
2748 this.defaultHeaders = {};
2749 this.hasDefaultHeaders = false;
2752 abort:function(o, callback, isTimeout)
2754 if(this.isCallInProgress(o)) {
2756 window.clearInterval(this.poll[o.tId]);
2757 delete this.poll[o.tId];
2759 delete this.timeout[o.tId];
2762 this.handleTransactionResponse(o, callback, true);
2772 isCallInProgress:function(o)
2775 return o.conn.readyState != 4 && o.conn.readyState != 0;
2784 releaseObject:function(o)
2793 'MSXML2.XMLHTTP.3.0',
2801 * Portions of this file are based on pieces of Yahoo User Interface Library
2802 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2803 * YUI licensed under the BSD License:
2804 * http://developer.yahoo.net/yui/license.txt
2805 * <script type="text/javascript">
2809 Roo.lib.Region = function(t, r, b, l) {
2819 Roo.lib.Region.prototype = {
2820 contains : function(region) {
2821 return ( region.left >= this.left &&
2822 region.right <= this.right &&
2823 region.top >= this.top &&
2824 region.bottom <= this.bottom );
2828 getArea : function() {
2829 return ( (this.bottom - this.top) * (this.right - this.left) );
2832 intersect : function(region) {
2833 var t = Math.max(this.top, region.top);
2834 var r = Math.min(this.right, region.right);
2835 var b = Math.min(this.bottom, region.bottom);
2836 var l = Math.max(this.left, region.left);
2838 if (b >= t && r >= l) {
2839 return new Roo.lib.Region(t, r, b, l);
2844 union : function(region) {
2845 var t = Math.min(this.top, region.top);
2846 var r = Math.max(this.right, region.right);
2847 var b = Math.max(this.bottom, region.bottom);
2848 var l = Math.min(this.left, region.left);
2850 return new Roo.lib.Region(t, r, b, l);
2853 adjust : function(t, l, b, r) {
2862 Roo.lib.Region.getRegion = function(el) {
2863 var p = Roo.lib.Dom.getXY(el);
2866 var r = p[0] + el.offsetWidth;
2867 var b = p[1] + el.offsetHeight;
2870 return new Roo.lib.Region(t, r, b, l);
2873 * Portions of this file are based on pieces of Yahoo User Interface Library
2874 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2875 * YUI licensed under the BSD License:
2876 * http://developer.yahoo.net/yui/license.txt
2877 * <script type="text/javascript">
2880 //@@dep Roo.lib.Region
2883 Roo.lib.Point = function(x, y) {
2884 if (x instanceof Array) {
2888 this.x = this.right = this.left = this[0] = x;
2889 this.y = this.top = this.bottom = this[1] = y;
2892 Roo.lib.Point.prototype = new Roo.lib.Region();
2894 * Portions of this file are based on pieces of Yahoo User Interface Library
2895 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2896 * YUI licensed under the BSD License:
2897 * http://developer.yahoo.net/yui/license.txt
2898 * <script type="text/javascript">
2905 scroll : function(el, args, duration, easing, cb, scope) {
2906 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2909 motion : function(el, args, duration, easing, cb, scope) {
2910 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2913 color : function(el, args, duration, easing, cb, scope) {
2914 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2917 run : function(el, args, duration, easing, cb, scope, type) {
2918 type = type || Roo.lib.AnimBase;
2919 if (typeof easing == "string") {
2920 easing = Roo.lib.Easing[easing];
2922 var anim = new type(el, args, duration, easing);
2923 anim.animateX(function() {
2924 Roo.callback(cb, scope);
2930 * Portions of this file are based on pieces of Yahoo User Interface Library
2931 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2932 * YUI licensed under the BSD License:
2933 * http://developer.yahoo.net/yui/license.txt
2934 * <script type="text/javascript">
2942 if (!libFlyweight) {
2943 libFlyweight = new Roo.Element.Flyweight();
2945 libFlyweight.dom = el;
2946 return libFlyweight;
2949 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2953 Roo.lib.AnimBase = function(el, attributes, duration, method) {
2955 this.init(el, attributes, duration, method);
2959 Roo.lib.AnimBase.fly = fly;
2963 Roo.lib.AnimBase.prototype = {
2965 toString: function() {
2966 var el = this.getEl();
2967 var id = el.id || el.tagName;
2968 return ("Anim " + id);
2972 noNegatives: /width|height|opacity|padding/i,
2973 offsetAttribute: /^((width|height)|(top|left))$/,
2974 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
2975 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
2979 doMethod: function(attr, start, end) {
2980 return this.method(this.currentFrame, start, end - start, this.totalFrames);
2984 setAttribute: function(attr, val, unit) {
2985 if (this.patterns.noNegatives.test(attr)) {
2986 val = (val > 0) ? val : 0;
2989 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
2993 getAttribute: function(attr) {
2994 var el = this.getEl();
2995 var val = fly(el).getStyle(attr);
2997 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
2998 return parseFloat(val);
3001 var a = this.patterns.offsetAttribute.exec(attr) || [];
3002 var pos = !!( a[3] );
3003 var box = !!( a[2] );
3006 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3007 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3016 getDefaultUnit: function(attr) {
3017 if (this.patterns.defaultUnit.test(attr)) {
3024 animateX : function(callback, scope) {
3025 var f = function() {
3026 this.onComplete.removeListener(f);
3027 if (typeof callback == "function") {
3028 callback.call(scope || this, this);
3031 this.onComplete.addListener(f, this);
3036 setRuntimeAttribute: function(attr) {
3039 var attributes = this.attributes;
3041 this.runtimeAttributes[attr] = {};
3043 var isset = function(prop) {
3044 return (typeof prop !== 'undefined');
3047 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3051 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3054 if (isset(attributes[attr]['to'])) {
3055 end = attributes[attr]['to'];
3056 } else if (isset(attributes[attr]['by'])) {
3057 if (start.constructor == Array) {
3059 for (var i = 0, len = start.length; i < len; ++i) {
3060 end[i] = start[i] + attributes[attr]['by'][i];
3063 end = start + attributes[attr]['by'];
3067 this.runtimeAttributes[attr].start = start;
3068 this.runtimeAttributes[attr].end = end;
3071 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3075 init: function(el, attributes, duration, method) {
3077 var isAnimated = false;
3080 var startTime = null;
3083 var actualFrames = 0;
3086 el = Roo.getDom(el);
3089 this.attributes = attributes || {};
3092 this.duration = duration || 1;
3095 this.method = method || Roo.lib.Easing.easeNone;
3098 this.useSeconds = true;
3101 this.currentFrame = 0;
3104 this.totalFrames = Roo.lib.AnimMgr.fps;
3107 this.getEl = function() {
3112 this.isAnimated = function() {
3117 this.getStartTime = function() {
3121 this.runtimeAttributes = {};
3124 this.animate = function() {
3125 if (this.isAnimated()) {
3129 this.currentFrame = 0;
3131 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3133 Roo.lib.AnimMgr.registerElement(this);
3137 this.stop = function(finish) {
3139 this.currentFrame = this.totalFrames;
3140 this._onTween.fire();
3142 Roo.lib.AnimMgr.stop(this);
3145 var onStart = function() {
3146 this.onStart.fire();
3148 this.runtimeAttributes = {};
3149 for (var attr in this.attributes) {
3150 this.setRuntimeAttribute(attr);
3155 startTime = new Date();
3159 var onTween = function() {
3161 duration: new Date() - this.getStartTime(),
3162 currentFrame: this.currentFrame
3165 data.toString = function() {
3167 'duration: ' + data.duration +
3168 ', currentFrame: ' + data.currentFrame
3172 this.onTween.fire(data);
3174 var runtimeAttributes = this.runtimeAttributes;
3176 for (var attr in runtimeAttributes) {
3177 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3183 var onComplete = function() {
3184 var actual_duration = (new Date() - startTime) / 1000 ;
3187 duration: actual_duration,
3188 frames: actualFrames,
3189 fps: actualFrames / actual_duration
3192 data.toString = function() {
3194 'duration: ' + data.duration +
3195 ', frames: ' + data.frames +
3196 ', fps: ' + data.fps
3202 this.onComplete.fire(data);
3206 this._onStart = new Roo.util.Event(this);
3207 this.onStart = new Roo.util.Event(this);
3208 this.onTween = new Roo.util.Event(this);
3209 this._onTween = new Roo.util.Event(this);
3210 this.onComplete = new Roo.util.Event(this);
3211 this._onComplete = new Roo.util.Event(this);
3212 this._onStart.addListener(onStart);
3213 this._onTween.addListener(onTween);
3214 this._onComplete.addListener(onComplete);
3219 * Portions of this file are based on pieces of Yahoo User Interface Library
3220 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3221 * YUI licensed under the BSD License:
3222 * http://developer.yahoo.net/yui/license.txt
3223 * <script type="text/javascript">
3227 Roo.lib.AnimMgr = new function() {
3244 this.registerElement = function(tween) {
3245 queue[queue.length] = tween;
3247 tween._onStart.fire();
3252 this.unRegister = function(tween, index) {
3253 tween._onComplete.fire();
3254 index = index || getIndex(tween);
3256 queue.splice(index, 1);
3260 if (tweenCount <= 0) {
3266 this.start = function() {
3267 if (thread === null) {
3268 thread = setInterval(this.run, this.delay);
3273 this.stop = function(tween) {
3275 clearInterval(thread);
3277 for (var i = 0, len = queue.length; i < len; ++i) {
3278 if (queue[0].isAnimated()) {
3279 this.unRegister(queue[0], 0);
3288 this.unRegister(tween);
3293 this.run = function() {
3294 for (var i = 0, len = queue.length; i < len; ++i) {
3295 var tween = queue[i];
3296 if (!tween || !tween.isAnimated()) {
3300 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3302 tween.currentFrame += 1;
3304 if (tween.useSeconds) {
3305 correctFrame(tween);
3307 tween._onTween.fire();
3310 Roo.lib.AnimMgr.stop(tween, i);
3315 var getIndex = function(anim) {
3316 for (var i = 0, len = queue.length; i < len; ++i) {
3317 if (queue[i] == anim) {
3325 var correctFrame = function(tween) {
3326 var frames = tween.totalFrames;
3327 var frame = tween.currentFrame;
3328 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3329 var elapsed = (new Date() - tween.getStartTime());
3332 if (elapsed < tween.duration * 1000) {
3333 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3335 tweak = frames - (frame + 1);
3337 if (tweak > 0 && isFinite(tweak)) {
3338 if (tween.currentFrame + tweak >= frames) {
3339 tweak = frames - (frame + 1);
3342 tween.currentFrame += tweak;
3346 * Portions of this file are based on pieces of Yahoo User Interface Library
3347 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3348 * YUI licensed under the BSD License:
3349 * http://developer.yahoo.net/yui/license.txt
3350 * <script type="text/javascript">
3353 Roo.lib.Bezier = new function() {
3355 this.getPosition = function(points, t) {
3356 var n = points.length;
3359 for (var i = 0; i < n; ++i) {
3360 tmp[i] = [points[i][0], points[i][1]];
3363 for (var j = 1; j < n; ++j) {
3364 for (i = 0; i < n - j; ++i) {
3365 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3366 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3370 return [ tmp[0][0], tmp[0][1] ];
3374 * Portions of this file are based on pieces of Yahoo User Interface Library
3375 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3376 * YUI licensed under the BSD License:
3377 * http://developer.yahoo.net/yui/license.txt
3378 * <script type="text/javascript">
3383 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3384 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3387 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3389 var fly = Roo.lib.AnimBase.fly;
3391 var superclass = Y.ColorAnim.superclass;
3392 var proto = Y.ColorAnim.prototype;
3394 proto.toString = function() {
3395 var el = this.getEl();
3396 var id = el.id || el.tagName;
3397 return ("ColorAnim " + id);
3400 proto.patterns.color = /color$/i;
3401 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3402 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3403 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3404 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3407 proto.parseColor = function(s) {
3408 if (s.length == 3) {
3412 var c = this.patterns.hex.exec(s);
3413 if (c && c.length == 4) {
3414 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3417 c = this.patterns.rgb.exec(s);
3418 if (c && c.length == 4) {
3419 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3422 c = this.patterns.hex3.exec(s);
3423 if (c && c.length == 4) {
3424 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3429 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3430 proto.getAttribute = function(attr) {
3431 var el = this.getEl();
3432 if (this.patterns.color.test(attr)) {
3433 var val = fly(el).getStyle(attr);
3435 if (this.patterns.transparent.test(val)) {
3436 var parent = el.parentNode;
3437 val = fly(parent).getStyle(attr);
3439 while (parent && this.patterns.transparent.test(val)) {
3440 parent = parent.parentNode;
3441 val = fly(parent).getStyle(attr);
3442 if (parent.tagName.toUpperCase() == 'HTML') {
3448 val = superclass.getAttribute.call(this, attr);
3453 proto.getAttribute = function(attr) {
3454 var el = this.getEl();
3455 if (this.patterns.color.test(attr)) {
3456 var val = fly(el).getStyle(attr);
3458 if (this.patterns.transparent.test(val)) {
3459 var parent = el.parentNode;
3460 val = fly(parent).getStyle(attr);
3462 while (parent && this.patterns.transparent.test(val)) {
3463 parent = parent.parentNode;
3464 val = fly(parent).getStyle(attr);
3465 if (parent.tagName.toUpperCase() == 'HTML') {
3471 val = superclass.getAttribute.call(this, attr);
3477 proto.doMethod = function(attr, start, end) {
3480 if (this.patterns.color.test(attr)) {
3482 for (var i = 0, len = start.length; i < len; ++i) {
3483 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3486 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3489 val = superclass.doMethod.call(this, attr, start, end);
3495 proto.setRuntimeAttribute = function(attr) {
3496 superclass.setRuntimeAttribute.call(this, attr);
3498 if (this.patterns.color.test(attr)) {
3499 var attributes = this.attributes;
3500 var start = this.parseColor(this.runtimeAttributes[attr].start);
3501 var end = this.parseColor(this.runtimeAttributes[attr].end);
3503 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3504 end = this.parseColor(attributes[attr].by);
3506 for (var i = 0, len = start.length; i < len; ++i) {
3507 end[i] = start[i] + end[i];
3511 this.runtimeAttributes[attr].start = start;
3512 this.runtimeAttributes[attr].end = end;
3518 * Portions of this file are based on pieces of Yahoo User Interface Library
3519 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3520 * YUI licensed under the BSD License:
3521 * http://developer.yahoo.net/yui/license.txt
3522 * <script type="text/javascript">
3528 easeNone: function (t, b, c, d) {
3529 return c * t / d + b;
3533 easeIn: function (t, b, c, d) {
3534 return c * (t /= d) * t + b;
3538 easeOut: function (t, b, c, d) {
3539 return -c * (t /= d) * (t - 2) + b;
3543 easeBoth: function (t, b, c, d) {
3544 if ((t /= d / 2) < 1) {
3545 return c / 2 * t * t + b;
3548 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3552 easeInStrong: function (t, b, c, d) {
3553 return c * (t /= d) * t * t * t + b;
3557 easeOutStrong: function (t, b, c, d) {
3558 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3562 easeBothStrong: function (t, b, c, d) {
3563 if ((t /= d / 2) < 1) {
3564 return c / 2 * t * t * t * t + b;
3567 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3572 elasticIn: function (t, b, c, d, a, p) {
3576 if ((t /= d) == 1) {
3583 if (!a || a < Math.abs(c)) {
3588 var s = p / (2 * Math.PI) * Math.asin(c / a);
3591 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3595 elasticOut: function (t, b, c, d, a, p) {
3599 if ((t /= d) == 1) {
3606 if (!a || a < Math.abs(c)) {
3611 var s = p / (2 * Math.PI) * Math.asin(c / a);
3614 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3618 elasticBoth: function (t, b, c, d, a, p) {
3623 if ((t /= d / 2) == 2) {
3631 if (!a || a < Math.abs(c)) {
3636 var s = p / (2 * Math.PI) * Math.asin(c / a);
3640 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3641 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3643 return a * Math.pow(2, -10 * (t -= 1)) *
3644 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3649 backIn: function (t, b, c, d, s) {
3650 if (typeof s == 'undefined') {
3653 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3657 backOut: function (t, b, c, d, s) {
3658 if (typeof s == 'undefined') {
3661 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3665 backBoth: function (t, b, c, d, s) {
3666 if (typeof s == 'undefined') {
3670 if ((t /= d / 2 ) < 1) {
3671 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3673 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3677 bounceIn: function (t, b, c, d) {
3678 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3682 bounceOut: function (t, b, c, d) {
3683 if ((t /= d) < (1 / 2.75)) {
3684 return c * (7.5625 * t * t) + b;
3685 } else if (t < (2 / 2.75)) {
3686 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3687 } else if (t < (2.5 / 2.75)) {
3688 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3690 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3694 bounceBoth: function (t, b, c, d) {
3696 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3698 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3701 * Portions of this file are based on pieces of Yahoo User Interface Library
3702 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3703 * YUI licensed under the BSD License:
3704 * http://developer.yahoo.net/yui/license.txt
3705 * <script type="text/javascript">
3709 Roo.lib.Motion = function(el, attributes, duration, method) {
3711 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3715 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3719 var superclass = Y.Motion.superclass;
3720 var proto = Y.Motion.prototype;
3722 proto.toString = function() {
3723 var el = this.getEl();
3724 var id = el.id || el.tagName;
3725 return ("Motion " + id);
3728 proto.patterns.points = /^points$/i;
3730 proto.setAttribute = function(attr, val, unit) {
3731 if (this.patterns.points.test(attr)) {
3732 unit = unit || 'px';
3733 superclass.setAttribute.call(this, 'left', val[0], unit);
3734 superclass.setAttribute.call(this, 'top', val[1], unit);
3736 superclass.setAttribute.call(this, attr, val, unit);
3740 proto.getAttribute = function(attr) {
3741 if (this.patterns.points.test(attr)) {
3743 superclass.getAttribute.call(this, 'left'),
3744 superclass.getAttribute.call(this, 'top')
3747 val = superclass.getAttribute.call(this, attr);
3753 proto.doMethod = function(attr, start, end) {
3756 if (this.patterns.points.test(attr)) {
3757 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3758 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3760 val = superclass.doMethod.call(this, attr, start, end);
3765 proto.setRuntimeAttribute = function(attr) {
3766 if (this.patterns.points.test(attr)) {
3767 var el = this.getEl();
3768 var attributes = this.attributes;
3770 var control = attributes['points']['control'] || [];
3774 if (control.length > 0 && !(control[0] instanceof Array)) {
3775 control = [control];
3778 for (i = 0,len = control.length; i < len; ++i) {
3779 tmp[i] = control[i];
3784 Roo.fly(el).position();
3786 if (isset(attributes['points']['from'])) {
3787 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3790 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3793 start = this.getAttribute('points');
3796 if (isset(attributes['points']['to'])) {
3797 end = translateValues.call(this, attributes['points']['to'], start);
3799 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3800 for (i = 0,len = control.length; i < len; ++i) {
3801 control[i] = translateValues.call(this, control[i], start);
3805 } else if (isset(attributes['points']['by'])) {
3806 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3808 for (i = 0,len = control.length; i < len; ++i) {
3809 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3813 this.runtimeAttributes[attr] = [start];
3815 if (control.length > 0) {
3816 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3819 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3822 superclass.setRuntimeAttribute.call(this, attr);
3826 var translateValues = function(val, start) {
3827 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3828 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3833 var isset = function(prop) {
3834 return (typeof prop !== 'undefined');
3838 * Portions of this file are based on pieces of Yahoo User Interface Library
3839 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3840 * YUI licensed under the BSD License:
3841 * http://developer.yahoo.net/yui/license.txt
3842 * <script type="text/javascript">
3846 Roo.lib.Scroll = function(el, attributes, duration, method) {
3848 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3852 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3856 var superclass = Y.Scroll.superclass;
3857 var proto = Y.Scroll.prototype;
3859 proto.toString = function() {
3860 var el = this.getEl();
3861 var id = el.id || el.tagName;
3862 return ("Scroll " + id);
3865 proto.doMethod = function(attr, start, end) {
3868 if (attr == 'scroll') {
3870 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3871 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3875 val = superclass.doMethod.call(this, attr, start, end);
3880 proto.getAttribute = function(attr) {
3882 var el = this.getEl();
3884 if (attr == 'scroll') {
3885 val = [ el.scrollLeft, el.scrollTop ];
3887 val = superclass.getAttribute.call(this, attr);
3893 proto.setAttribute = function(attr, val, unit) {
3894 var el = this.getEl();
3896 if (attr == 'scroll') {
3897 el.scrollLeft = val[0];
3898 el.scrollTop = val[1];
3900 superclass.setAttribute.call(this, attr, val, unit);
3906 * Ext JS Library 1.1.1
3907 * Copyright(c) 2006-2007, Ext JS, LLC.
3909 * Originally Released Under LGPL - original licence link has changed is not relivant.
3912 * <script type="text/javascript">
3917 * @class Roo.DomHelper
3918 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3919 * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
3922 Roo.DomHelper = function(){
3923 var tempTableEl = null;
3924 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3925 var tableRe = /^table|tbody|tr|td$/i;
3927 // build as innerHTML where available
3929 var createHtml = function(o){
3930 if(typeof o == 'string'){
3939 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3940 if(attr == "style"){
3942 if(typeof s == "function"){
3945 if(typeof s == "string"){
3946 b += ' style="' + s + '"';
3947 }else if(typeof s == "object"){
3950 if(typeof s[key] != "function"){
3951 b += key + ":" + s[key] + ";";
3958 b += ' class="' + o["cls"] + '"';
3959 }else if(attr == "htmlFor"){
3960 b += ' for="' + o["htmlFor"] + '"';
3962 b += " " + attr + '="' + o[attr] + '"';
3966 if(emptyTags.test(o.tag)){
3970 var cn = o.children || o.cn;
3972 //http://bugs.kde.org/show_bug.cgi?id=71506
3973 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
3974 for(var i = 0, len = cn.length; i < len; i++) {
3975 b += createHtml(cn[i], b);
3978 b += createHtml(cn, b);
3984 b += "</" + o.tag + ">";
3991 var createDom = function(o, parentNode){
3993 // defininition craeted..
3995 if (o.ns && o.ns != 'html') {
3997 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
3998 xmlns[o.ns] = o.xmlns;
4001 if (typeof(xmlns[o.ns]) == 'undefined') {
4002 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4008 if (typeof(o) == 'string') {
4009 return parentNode.appendChild(document.createTextNode(o));
4011 o.tag = o.tag || div;
4012 if (o.ns && Roo.isIE) {
4014 o.tag = o.ns + ':' + o.tag;
4017 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4018 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4021 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4022 attr == "style" || typeof o[attr] == "function") continue;
4024 if(attr=="cls" && Roo.isIE){
4025 el.className = o["cls"];
4027 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4028 else el[attr] = o[attr];
4031 Roo.DomHelper.applyStyles(el, o.style);
4032 var cn = o.children || o.cn;
4034 //http://bugs.kde.org/show_bug.cgi?id=71506
4035 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4036 for(var i = 0, len = cn.length; i < len; i++) {
4037 createDom(cn[i], el);
4044 el.innerHTML = o.html;
4047 parentNode.appendChild(el);
4052 var ieTable = function(depth, s, h, e){
4053 tempTableEl.innerHTML = [s, h, e].join('');
4054 var i = -1, el = tempTableEl;
4061 // kill repeat to save bytes
4065 tbe = '</tbody>'+te,
4071 * Nasty code for IE's broken table implementation
4073 var insertIntoTable = function(tag, where, el, html){
4075 tempTableEl = document.createElement('div');
4080 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4083 if(where == 'beforebegin'){
4087 before = el.nextSibling;
4090 node = ieTable(4, trs, html, tre);
4092 else if(tag == 'tr'){
4093 if(where == 'beforebegin'){
4096 node = ieTable(3, tbs, html, tbe);
4097 } else if(where == 'afterend'){
4098 before = el.nextSibling;
4100 node = ieTable(3, tbs, html, tbe);
4101 } else{ // INTO a TR
4102 if(where == 'afterbegin'){
4103 before = el.firstChild;
4105 node = ieTable(4, trs, html, tre);
4107 } else if(tag == 'tbody'){
4108 if(where == 'beforebegin'){
4111 node = ieTable(2, ts, html, te);
4112 } else if(where == 'afterend'){
4113 before = el.nextSibling;
4115 node = ieTable(2, ts, html, te);
4117 if(where == 'afterbegin'){
4118 before = el.firstChild;
4120 node = ieTable(3, tbs, html, tbe);
4123 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4126 if(where == 'afterbegin'){
4127 before = el.firstChild;
4129 node = ieTable(2, ts, html, te);
4131 el.insertBefore(node, before);
4136 /** True to force the use of DOM instead of html fragments @type Boolean */
4140 * Returns the markup for the passed Element(s) config
4141 * @param {Object} o The Dom object spec (and children)
4144 markup : function(o){
4145 return createHtml(o);
4149 * Applies a style specification to an element
4150 * @param {String/HTMLElement} el The element to apply styles to
4151 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4152 * a function which returns such a specification.
4154 applyStyles : function(el, styles){
4157 if(typeof styles == "string"){
4158 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4160 while ((matches = re.exec(styles)) != null){
4161 el.setStyle(matches[1], matches[2]);
4163 }else if (typeof styles == "object"){
4164 for (var style in styles){
4165 el.setStyle(style, styles[style]);
4167 }else if (typeof styles == "function"){
4168 Roo.DomHelper.applyStyles(el, styles.call());
4174 * Inserts an HTML fragment into the Dom
4175 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4176 * @param {HTMLElement} el The context element
4177 * @param {String} html The HTML fragmenet
4178 * @return {HTMLElement} The new node
4180 insertHtml : function(where, el, html){
4181 where = where.toLowerCase();
4182 if(el.insertAdjacentHTML){
4183 if(tableRe.test(el.tagName)){
4185 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4191 el.insertAdjacentHTML('BeforeBegin', html);
4192 return el.previousSibling;
4194 el.insertAdjacentHTML('AfterBegin', html);
4195 return el.firstChild;
4197 el.insertAdjacentHTML('BeforeEnd', html);
4198 return el.lastChild;
4200 el.insertAdjacentHTML('AfterEnd', html);
4201 return el.nextSibling;
4203 throw 'Illegal insertion point -> "' + where + '"';
4205 var range = el.ownerDocument.createRange();
4209 range.setStartBefore(el);
4210 frag = range.createContextualFragment(html);
4211 el.parentNode.insertBefore(frag, el);
4212 return el.previousSibling;
4215 range.setStartBefore(el.firstChild);
4216 frag = range.createContextualFragment(html);
4217 el.insertBefore(frag, el.firstChild);
4218 return el.firstChild;
4220 el.innerHTML = html;
4221 return el.firstChild;
4225 range.setStartAfter(el.lastChild);
4226 frag = range.createContextualFragment(html);
4227 el.appendChild(frag);
4228 return el.lastChild;
4230 el.innerHTML = html;
4231 return el.lastChild;
4234 range.setStartAfter(el);
4235 frag = range.createContextualFragment(html);
4236 el.parentNode.insertBefore(frag, el.nextSibling);
4237 return el.nextSibling;
4239 throw 'Illegal insertion point -> "' + where + '"';
4243 * Creates new Dom element(s) and inserts them before el
4244 * @param {String/HTMLElement/Element} el The context element
4245 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4246 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4247 * @return {HTMLElement/Roo.Element} The new node
4249 insertBefore : function(el, o, returnElement){
4250 return this.doInsert(el, o, returnElement, "beforeBegin");
4254 * Creates new Dom element(s) and inserts them after el
4255 * @param {String/HTMLElement/Element} el The context element
4256 * @param {Object} o The Dom object spec (and children)
4257 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4258 * @return {HTMLElement/Roo.Element} The new node
4260 insertAfter : function(el, o, returnElement){
4261 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4265 * Creates new Dom element(s) and inserts them as the first child of el
4266 * @param {String/HTMLElement/Element} el The context element
4267 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4268 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4269 * @return {HTMLElement/Roo.Element} The new node
4271 insertFirst : function(el, o, returnElement){
4272 return this.doInsert(el, o, returnElement, "afterBegin");
4276 doInsert : function(el, o, returnElement, pos, sibling){
4277 el = Roo.getDom(el);
4279 if(this.useDom || o.ns){
4280 newNode = createDom(o, null);
4281 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4283 var html = createHtml(o);
4284 newNode = this.insertHtml(pos, el, html);
4286 return returnElement ? Roo.get(newNode, true) : newNode;
4290 * Creates new Dom element(s) and appends them to el
4291 * @param {String/HTMLElement/Element} el The context element
4292 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4293 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4294 * @return {HTMLElement/Roo.Element} The new node
4296 append : function(el, o, returnElement){
4297 el = Roo.getDom(el);
4299 if(this.useDom || o.ns){
4300 newNode = createDom(o, null);
4301 el.appendChild(newNode);
4303 var html = createHtml(o);
4304 newNode = this.insertHtml("beforeEnd", el, html);
4306 return returnElement ? Roo.get(newNode, true) : newNode;
4310 * Creates new Dom element(s) and overwrites the contents of el with them
4311 * @param {String/HTMLElement/Element} el The context element
4312 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4313 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4314 * @return {HTMLElement/Roo.Element} The new node
4316 overwrite : function(el, o, returnElement){
4317 el = Roo.getDom(el);
4320 while (el.childNodes.length) {
4321 el.removeChild(el.firstChild);
4325 el.innerHTML = createHtml(o);
4328 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4332 * Creates a new Roo.DomHelper.Template from the Dom object spec
4333 * @param {Object} o The Dom object spec (and children)
4334 * @return {Roo.DomHelper.Template} The new template
4336 createTemplate : function(o){
4337 var html = createHtml(o);
4338 return new Roo.Template(html);
4344 * Ext JS Library 1.1.1
4345 * Copyright(c) 2006-2007, Ext JS, LLC.
4347 * Originally Released Under LGPL - original licence link has changed is not relivant.
4350 * <script type="text/javascript">
4354 * @class Roo.Template
4355 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4356 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4359 var t = new Roo.Template(
4360 '<div name="{id}">',
4361 '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
4364 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4366 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>.
4368 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4370 Roo.Template = function(html){
4371 if(html instanceof Array){
4372 html = html.join("");
4373 }else if(arguments.length > 1){
4374 html = Array.prototype.join.call(arguments, "");
4380 Roo.Template.prototype = {
4382 * Returns an HTML fragment of this template with the specified values applied.
4383 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4384 * @return {String} The HTML fragment
4386 applyTemplate : function(values){
4388 return this.compiled(values);
4390 var useF = this.disableFormats !== true;
4391 var fm = Roo.util.Format, tpl = this;
4392 var fn = function(m, name, format, args){
4394 if(format.substr(0, 5) == "this."){
4395 return tpl.call(format.substr(5), values[name], values);
4398 // quoted values are required for strings in compiled templates,
4399 // but for non compiled we need to strip them
4400 // quoted reversed for jsmin
4401 var re = /^\s*['"](.*)["']\s*$/;
4402 args = args.split(',');
4403 for(var i = 0, len = args.length; i < len; i++){
4404 args[i] = args[i].replace(re, "$1");
4406 args = [values[name]].concat(args);
4408 args = [values[name]];
4410 return fm[format].apply(fm, args);
4413 return values[name] !== undefined ? values[name] : "";
4416 return this.html.replace(this.re, fn);
4420 * Sets the HTML used as the template and optionally compiles it.
4421 * @param {String} html
4422 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4423 * @return {Roo.Template} this
4425 set : function(html, compile){
4427 this.compiled = null;
4435 * True to disable format functions (defaults to false)
4438 disableFormats : false,
4441 * The regular expression used to match template variables
4445 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4448 * Compiles the template into an internal function, eliminating the RegEx overhead.
4449 * @return {Roo.Template} this
4451 compile : function(){
4452 var fm = Roo.util.Format;
4453 var useF = this.disableFormats !== true;
4454 var sep = Roo.isGecko ? "+" : ",";
4455 var fn = function(m, name, format, args){
4457 args = args ? ',' + args : "";
4458 if(format.substr(0, 5) != "this."){
4459 format = "fm." + format + '(';
4461 format = 'this.call("'+ format.substr(5) + '", ';
4465 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4467 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4470 // branched to use + in gecko and [].join() in others
4472 body = "this.compiled = function(values){ return '" +
4473 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4476 body = ["this.compiled = function(values){ return ['"];
4477 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4478 body.push("'].join('');};");
4479 body = body.join('');
4489 // private function used to call members
4490 call : function(fnName, value, allValues){
4491 return this[fnName](value, allValues);
4495 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4496 * @param {String/HTMLElement/Roo.Element} el The context element
4497 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4498 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4499 * @return {HTMLElement/Roo.Element} The new node or Element
4501 insertFirst: function(el, values, returnElement){
4502 return this.doInsert('afterBegin', el, values, returnElement);
4506 * Applies the supplied values to the template and inserts the new node(s) before el.
4507 * @param {String/HTMLElement/Roo.Element} el The context element
4508 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4509 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4510 * @return {HTMLElement/Roo.Element} The new node or Element
4512 insertBefore: function(el, values, returnElement){
4513 return this.doInsert('beforeBegin', el, values, returnElement);
4517 * Applies the supplied values to the template and inserts the new node(s) after el.
4518 * @param {String/HTMLElement/Roo.Element} el The context element
4519 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4520 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4521 * @return {HTMLElement/Roo.Element} The new node or Element
4523 insertAfter : function(el, values, returnElement){
4524 return this.doInsert('afterEnd', el, values, returnElement);
4528 * Applies the supplied values to the template and appends the new node(s) to el.
4529 * @param {String/HTMLElement/Roo.Element} el The context element
4530 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4531 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4532 * @return {HTMLElement/Roo.Element} The new node or Element
4534 append : function(el, values, returnElement){
4535 return this.doInsert('beforeEnd', el, values, returnElement);
4538 doInsert : function(where, el, values, returnEl){
4539 el = Roo.getDom(el);
4540 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4541 return returnEl ? Roo.get(newNode, true) : newNode;
4545 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4546 * @param {String/HTMLElement/Roo.Element} el The context element
4547 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4548 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4549 * @return {HTMLElement/Roo.Element} The new node or Element
4551 overwrite : function(el, values, returnElement){
4552 el = Roo.getDom(el);
4553 el.innerHTML = this.applyTemplate(values);
4554 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4558 * Alias for {@link #applyTemplate}
4561 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4564 Roo.DomHelper.Template = Roo.Template;
4567 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4568 * @param {String/HTMLElement} el A DOM element or its id
4569 * @returns {Roo.Template} The created template
4572 Roo.Template.from = function(el){
4573 el = Roo.getDom(el);
4574 return new Roo.Template(el.value || el.innerHTML);
4577 * Ext JS Library 1.1.1
4578 * Copyright(c) 2006-2007, Ext JS, LLC.
4580 * Originally Released Under LGPL - original licence link has changed is not relivant.
4583 * <script type="text/javascript">
4588 * This is code is also distributed under MIT license for use
4589 * with jQuery and prototype JavaScript libraries.
4592 * @class Roo.DomQuery
4593 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4595 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4598 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4600 <h4>Element Selectors:</h4>
4602 <li> <b>*</b> any element</li>
4603 <li> <b>E</b> an element with the tag E</li>
4604 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4605 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4606 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4607 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4609 <h4>Attribute Selectors:</h4>
4610 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4612 <li> <b>E[foo]</b> has an attribute "foo"</li>
4613 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4614 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4615 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4616 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4617 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4618 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4620 <h4>Pseudo Classes:</h4>
4622 <li> <b>E:first-child</b> E is the first child of its parent</li>
4623 <li> <b>E:last-child</b> E is the last child of its parent</li>
4624 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4625 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4626 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4627 <li> <b>E:only-child</b> E is the only child of its parent</li>
4628 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4629 <li> <b>E:first</b> the first E in the resultset</li>
4630 <li> <b>E:last</b> the last E in the resultset</li>
4631 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4632 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4633 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4634 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4635 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4636 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4637 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4638 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4639 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4641 <h4>CSS Value Selectors:</h4>
4643 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4644 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4645 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4646 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4647 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4648 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4652 Roo.DomQuery = function(){
4653 var cache = {}, simpleCache = {}, valueCache = {};
4654 var nonSpace = /\S/;
4655 var trimRe = /^\s+|\s+$/g;
4656 var tplRe = /\{(\d+)\}/g;
4657 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4658 var tagTokenRe = /^(#)?([\w-\*]+)/;
4659 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4661 function child(p, index){
4663 var n = p.firstChild;
4665 if(n.nodeType == 1){
4676 while((n = n.nextSibling) && n.nodeType != 1);
4681 while((n = n.previousSibling) && n.nodeType != 1);
4685 function children(d){
4686 var n = d.firstChild, ni = -1;
4688 var nx = n.nextSibling;
4689 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4699 function byClassName(c, a, v){
4703 var r = [], ri = -1, cn;
4704 for(var i = 0, ci; ci = c[i]; i++){
4705 if((' '+ci.className+' ').indexOf(v) != -1){
4712 function attrValue(n, attr){
4713 if(!n.tagName && typeof n.length != "undefined"){
4722 if(attr == "class" || attr == "className"){
4725 return n.getAttribute(attr) || n[attr];
4729 function getNodes(ns, mode, tagName){
4730 var result = [], ri = -1, cs;
4734 tagName = tagName || "*";
4735 if(typeof ns.getElementsByTagName != "undefined"){
4739 for(var i = 0, ni; ni = ns[i]; i++){
4740 cs = ni.getElementsByTagName(tagName);
4741 for(var j = 0, ci; ci = cs[j]; j++){
4745 }else if(mode == "/" || mode == ">"){
4746 var utag = tagName.toUpperCase();
4747 for(var i = 0, ni, cn; ni = ns[i]; i++){
4748 cn = ni.children || ni.childNodes;
4749 for(var j = 0, cj; cj = cn[j]; j++){
4750 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4755 }else if(mode == "+"){
4756 var utag = tagName.toUpperCase();
4757 for(var i = 0, n; n = ns[i]; i++){
4758 while((n = n.nextSibling) && n.nodeType != 1);
4759 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4763 }else if(mode == "~"){
4764 for(var i = 0, n; n = ns[i]; i++){
4765 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4774 function concat(a, b){
4778 for(var i = 0, l = b.length; i < l; i++){
4784 function byTag(cs, tagName){
4785 if(cs.tagName || cs == document){
4791 var r = [], ri = -1;
4792 tagName = tagName.toLowerCase();
4793 for(var i = 0, ci; ci = cs[i]; i++){
4794 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4801 function byId(cs, attr, id){
4802 if(cs.tagName || cs == document){
4808 var r = [], ri = -1;
4809 for(var i = 0,ci; ci = cs[i]; i++){
4810 if(ci && ci.id == id){
4818 function byAttribute(cs, attr, value, op, custom){
4819 var r = [], ri = -1, st = custom=="{";
4820 var f = Roo.DomQuery.operators[op];
4821 for(var i = 0, ci; ci = cs[i]; i++){
4824 a = Roo.DomQuery.getStyle(ci, attr);
4826 else if(attr == "class" || attr == "className"){
4828 }else if(attr == "for"){
4830 }else if(attr == "href"){
4831 a = ci.getAttribute("href", 2);
4833 a = ci.getAttribute(attr);
4835 if((f && f(a, value)) || (!f && a)){
4842 function byPseudo(cs, name, value){
4843 return Roo.DomQuery.pseudos[name](cs, value);
4846 // This is for IE MSXML which does not support expandos.
4847 // IE runs the same speed using setAttribute, however FF slows way down
4848 // and Safari completely fails so they need to continue to use expandos.
4849 var isIE = window.ActiveXObject ? true : false;
4851 // this eval is stop the compressor from
4852 // renaming the variable to something shorter
4854 /** eval:var:batch */
4859 function nodupIEXml(cs){
4861 cs[0].setAttribute("_nodup", d);
4863 for(var i = 1, len = cs.length; i < len; i++){
4865 if(!c.getAttribute("_nodup") != d){
4866 c.setAttribute("_nodup", d);
4870 for(var i = 0, len = cs.length; i < len; i++){
4871 cs[i].removeAttribute("_nodup");
4880 var len = cs.length, c, i, r = cs, cj, ri = -1;
4881 if(!len || typeof cs.nodeType != "undefined" || len == 1){
4884 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4885 return nodupIEXml(cs);
4889 for(i = 1; c = cs[i]; i++){
4894 for(var j = 0; j < i; j++){
4897 for(j = i+1; cj = cs[j]; j++){
4909 function quickDiffIEXml(c1, c2){
4911 for(var i = 0, len = c1.length; i < len; i++){
4912 c1[i].setAttribute("_qdiff", d);
4915 for(var i = 0, len = c2.length; i < len; i++){
4916 if(c2[i].getAttribute("_qdiff") != d){
4917 r[r.length] = c2[i];
4920 for(var i = 0, len = c1.length; i < len; i++){
4921 c1[i].removeAttribute("_qdiff");
4926 function quickDiff(c1, c2){
4927 var len1 = c1.length;
4931 if(isIE && c1[0].selectSingleNode){
4932 return quickDiffIEXml(c1, c2);
4935 for(var i = 0; i < len1; i++){
4939 for(var i = 0, len = c2.length; i < len; i++){
4940 if(c2[i]._qdiff != d){
4941 r[r.length] = c2[i];
4947 function quickId(ns, mode, root, id){
4949 var d = root.ownerDocument || root;
4950 return d.getElementById(id);
4952 ns = getNodes(ns, mode, "*");
4953 return byId(ns, null, id);
4957 getStyle : function(el, name){
4958 return Roo.fly(el).getStyle(name);
4961 * Compiles a selector/xpath query into a reusable function. The returned function
4962 * takes one parameter "root" (optional), which is the context node from where the query should start.
4963 * @param {String} selector The selector/xpath query
4964 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
4965 * @return {Function}
4967 compile : function(path, type){
4968 type = type || "select";
4970 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
4971 var q = path, mode, lq;
4972 var tk = Roo.DomQuery.matchers;
4973 var tklen = tk.length;
4976 // accept leading mode switch
4977 var lmode = q.match(modeRe);
4978 if(lmode && lmode[1]){
4979 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
4980 q = q.replace(lmode[1], "");
4982 // strip leading slashes
4983 while(path.substr(0, 1)=="/"){
4984 path = path.substr(1);
4987 while(q && lq != q){
4989 var tm = q.match(tagTokenRe);
4990 if(type == "select"){
4993 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
4995 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
4997 q = q.replace(tm[0], "");
4998 }else if(q.substr(0, 1) != '@'){
4999 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5004 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5006 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5008 q = q.replace(tm[0], "");
5011 while(!(mm = q.match(modeRe))){
5012 var matched = false;
5013 for(var j = 0; j < tklen; j++){
5015 var m = q.match(t.re);
5017 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5020 q = q.replace(m[0], "");
5025 // prevent infinite loop on bad selector
5027 throw 'Error parsing selector, parsing failed at "' + q + '"';
5031 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5032 q = q.replace(mm[1], "");
5035 fn[fn.length] = "return nodup(n);\n}";
5038 * list of variables that need from compression as they are used by eval.
5048 * eval:var:byClassName
5050 * eval:var:byAttribute
5051 * eval:var:attrValue
5059 * Selects a group of elements.
5060 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5061 * @param {Node} root (optional) The start of the query (defaults to document).
5064 select : function(path, root, type){
5065 if(!root || root == document){
5068 if(typeof root == "string"){
5069 root = document.getElementById(root);
5071 var paths = path.split(",");
5073 for(var i = 0, len = paths.length; i < len; i++){
5074 var p = paths[i].replace(trimRe, "");
5076 cache[p] = Roo.DomQuery.compile(p);
5078 throw p + " is not a valid selector";
5081 var result = cache[p](root);
5082 if(result && result != document){
5083 results = results.concat(result);
5086 if(paths.length > 1){
5087 return nodup(results);
5093 * Selects a single element.
5094 * @param {String} selector The selector/xpath query
5095 * @param {Node} root (optional) The start of the query (defaults to document).
5098 selectNode : function(path, root){
5099 return Roo.DomQuery.select(path, root)[0];
5103 * Selects the value of a node, optionally replacing null with the defaultValue.
5104 * @param {String} selector The selector/xpath query
5105 * @param {Node} root (optional) The start of the query (defaults to document).
5106 * @param {String} defaultValue
5108 selectValue : function(path, root, defaultValue){
5109 path = path.replace(trimRe, "");
5110 if(!valueCache[path]){
5111 valueCache[path] = Roo.DomQuery.compile(path, "select");
5113 var n = valueCache[path](root);
5114 n = n[0] ? n[0] : n;
5115 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5116 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5120 * Selects the value of a node, parsing integers and floats.
5121 * @param {String} selector The selector/xpath query
5122 * @param {Node} root (optional) The start of the query (defaults to document).
5123 * @param {Number} defaultValue
5126 selectNumber : function(path, root, defaultValue){
5127 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5128 return parseFloat(v);
5132 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5133 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5134 * @param {String} selector The simple selector to test
5137 is : function(el, ss){
5138 if(typeof el == "string"){
5139 el = document.getElementById(el);
5141 var isArray = (el instanceof Array);
5142 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5143 return isArray ? (result.length == el.length) : (result.length > 0);
5147 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5148 * @param {Array} el An array of elements to filter
5149 * @param {String} selector The simple selector to test
5150 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5151 * the selector instead of the ones that match
5154 filter : function(els, ss, nonMatches){
5155 ss = ss.replace(trimRe, "");
5156 if(!simpleCache[ss]){
5157 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5159 var result = simpleCache[ss](els);
5160 return nonMatches ? quickDiff(result, els) : result;
5164 * Collection of matching regular expressions and code snippets.
5168 select: 'n = byClassName(n, null, " {1} ");'
5170 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5171 select: 'n = byPseudo(n, "{1}", "{2}");'
5173 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5174 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5177 select: 'n = byId(n, null, "{1}");'
5180 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5185 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5186 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5189 "=" : function(a, v){
5192 "!=" : function(a, v){
5195 "^=" : function(a, v){
5196 return a && a.substr(0, v.length) == v;
5198 "$=" : function(a, v){
5199 return a && a.substr(a.length-v.length) == v;
5201 "*=" : function(a, v){
5202 return a && a.indexOf(v) !== -1;
5204 "%=" : function(a, v){
5205 return (a % v) == 0;
5207 "|=" : function(a, v){
5208 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5210 "~=" : function(a, v){
5211 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5216 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5217 * and the argument (if any) supplied in the selector.
5220 "first-child" : function(c){
5221 var r = [], ri = -1, n;
5222 for(var i = 0, ci; ci = n = c[i]; i++){
5223 while((n = n.previousSibling) && n.nodeType != 1);
5231 "last-child" : function(c){
5232 var r = [], ri = -1, n;
5233 for(var i = 0, ci; ci = n = c[i]; i++){
5234 while((n = n.nextSibling) && n.nodeType != 1);
5242 "nth-child" : function(c, a) {
5243 var r = [], ri = -1;
5244 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5245 var f = (m[1] || 1) - 0, l = m[2] - 0;
5246 for(var i = 0, n; n = c[i]; i++){
5247 var pn = n.parentNode;
5248 if (batch != pn._batch) {
5250 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5251 if(cn.nodeType == 1){
5258 if (l == 0 || n.nodeIndex == l){
5261 } else if ((n.nodeIndex + l) % f == 0){
5269 "only-child" : function(c){
5270 var r = [], ri = -1;;
5271 for(var i = 0, ci; ci = c[i]; i++){
5272 if(!prev(ci) && !next(ci)){
5279 "empty" : function(c){
5280 var r = [], ri = -1;
5281 for(var i = 0, ci; ci = c[i]; i++){
5282 var cns = ci.childNodes, j = 0, cn, empty = true;
5285 if(cn.nodeType == 1 || cn.nodeType == 3){
5297 "contains" : function(c, v){
5298 var r = [], ri = -1;
5299 for(var i = 0, ci; ci = c[i]; i++){
5300 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5307 "nodeValue" : function(c, v){
5308 var r = [], ri = -1;
5309 for(var i = 0, ci; ci = c[i]; i++){
5310 if(ci.firstChild && ci.firstChild.nodeValue == v){
5317 "checked" : function(c){
5318 var r = [], ri = -1;
5319 for(var i = 0, ci; ci = c[i]; i++){
5320 if(ci.checked == true){
5327 "not" : function(c, ss){
5328 return Roo.DomQuery.filter(c, ss, true);
5331 "odd" : function(c){
5332 return this["nth-child"](c, "odd");
5335 "even" : function(c){
5336 return this["nth-child"](c, "even");
5339 "nth" : function(c, a){
5340 return c[a-1] || [];
5343 "first" : function(c){
5347 "last" : function(c){
5348 return c[c.length-1] || [];
5351 "has" : function(c, ss){
5352 var s = Roo.DomQuery.select;
5353 var r = [], ri = -1;
5354 for(var i = 0, ci; ci = c[i]; i++){
5355 if(s(ss, ci).length > 0){
5362 "next" : function(c, ss){
5363 var is = Roo.DomQuery.is;
5364 var r = [], ri = -1;
5365 for(var i = 0, ci; ci = c[i]; i++){
5374 "prev" : function(c, ss){
5375 var is = Roo.DomQuery.is;
5376 var r = [], ri = -1;
5377 for(var i = 0, ci; ci = c[i]; i++){
5390 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5391 * @param {String} path The selector/xpath query
5392 * @param {Node} root (optional) The start of the query (defaults to document).
5397 Roo.query = Roo.DomQuery.select;
5400 * Ext JS Library 1.1.1
5401 * Copyright(c) 2006-2007, Ext JS, LLC.
5403 * Originally Released Under LGPL - original licence link has changed is not relivant.
5406 * <script type="text/javascript">
5410 * @class Roo.util.Observable
5411 * Base class that provides a common interface for publishing events. Subclasses are expected to
5412 * to have a property "events" with all the events defined.<br>
5415 Employee = function(name){
5422 Roo.extend(Employee, Roo.util.Observable);
5424 * @param {Object} config properties to use (incuding events / listeners)
5427 Roo.util.Observable = function(cfg){
5430 this.addEvents(cfg.events || {});
5432 delete cfg.events; // make sure
5435 Roo.apply(this, cfg);
5438 this.on(this.listeners);
5439 delete this.listeners;
5442 Roo.util.Observable.prototype = {
5444 * @cfg {Object} listeners list of events and functions to call for this object,
5448 'click' : function(e) {
5458 * Fires the specified event with the passed parameters (minus the event name).
5459 * @param {String} eventName
5460 * @param {Object...} args Variable number of parameters are passed to handlers
5461 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5463 fireEvent : function(){
5464 var ce = this.events[arguments[0].toLowerCase()];
5465 if(typeof ce == "object"){
5466 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5473 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5476 * Appends an event handler to this component
5477 * @param {String} eventName The type of event to listen for
5478 * @param {Function} handler The method the event invokes
5479 * @param {Object} scope (optional) The scope in which to execute the handler
5480 * function. The handler function's "this" context.
5481 * @param {Object} options (optional) An object containing handler configuration
5482 * properties. This may contain any of the following properties:<ul>
5483 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5484 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5485 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5486 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5487 * by the specified number of milliseconds. If the event fires again within that time, the original
5488 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5491 * <b>Combining Options</b><br>
5492 * Using the options argument, it is possible to combine different types of listeners:<br>
5494 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5496 el.on('click', this.onClick, this, {
5503 * <b>Attaching multiple handlers in 1 call</b><br>
5504 * The method also allows for a single argument to be passed which is a config object containing properties
5505 * which specify multiple handlers.
5514 fn: this.onMouseOver,
5518 fn: this.onMouseOut,
5524 * Or a shorthand syntax which passes the same scope object to all handlers:
5527 'click': this.onClick,
5528 'mouseover': this.onMouseOver,
5529 'mouseout': this.onMouseOut,
5534 addListener : function(eventName, fn, scope, o){
5535 if(typeof eventName == "object"){
5538 if(this.filterOptRe.test(e)){
5541 if(typeof o[e] == "function"){
5543 this.addListener(e, o[e], o.scope, o);
5545 // individual options
5546 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5551 o = (!o || typeof o == "boolean") ? {} : o;
5552 eventName = eventName.toLowerCase();
5553 var ce = this.events[eventName] || true;
5554 if(typeof ce == "boolean"){
5555 ce = new Roo.util.Event(this, eventName);
5556 this.events[eventName] = ce;
5558 ce.addListener(fn, scope, o);
5562 * Removes a listener
5563 * @param {String} eventName The type of event to listen for
5564 * @param {Function} handler The handler to remove
5565 * @param {Object} scope (optional) The scope (this object) for the handler
5567 removeListener : function(eventName, fn, scope){
5568 var ce = this.events[eventName.toLowerCase()];
5569 if(typeof ce == "object"){
5570 ce.removeListener(fn, scope);
5575 * Removes all listeners for this object
5577 purgeListeners : function(){
5578 for(var evt in this.events){
5579 if(typeof this.events[evt] == "object"){
5580 this.events[evt].clearListeners();
5585 relayEvents : function(o, events){
5586 var createHandler = function(ename){
5588 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5591 for(var i = 0, len = events.length; i < len; i++){
5592 var ename = events[i];
5593 if(!this.events[ename]){ this.events[ename] = true; };
5594 o.on(ename, createHandler(ename), this);
5599 * Used to define events on this Observable
5600 * @param {Object} object The object with the events defined
5602 addEvents : function(o){
5606 Roo.applyIf(this.events, o);
5610 * Checks to see if this object has any listeners for a specified event
5611 * @param {String} eventName The name of the event to check for
5612 * @return {Boolean} True if the event is being listened for, else false
5614 hasListener : function(eventName){
5615 var e = this.events[eventName];
5616 return typeof e == "object" && e.listeners.length > 0;
5620 * Appends an event handler to this element (shorthand for addListener)
5621 * @param {String} eventName The type of event to listen for
5622 * @param {Function} handler The method the event invokes
5623 * @param {Object} scope (optional) The scope in which to execute the handler
5624 * function. The handler function's "this" context.
5625 * @param {Object} options (optional)
5628 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5630 * Removes a listener (shorthand for removeListener)
5631 * @param {String} eventName The type of event to listen for
5632 * @param {Function} handler The handler to remove
5633 * @param {Object} scope (optional) The scope (this object) for the handler
5636 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5639 * Starts capture on the specified Observable. All events will be passed
5640 * to the supplied function with the event name + standard signature of the event
5641 * <b>before</b> the event is fired. If the supplied function returns false,
5642 * the event will not fire.
5643 * @param {Observable} o The Observable to capture
5644 * @param {Function} fn The function to call
5645 * @param {Object} scope (optional) The scope (this object) for the fn
5648 Roo.util.Observable.capture = function(o, fn, scope){
5649 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5653 * Removes <b>all</b> added captures from the Observable.
5654 * @param {Observable} o The Observable to release
5657 Roo.util.Observable.releaseCapture = function(o){
5658 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5663 var createBuffered = function(h, o, scope){
5664 var task = new Roo.util.DelayedTask();
5666 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5670 var createSingle = function(h, e, fn, scope){
5672 e.removeListener(fn, scope);
5673 return h.apply(scope, arguments);
5677 var createDelayed = function(h, o, scope){
5679 var args = Array.prototype.slice.call(arguments, 0);
5680 setTimeout(function(){
5681 h.apply(scope, args);
5686 Roo.util.Event = function(obj, name){
5689 this.listeners = [];
5692 Roo.util.Event.prototype = {
5693 addListener : function(fn, scope, options){
5694 var o = options || {};
5695 scope = scope || this.obj;
5696 if(!this.isListening(fn, scope)){
5697 var l = {fn: fn, scope: scope, options: o};
5700 h = createDelayed(h, o, scope);
5703 h = createSingle(h, this, fn, scope);
5706 h = createBuffered(h, o, scope);
5709 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5710 this.listeners.push(l);
5712 this.listeners = this.listeners.slice(0);
5713 this.listeners.push(l);
5718 findListener : function(fn, scope){
5719 scope = scope || this.obj;
5720 var ls = this.listeners;
5721 for(var i = 0, len = ls.length; i < len; i++){
5723 if(l.fn == fn && l.scope == scope){
5730 isListening : function(fn, scope){
5731 return this.findListener(fn, scope) != -1;
5734 removeListener : function(fn, scope){
5736 if((index = this.findListener(fn, scope)) != -1){
5738 this.listeners.splice(index, 1);
5740 this.listeners = this.listeners.slice(0);
5741 this.listeners.splice(index, 1);
5748 clearListeners : function(){
5749 this.listeners = [];
5753 var ls = this.listeners, scope, len = ls.length;
5756 var args = Array.prototype.slice.call(arguments, 0);
5757 for(var i = 0; i < len; i++){
5759 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5760 this.firing = false;
5764 this.firing = false;
5771 * Ext JS Library 1.1.1
5772 * Copyright(c) 2006-2007, Ext JS, LLC.
5774 * Originally Released Under LGPL - original licence link has changed is not relivant.
5777 * <script type="text/javascript">
5781 * @class Roo.EventManager
5782 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5783 * several useful events directly.
5784 * See {@link Roo.EventObject} for more details on normalized event objects.
5787 Roo.EventManager = function(){
5788 var docReadyEvent, docReadyProcId, docReadyState = false;
5789 var resizeEvent, resizeTask, textEvent, textSize;
5790 var E = Roo.lib.Event;
5791 var D = Roo.lib.Dom;
5794 var fireDocReady = function(){
5796 docReadyState = true;
5799 clearInterval(docReadyProcId);
5801 if(Roo.isGecko || Roo.isOpera) {
5802 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5805 var defer = document.getElementById("ie-deferred-loader");
5807 defer.onreadystatechange = null;
5808 defer.parentNode.removeChild(defer);
5812 docReadyEvent.fire();
5813 docReadyEvent.clearListeners();
5818 var initDocReady = function(){
5819 docReadyEvent = new Roo.util.Event();
5820 if(Roo.isGecko || Roo.isOpera) {
5821 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5823 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5824 var defer = document.getElementById("ie-deferred-loader");
5825 defer.onreadystatechange = function(){
5826 if(this.readyState == "complete"){
5830 }else if(Roo.isSafari){
5831 docReadyProcId = setInterval(function(){
5832 var rs = document.readyState;
5833 if(rs == "complete") {
5838 // no matter what, make sure it fires on load
5839 E.on(window, "load", fireDocReady);
5842 var createBuffered = function(h, o){
5843 var task = new Roo.util.DelayedTask(h);
5845 // create new event object impl so new events don't wipe out properties
5846 e = new Roo.EventObjectImpl(e);
5847 task.delay(o.buffer, h, null, [e]);
5851 var createSingle = function(h, el, ename, fn){
5853 Roo.EventManager.removeListener(el, ename, fn);
5858 var createDelayed = function(h, o){
5860 // create new event object impl so new events don't wipe out properties
5861 e = new Roo.EventObjectImpl(e);
5862 setTimeout(function(){
5868 var listen = function(element, ename, opt, fn, scope){
5869 var o = (!opt || typeof opt == "boolean") ? {} : opt;
5870 fn = fn || o.fn; scope = scope || o.scope;
5871 var el = Roo.getDom(element);
5873 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5875 var h = function(e){
5876 e = Roo.EventObject.setEvent(e);
5879 t = e.getTarget(o.delegate, el);
5886 if(o.stopEvent === true){
5889 if(o.preventDefault === true){
5892 if(o.stopPropagation === true){
5893 e.stopPropagation();
5896 if(o.normalized === false){
5900 fn.call(scope || el, e, t, o);
5903 h = createDelayed(h, o);
5906 h = createSingle(h, el, ename, fn);
5909 h = createBuffered(h, o);
5911 fn._handlers = fn._handlers || [];
5912 fn._handlers.push([Roo.id(el), ename, h]);
5915 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5916 el.addEventListener("DOMMouseScroll", h, false);
5917 E.on(window, 'unload', function(){
5918 el.removeEventListener("DOMMouseScroll", h, false);
5921 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5922 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5927 var stopListening = function(el, ename, fn){
5928 var id = Roo.id(el), hds = fn._handlers, hd = fn;
5930 for(var i = 0, len = hds.length; i < len; i++){
5932 if(h[0] == id && h[1] == ename){
5939 E.un(el, ename, hd);
5940 el = Roo.getDom(el);
5941 if(ename == "mousewheel" && el.addEventListener){
5942 el.removeEventListener("DOMMouseScroll", hd, false);
5944 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5945 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5949 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
5956 * @scope Roo.EventManager
5961 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
5962 * object with a Roo.EventObject
5963 * @param {Function} fn The method the event invokes
5964 * @param {Object} scope An object that becomes the scope of the handler
5965 * @param {boolean} override If true, the obj passed in becomes
5966 * the execution scope of the listener
5967 * @return {Function} The wrapped function
5970 wrap : function(fn, scope, override){
5972 Roo.EventObject.setEvent(e);
5973 fn.call(override ? scope || window : window, Roo.EventObject, scope);
5978 * Appends an event handler to an element (shorthand for addListener)
5979 * @param {String/HTMLElement} element The html element or id to assign the
5980 * @param {String} eventName The type of event to listen for
5981 * @param {Function} handler The method the event invokes
5982 * @param {Object} scope (optional) The scope in which to execute the handler
5983 * function. The handler function's "this" context.
5984 * @param {Object} options (optional) An object containing handler configuration
5985 * properties. This may contain any of the following properties:<ul>
5986 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5987 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
5988 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
5989 * <li>preventDefault {Boolean} True to prevent the default action</li>
5990 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
5991 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
5992 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5993 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5994 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5995 * by the specified number of milliseconds. If the event fires again within that time, the original
5996 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5999 * <b>Combining Options</b><br>
6000 * Using the options argument, it is possible to combine different types of listeners:<br>
6002 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6004 el.on('click', this.onClick, this, {
6011 * <b>Attaching multiple handlers in 1 call</b><br>
6012 * The method also allows for a single argument to be passed which is a config object containing properties
6013 * which specify multiple handlers.
6023 fn: this.onMouseOver
6032 * Or a shorthand syntax:<br>
6035 'click' : this.onClick,
6036 'mouseover' : this.onMouseOver,
6037 'mouseout' : this.onMouseOut
6041 addListener : function(element, eventName, fn, scope, options){
6042 if(typeof eventName == "object"){
6048 if(typeof o[e] == "function"){
6050 listen(element, e, o, o[e], o.scope);
6052 // individual options
6053 listen(element, e, o[e]);
6058 return listen(element, eventName, options, fn, scope);
6062 * Removes an event handler
6064 * @param {String/HTMLElement} element The id or html element to remove the
6066 * @param {String} eventName The type of event
6067 * @param {Function} fn
6068 * @return {Boolean} True if a listener was actually removed
6070 removeListener : function(element, eventName, fn){
6071 return stopListening(element, eventName, fn);
6075 * Fires when the document is ready (before onload and before images are loaded). Can be
6076 * accessed shorthanded Roo.onReady().
6077 * @param {Function} fn The method the event invokes
6078 * @param {Object} scope An object that becomes the scope of the handler
6079 * @param {boolean} options
6081 onDocumentReady : function(fn, scope, options){
6082 if(docReadyState){ // if it already fired
6083 docReadyEvent.addListener(fn, scope, options);
6084 docReadyEvent.fire();
6085 docReadyEvent.clearListeners();
6091 docReadyEvent.addListener(fn, scope, options);
6095 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6096 * @param {Function} fn The method the event invokes
6097 * @param {Object} scope An object that becomes the scope of the handler
6098 * @param {boolean} options
6100 onWindowResize : function(fn, scope, options){
6102 resizeEvent = new Roo.util.Event();
6103 resizeTask = new Roo.util.DelayedTask(function(){
6104 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6106 E.on(window, "resize", function(){
6108 resizeTask.delay(50);
6110 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6114 resizeEvent.addListener(fn, scope, options);
6118 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6119 * @param {Function} fn The method the event invokes
6120 * @param {Object} scope An object that becomes the scope of the handler
6121 * @param {boolean} options
6123 onTextResize : function(fn, scope, options){
6125 textEvent = new Roo.util.Event();
6126 var textEl = new Roo.Element(document.createElement('div'));
6127 textEl.dom.className = 'x-text-resize';
6128 textEl.dom.innerHTML = 'X';
6129 textEl.appendTo(document.body);
6130 textSize = textEl.dom.offsetHeight;
6131 setInterval(function(){
6132 if(textEl.dom.offsetHeight != textSize){
6133 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6135 }, this.textResizeInterval);
6137 textEvent.addListener(fn, scope, options);
6141 * Removes the passed window resize listener.
6142 * @param {Function} fn The method the event invokes
6143 * @param {Object} scope The scope of handler
6145 removeResizeListener : function(fn, scope){
6147 resizeEvent.removeListener(fn, scope);
6152 fireResize : function(){
6154 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6158 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6162 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6164 textResizeInterval : 50
6169 * @scopeAlias pub=Roo.EventManager
6173 * Appends an event handler to an element (shorthand for addListener)
6174 * @param {String/HTMLElement} element The html element or id to assign the
6175 * @param {String} eventName The type of event to listen for
6176 * @param {Function} handler The method the event invokes
6177 * @param {Object} scope (optional) The scope in which to execute the handler
6178 * function. The handler function's "this" context.
6179 * @param {Object} options (optional) An object containing handler configuration
6180 * properties. This may contain any of the following properties:<ul>
6181 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6182 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6183 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6184 * <li>preventDefault {Boolean} True to prevent the default action</li>
6185 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6186 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6187 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6188 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6189 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6190 * by the specified number of milliseconds. If the event fires again within that time, the original
6191 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6194 * <b>Combining Options</b><br>
6195 * Using the options argument, it is possible to combine different types of listeners:<br>
6197 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6199 el.on('click', this.onClick, this, {
6206 * <b>Attaching multiple handlers in 1 call</b><br>
6207 * The method also allows for a single argument to be passed which is a config object containing properties
6208 * which specify multiple handlers.
6218 fn: this.onMouseOver
6227 * Or a shorthand syntax:<br>
6230 'click' : this.onClick,
6231 'mouseover' : this.onMouseOver,
6232 'mouseout' : this.onMouseOut
6236 pub.on = pub.addListener;
6237 pub.un = pub.removeListener;
6239 pub.stoppedMouseDownEvent = new Roo.util.Event();
6243 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6244 * @param {Function} fn The method the event invokes
6245 * @param {Object} scope An object that becomes the scope of the handler
6246 * @param {boolean} override If true, the obj passed in becomes
6247 * the execution scope of the listener
6251 Roo.onReady = Roo.EventManager.onDocumentReady;
6253 Roo.onReady(function(){
6254 var bd = Roo.get(document.body);
6259 : Roo.isGecko ? "roo-gecko"
6260 : Roo.isOpera ? "roo-opera"
6261 : Roo.isSafari ? "roo-safari" : ""];
6264 cls.push("roo-mac");
6267 cls.push("roo-linux");
6269 if(Roo.isBorderBox){
6270 cls.push('roo-border-box');
6272 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6273 var p = bd.dom.parentNode;
6275 p.className += ' roo-strict';
6278 bd.addClass(cls.join(' '));
6282 * @class Roo.EventObject
6283 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6284 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6287 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6289 var target = e.getTarget();
6292 var myDiv = Roo.get("myDiv");
6293 myDiv.on("click", handleClick);
6295 Roo.EventManager.on("myDiv", 'click', handleClick);
6296 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6300 Roo.EventObject = function(){
6302 var E = Roo.lib.Event;
6304 // safari keypress events for special keys return bad keycodes
6307 63235 : 39, // right
6310 63276 : 33, // page up
6311 63277 : 34, // page down
6312 63272 : 46, // delete
6317 // normalize button clicks
6318 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6319 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6321 Roo.EventObjectImpl = function(e){
6323 this.setEvent(e.browserEvent || e);
6326 Roo.EventObjectImpl.prototype = {
6328 * Used to fix doc tools.
6329 * @scope Roo.EventObject.prototype
6335 /** The normal browser event */
6336 browserEvent : null,
6337 /** The button pressed in a mouse event */
6339 /** True if the shift key was down during the event */
6341 /** True if the control key was down during the event */
6343 /** True if the alt key was down during the event */
6402 setEvent : function(e){
6403 if(e == this || (e && e.browserEvent)){ // already wrapped
6406 this.browserEvent = e;
6408 // normalize buttons
6409 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6410 if(e.type == 'click' && this.button == -1){
6414 this.shiftKey = e.shiftKey;
6415 // mac metaKey behaves like ctrlKey
6416 this.ctrlKey = e.ctrlKey || e.metaKey;
6417 this.altKey = e.altKey;
6418 // in getKey these will be normalized for the mac
6419 this.keyCode = e.keyCode;
6420 // keyup warnings on firefox.
6421 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6422 // cache the target for the delayed and or buffered events
6423 this.target = E.getTarget(e);
6425 this.xy = E.getXY(e);
6428 this.shiftKey = false;
6429 this.ctrlKey = false;
6430 this.altKey = false;
6440 * Stop the event (preventDefault and stopPropagation)
6442 stopEvent : function(){
6443 if(this.browserEvent){
6444 if(this.browserEvent.type == 'mousedown'){
6445 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6447 E.stopEvent(this.browserEvent);
6452 * Prevents the browsers default handling of the event.
6454 preventDefault : function(){
6455 if(this.browserEvent){
6456 E.preventDefault(this.browserEvent);
6461 isNavKeyPress : function(){
6462 var k = this.keyCode;
6463 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6464 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6467 isSpecialKey : function(){
6468 var k = this.keyCode;
6469 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6470 (k == 16) || (k == 17) ||
6471 (k >= 18 && k <= 20) ||
6472 (k >= 33 && k <= 35) ||
6473 (k >= 36 && k <= 39) ||
6474 (k >= 44 && k <= 45);
6477 * Cancels bubbling of the event.
6479 stopPropagation : function(){
6480 if(this.browserEvent){
6481 if(this.type == 'mousedown'){
6482 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6484 E.stopPropagation(this.browserEvent);
6489 * Gets the key code for the event.
6492 getCharCode : function(){
6493 return this.charCode || this.keyCode;
6497 * Returns a normalized keyCode for the event.
6498 * @return {Number} The key code
6500 getKey : function(){
6501 var k = this.keyCode || this.charCode;
6502 return Roo.isSafari ? (safariKeys[k] || k) : k;
6506 * Gets the x coordinate of the event.
6509 getPageX : function(){
6514 * Gets the y coordinate of the event.
6517 getPageY : function(){
6522 * Gets the time of the event.
6525 getTime : function(){
6526 if(this.browserEvent){
6527 return E.getTime(this.browserEvent);
6533 * Gets the page coordinates of the event.
6534 * @return {Array} The xy values like [x, y]
6541 * Gets the target for the event.
6542 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6543 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6544 search as a number or element (defaults to 10 || document.body)
6545 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6546 * @return {HTMLelement}
6548 getTarget : function(selector, maxDepth, returnEl){
6549 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6552 * Gets the related target.
6553 * @return {HTMLElement}
6555 getRelatedTarget : function(){
6556 if(this.browserEvent){
6557 return E.getRelatedTarget(this.browserEvent);
6563 * Normalizes mouse wheel delta across browsers
6564 * @return {Number} The delta
6566 getWheelDelta : function(){
6567 var e = this.browserEvent;
6569 if(e.wheelDelta){ /* IE/Opera. */
6570 delta = e.wheelDelta/120;
6571 }else if(e.detail){ /* Mozilla case. */
6572 delta = -e.detail/3;
6578 * Returns true if the control, meta, shift or alt key was pressed during this event.
6581 hasModifier : function(){
6582 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6586 * Returns true if the target of this event equals el or is a child of el
6587 * @param {String/HTMLElement/Element} el
6588 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6591 within : function(el, related){
6592 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6593 return t && Roo.fly(el).contains(t);
6596 getPoint : function(){
6597 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6601 return new Roo.EventObjectImpl();
6606 * Ext JS Library 1.1.1
6607 * Copyright(c) 2006-2007, Ext JS, LLC.
6609 * Originally Released Under LGPL - original licence link has changed is not relivant.
6612 * <script type="text/javascript">
6616 // was in Composite Element!??!?!
6619 var D = Roo.lib.Dom;
6620 var E = Roo.lib.Event;
6621 var A = Roo.lib.Anim;
6623 // local style camelizing for speed
6625 var camelRe = /(-[a-z])/gi;
6626 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6627 var view = document.defaultView;
6630 * @class Roo.Element
6631 * Represents an Element in the DOM.<br><br>
6634 var el = Roo.get("my-div");
6637 var el = getEl("my-div");
6639 // or with a DOM element
6640 var el = Roo.get(myDivElement);
6642 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6643 * each call instead of constructing a new one.<br><br>
6644 * <b>Animations</b><br />
6645 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6646 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6648 Option Default Description
6649 --------- -------- ---------------------------------------------
6650 duration .35 The duration of the animation in seconds
6651 easing easeOut The YUI easing method
6652 callback none A function to execute when the anim completes
6653 scope this The scope (this) of the callback function
6655 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6656 * manipulate the animation. Here's an example:
6658 var el = Roo.get("my-div");
6663 // default animation
6664 el.setWidth(100, true);
6666 // animation with some options set
6673 // using the "anim" property to get the Anim object
6679 el.setWidth(100, opt);
6681 if(opt.anim.isAnimated()){
6685 * <b> Composite (Collections of) Elements</b><br />
6686 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6687 * @constructor Create a new Element directly.
6688 * @param {String/HTMLElement} element
6689 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6691 Roo.Element = function(element, forceNew){
6692 var dom = typeof element == "string" ?
6693 document.getElementById(element) : element;
6694 if(!dom){ // invalid id/element
6698 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6699 return Roo.Element.cache[id];
6709 * The DOM element ID
6712 this.id = id || Roo.id(dom);
6715 var El = Roo.Element;
6719 * The element's default display mode (defaults to "")
6722 originalDisplay : "",
6726 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6731 * Sets the element's visibility mode. When setVisible() is called it
6732 * will use this to determine whether to set the visibility or the display property.
6733 * @param visMode Element.VISIBILITY or Element.DISPLAY
6734 * @return {Roo.Element} this
6736 setVisibilityMode : function(visMode){
6737 this.visibilityMode = visMode;
6741 * Convenience method for setVisibilityMode(Element.DISPLAY)
6742 * @param {String} display (optional) What to set display to when visible
6743 * @return {Roo.Element} this
6745 enableDisplayMode : function(display){
6746 this.setVisibilityMode(El.DISPLAY);
6747 if(typeof display != "undefined") this.originalDisplay = display;
6752 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6753 * @param {String} selector The simple selector to test
6754 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6755 search as a number or element (defaults to 10 || document.body)
6756 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6757 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6759 findParent : function(simpleSelector, maxDepth, returnEl){
6760 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6761 maxDepth = maxDepth || 50;
6762 if(typeof maxDepth != "number"){
6763 stopEl = Roo.getDom(maxDepth);
6766 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6767 if(dq.is(p, simpleSelector)){
6768 return returnEl ? Roo.get(p) : p;
6778 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6779 * @param {String} selector The simple selector to test
6780 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6781 search as a number or element (defaults to 10 || document.body)
6782 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6783 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6785 findParentNode : function(simpleSelector, maxDepth, returnEl){
6786 var p = Roo.fly(this.dom.parentNode, '_internal');
6787 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6791 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6792 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6793 * @param {String} selector The simple selector to test
6794 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6795 search as a number or element (defaults to 10 || document.body)
6796 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6798 up : function(simpleSelector, maxDepth){
6799 return this.findParentNode(simpleSelector, maxDepth, true);
6805 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6806 * @param {String} selector The simple selector to test
6807 * @return {Boolean} True if this element matches the selector, else false
6809 is : function(simpleSelector){
6810 return Roo.DomQuery.is(this.dom, simpleSelector);
6814 * Perform animation on this element.
6815 * @param {Object} args The YUI animation control args
6816 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6817 * @param {Function} onComplete (optional) Function to call when animation completes
6818 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6819 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6820 * @return {Roo.Element} this
6822 animate : function(args, duration, onComplete, easing, animType){
6823 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6828 * @private Internal animation call
6830 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6831 animType = animType || 'run';
6833 var anim = Roo.lib.Anim[animType](
6835 (opt.duration || defaultDur) || .35,
6836 (opt.easing || defaultEase) || 'easeOut',
6838 Roo.callback(cb, this);
6839 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6847 // private legacy anim prep
6848 preanim : function(a, i){
6849 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6853 * Removes worthless text nodes
6854 * @param {Boolean} forceReclean (optional) By default the element
6855 * keeps track if it has been cleaned already so
6856 * you can call this over and over. However, if you update the element and
6857 * need to force a reclean, you can pass true.
6859 clean : function(forceReclean){
6860 if(this.isCleaned && forceReclean !== true){
6864 var d = this.dom, n = d.firstChild, ni = -1;
6866 var nx = n.nextSibling;
6867 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6874 this.isCleaned = true;
6879 calcOffsetsTo : function(el){
6882 var restorePos = false;
6883 if(el.getStyle('position') == 'static'){
6884 el.position('relative');
6889 while(op && op != d && op.tagName != 'HTML'){
6892 op = op.offsetParent;
6895 el.position('static');
6901 * Scrolls this element into view within the passed container.
6902 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6903 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6904 * @return {Roo.Element} this
6906 scrollIntoView : function(container, hscroll){
6907 var c = Roo.getDom(container) || document.body;
6910 var o = this.calcOffsetsTo(c),
6913 b = t+el.offsetHeight,
6914 r = l+el.offsetWidth;
6916 var ch = c.clientHeight;
6917 var ct = parseInt(c.scrollTop, 10);
6918 var cl = parseInt(c.scrollLeft, 10);
6920 var cr = cl + c.clientWidth;
6928 if(hscroll !== false){
6932 c.scrollLeft = r-c.clientWidth;
6939 scrollChildIntoView : function(child, hscroll){
6940 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6944 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6945 * the new height may not be available immediately.
6946 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6947 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6948 * @param {Function} onComplete (optional) Function to call when animation completes
6949 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
6950 * @return {Roo.Element} this
6952 autoHeight : function(animate, duration, onComplete, easing){
6953 var oldHeight = this.getHeight();
6955 this.setHeight(1); // force clipping
6956 setTimeout(function(){
6957 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
6959 this.setHeight(height);
6961 if(typeof onComplete == "function"){
6965 this.setHeight(oldHeight); // restore original height
6966 this.setHeight(height, animate, duration, function(){
6968 if(typeof onComplete == "function") onComplete();
6969 }.createDelegate(this), easing);
6971 }.createDelegate(this), 0);
6976 * Returns true if this element is an ancestor of the passed element
6977 * @param {HTMLElement/String} el The element to check
6978 * @return {Boolean} True if this element is an ancestor of el, else false
6980 contains : function(el){
6981 if(!el){return false;}
6982 return D.isAncestor(this.dom, el.dom ? el.dom : el);
6986 * Checks whether the element is currently visible using both visibility and display properties.
6987 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
6988 * @return {Boolean} True if the element is currently visible, else false
6990 isVisible : function(deep) {
6991 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
6992 if(deep !== true || !vis){
6995 var p = this.dom.parentNode;
6996 while(p && p.tagName.toLowerCase() != "body"){
6997 if(!Roo.fly(p, '_isVisible').isVisible()){
7006 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7007 * @param {String} selector The CSS selector
7008 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7009 * @return {CompositeElement/CompositeElementLite} The composite element
7011 select : function(selector, unique){
7012 return El.select(selector, unique, this.dom);
7016 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7017 * @param {String} selector The CSS selector
7018 * @return {Array} An array of the matched nodes
7020 query : function(selector, unique){
7021 return Roo.DomQuery.select(selector, this.dom);
7025 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7026 * @param {String} selector The CSS selector
7027 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7028 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7030 child : function(selector, returnDom){
7031 var n = Roo.DomQuery.selectNode(selector, this.dom);
7032 return returnDom ? n : Roo.get(n);
7036 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7037 * @param {String} selector The CSS selector
7038 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7039 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7041 down : function(selector, returnDom){
7042 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7043 return returnDom ? n : Roo.get(n);
7047 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7048 * @param {String} group The group the DD object is member of
7049 * @param {Object} config The DD config object
7050 * @param {Object} overrides An object containing methods to override/implement on the DD object
7051 * @return {Roo.dd.DD} The DD object
7053 initDD : function(group, config, overrides){
7054 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7055 return Roo.apply(dd, overrides);
7059 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7060 * @param {String} group The group the DDProxy object is member of
7061 * @param {Object} config The DDProxy config object
7062 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7063 * @return {Roo.dd.DDProxy} The DDProxy object
7065 initDDProxy : function(group, config, overrides){
7066 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7067 return Roo.apply(dd, overrides);
7071 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7072 * @param {String} group The group the DDTarget object is member of
7073 * @param {Object} config The DDTarget config object
7074 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7075 * @return {Roo.dd.DDTarget} The DDTarget object
7077 initDDTarget : function(group, config, overrides){
7078 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7079 return Roo.apply(dd, overrides);
7083 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7084 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7085 * @param {Boolean} visible Whether the element is visible
7086 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7087 * @return {Roo.Element} this
7089 setVisible : function(visible, animate){
7091 if(this.visibilityMode == El.DISPLAY){
7092 this.setDisplayed(visible);
7095 this.dom.style.visibility = visible ? "visible" : "hidden";
7098 // closure for composites
7100 var visMode = this.visibilityMode;
7102 this.setOpacity(.01);
7103 this.setVisible(true);
7105 this.anim({opacity: { to: (visible?1:0) }},
7106 this.preanim(arguments, 1),
7107 null, .35, 'easeIn', function(){
7109 if(visMode == El.DISPLAY){
7110 dom.style.display = "none";
7112 dom.style.visibility = "hidden";
7114 Roo.get(dom).setOpacity(1);
7122 * Returns true if display is not "none"
7125 isDisplayed : function() {
7126 return this.getStyle("display") != "none";
7130 * Toggles the element's visibility or display, depending on visibility mode.
7131 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7132 * @return {Roo.Element} this
7134 toggle : function(animate){
7135 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7140 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7141 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7142 * @return {Roo.Element} this
7144 setDisplayed : function(value) {
7145 if(typeof value == "boolean"){
7146 value = value ? this.originalDisplay : "none";
7148 this.setStyle("display", value);
7153 * Tries to focus the element. Any exceptions are caught and ignored.
7154 * @return {Roo.Element} this
7156 focus : function() {
7164 * Tries to blur the element. Any exceptions are caught and ignored.
7165 * @return {Roo.Element} this
7175 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7176 * @param {String/Array} className The CSS class to add, or an array of classes
7177 * @return {Roo.Element} this
7179 addClass : function(className){
7180 if(className instanceof Array){
7181 for(var i = 0, len = className.length; i < len; i++) {
7182 this.addClass(className[i]);
7185 if(className && !this.hasClass(className)){
7186 this.dom.className = this.dom.className + " " + className;
7193 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7194 * @param {String/Array} className The CSS class to add, or an array of classes
7195 * @return {Roo.Element} this
7197 radioClass : function(className){
7198 var siblings = this.dom.parentNode.childNodes;
7199 for(var i = 0; i < siblings.length; i++) {
7200 var s = siblings[i];
7201 if(s.nodeType == 1){
7202 Roo.get(s).removeClass(className);
7205 this.addClass(className);
7210 * Removes one or more CSS classes from the element.
7211 * @param {String/Array} className The CSS class to remove, or an array of classes
7212 * @return {Roo.Element} this
7214 removeClass : function(className){
7215 if(!className || !this.dom.className){
7218 if(className instanceof Array){
7219 for(var i = 0, len = className.length; i < len; i++) {
7220 this.removeClass(className[i]);
7223 if(this.hasClass(className)){
7224 var re = this.classReCache[className];
7226 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7227 this.classReCache[className] = re;
7229 this.dom.className =
7230 this.dom.className.replace(re, " ");
7240 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7241 * @param {String} className The CSS class to toggle
7242 * @return {Roo.Element} this
7244 toggleClass : function(className){
7245 if(this.hasClass(className)){
7246 this.removeClass(className);
7248 this.addClass(className);
7254 * Checks if the specified CSS class exists on this element's DOM node.
7255 * @param {String} className The CSS class to check for
7256 * @return {Boolean} True if the class exists, else false
7258 hasClass : function(className){
7259 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7263 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7264 * @param {String} oldClassName The CSS class to replace
7265 * @param {String} newClassName The replacement CSS class
7266 * @return {Roo.Element} this
7268 replaceClass : function(oldClassName, newClassName){
7269 this.removeClass(oldClassName);
7270 this.addClass(newClassName);
7275 * Returns an object with properties matching the styles requested.
7276 * For example, el.getStyles('color', 'font-size', 'width') might return
7277 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7278 * @param {String} style1 A style name
7279 * @param {String} style2 A style name
7280 * @param {String} etc.
7281 * @return {Object} The style object
7283 getStyles : function(){
7284 var a = arguments, len = a.length, r = {};
7285 for(var i = 0; i < len; i++){
7286 r[a[i]] = this.getStyle(a[i]);
7292 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7293 * @param {String} property The style property whose value is returned.
7294 * @return {String} The current value of the style property for this element.
7296 getStyle : function(){
7297 return view && view.getComputedStyle ?
7299 var el = this.dom, v, cs, camel;
7300 if(prop == 'float'){
7303 if(el.style && (v = el.style[prop])){
7306 if(cs = view.getComputedStyle(el, "")){
7307 if(!(camel = propCache[prop])){
7308 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7315 var el = this.dom, v, cs, camel;
7316 if(prop == 'opacity'){
7317 if(typeof el.style.filter == 'string'){
7318 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7320 var fv = parseFloat(m[1]);
7322 return fv ? fv / 100 : 0;
7327 }else if(prop == 'float'){
7328 prop = "styleFloat";
7330 if(!(camel = propCache[prop])){
7331 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7333 if(v = el.style[camel]){
7336 if(cs = el.currentStyle){
7344 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7345 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7346 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7347 * @return {Roo.Element} this
7349 setStyle : function(prop, value){
7350 if(typeof prop == "string"){
7352 if(!(camel = propCache[prop])){
7353 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7355 if(camel == 'opacity') {
7356 this.setOpacity(value);
7358 this.dom.style[camel] = value;
7361 for(var style in prop){
7362 if(typeof prop[style] != "function"){
7363 this.setStyle(style, prop[style]);
7371 * More flexible version of {@link #setStyle} for setting style properties.
7372 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7373 * a function which returns such a specification.
7374 * @return {Roo.Element} this
7376 applyStyles : function(style){
7377 Roo.DomHelper.applyStyles(this.dom, style);
7382 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7383 * @return {Number} The X position of the element
7386 return D.getX(this.dom);
7390 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7391 * @return {Number} The Y position of the element
7394 return D.getY(this.dom);
7398 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7399 * @return {Array} The XY position of the element
7402 return D.getXY(this.dom);
7406 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7407 * @param {Number} The X position of the element
7408 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7409 * @return {Roo.Element} this
7411 setX : function(x, animate){
7413 D.setX(this.dom, x);
7415 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7421 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7422 * @param {Number} The Y position of the element
7423 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7424 * @return {Roo.Element} this
7426 setY : function(y, animate){
7428 D.setY(this.dom, y);
7430 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7436 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7437 * @param {String} left The left CSS property value
7438 * @return {Roo.Element} this
7440 setLeft : function(left){
7441 this.setStyle("left", this.addUnits(left));
7446 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7447 * @param {String} top The top CSS property value
7448 * @return {Roo.Element} this
7450 setTop : function(top){
7451 this.setStyle("top", this.addUnits(top));
7456 * Sets the element's CSS right style.
7457 * @param {String} right The right CSS property value
7458 * @return {Roo.Element} this
7460 setRight : function(right){
7461 this.setStyle("right", this.addUnits(right));
7466 * Sets the element's CSS bottom style.
7467 * @param {String} bottom The bottom CSS property value
7468 * @return {Roo.Element} this
7470 setBottom : function(bottom){
7471 this.setStyle("bottom", this.addUnits(bottom));
7476 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7477 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7478 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7479 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7480 * @return {Roo.Element} this
7482 setXY : function(pos, animate){
7484 D.setXY(this.dom, pos);
7486 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7492 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7493 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7494 * @param {Number} x X value for new position (coordinates are page-based)
7495 * @param {Number} y Y value for new position (coordinates are page-based)
7496 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7497 * @return {Roo.Element} this
7499 setLocation : function(x, y, animate){
7500 this.setXY([x, y], this.preanim(arguments, 2));
7505 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7506 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7507 * @param {Number} x X value for new position (coordinates are page-based)
7508 * @param {Number} y Y value for new position (coordinates are page-based)
7509 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7510 * @return {Roo.Element} this
7512 moveTo : function(x, y, animate){
7513 this.setXY([x, y], this.preanim(arguments, 2));
7518 * Returns the region of the given element.
7519 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7520 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7522 getRegion : function(){
7523 return D.getRegion(this.dom);
7527 * Returns the offset height of the element
7528 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7529 * @return {Number} The element's height
7531 getHeight : function(contentHeight){
7532 var h = this.dom.offsetHeight || 0;
7533 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7537 * Returns the offset width of the element
7538 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7539 * @return {Number} The element's width
7541 getWidth : function(contentWidth){
7542 var w = this.dom.offsetWidth || 0;
7543 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7547 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7548 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7549 * if a height has not been set using CSS.
7552 getComputedHeight : function(){
7553 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7555 h = parseInt(this.getStyle('height'), 10) || 0;
7556 if(!this.isBorderBox()){
7557 h += this.getFrameWidth('tb');
7564 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7565 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7566 * if a width has not been set using CSS.
7569 getComputedWidth : function(){
7570 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7572 w = parseInt(this.getStyle('width'), 10) || 0;
7573 if(!this.isBorderBox()){
7574 w += this.getFrameWidth('lr');
7581 * Returns the size of the element.
7582 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7583 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7585 getSize : function(contentSize){
7586 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7590 * Returns the width and height of the viewport.
7591 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7593 getViewSize : function(){
7594 var d = this.dom, doc = document, aw = 0, ah = 0;
7595 if(d == doc || d == doc.body){
7596 return {width : D.getViewWidth(), height: D.getViewHeight()};
7599 width : d.clientWidth,
7600 height: d.clientHeight
7606 * Returns the value of the "value" attribute
7607 * @param {Boolean} asNumber true to parse the value as a number
7608 * @return {String/Number}
7610 getValue : function(asNumber){
7611 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7615 adjustWidth : function(width){
7616 if(typeof width == "number"){
7617 if(this.autoBoxAdjust && !this.isBorderBox()){
7618 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7628 adjustHeight : function(height){
7629 if(typeof height == "number"){
7630 if(this.autoBoxAdjust && !this.isBorderBox()){
7631 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7641 * Set the width of the element
7642 * @param {Number} width The new width
7643 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7644 * @return {Roo.Element} this
7646 setWidth : function(width, animate){
7647 width = this.adjustWidth(width);
7649 this.dom.style.width = this.addUnits(width);
7651 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7657 * Set the height of the element
7658 * @param {Number} height The new height
7659 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7660 * @return {Roo.Element} this
7662 setHeight : function(height, animate){
7663 height = this.adjustHeight(height);
7665 this.dom.style.height = this.addUnits(height);
7667 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7673 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7674 * @param {Number} width The new width
7675 * @param {Number} height The new height
7676 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7677 * @return {Roo.Element} this
7679 setSize : function(width, height, animate){
7680 if(typeof width == "object"){ // in case of object from getSize()
7681 height = width.height; width = width.width;
7683 width = this.adjustWidth(width); height = this.adjustHeight(height);
7685 this.dom.style.width = this.addUnits(width);
7686 this.dom.style.height = this.addUnits(height);
7688 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7694 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7695 * @param {Number} x X value for new position (coordinates are page-based)
7696 * @param {Number} y Y value for new position (coordinates are page-based)
7697 * @param {Number} width The new width
7698 * @param {Number} height The new height
7699 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7700 * @return {Roo.Element} this
7702 setBounds : function(x, y, width, height, animate){
7704 this.setSize(width, height);
7705 this.setLocation(x, y);
7707 width = this.adjustWidth(width); height = this.adjustHeight(height);
7708 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7709 this.preanim(arguments, 4), 'motion');
7715 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7716 * @param {Roo.lib.Region} region The region to fill
7717 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7718 * @return {Roo.Element} this
7720 setRegion : function(region, animate){
7721 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7726 * Appends an event handler
7728 * @param {String} eventName The type of event to append
7729 * @param {Function} fn The method the event invokes
7730 * @param {Object} scope (optional) The scope (this object) of the fn
7731 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7733 addListener : function(eventName, fn, scope, options){
7734 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7738 * Removes an event handler from this element
7739 * @param {String} eventName the type of event to remove
7740 * @param {Function} fn the method the event invokes
7741 * @return {Roo.Element} this
7743 removeListener : function(eventName, fn){
7744 Roo.EventManager.removeListener(this.dom, eventName, fn);
7749 * Removes all previous added listeners from this element
7750 * @return {Roo.Element} this
7752 removeAllListeners : function(){
7753 E.purgeElement(this.dom);
7757 relayEvent : function(eventName, observable){
7758 this.on(eventName, function(e){
7759 observable.fireEvent(eventName, e);
7764 * Set the opacity of the element
7765 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7766 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7767 * @return {Roo.Element} this
7769 setOpacity : function(opacity, animate){
7771 var s = this.dom.style;
7774 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7775 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7777 s.opacity = opacity;
7780 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7786 * Gets the left X coordinate
7787 * @param {Boolean} local True to get the local css position instead of page coordinate
7790 getLeft : function(local){
7794 return parseInt(this.getStyle("left"), 10) || 0;
7799 * Gets the right X coordinate of the element (element X position + element width)
7800 * @param {Boolean} local True to get the local css position instead of page coordinate
7803 getRight : function(local){
7805 return this.getX() + this.getWidth();
7807 return (this.getLeft(true) + this.getWidth()) || 0;
7812 * Gets the top Y coordinate
7813 * @param {Boolean} local True to get the local css position instead of page coordinate
7816 getTop : function(local) {
7820 return parseInt(this.getStyle("top"), 10) || 0;
7825 * Gets the bottom Y coordinate of the element (element Y position + element height)
7826 * @param {Boolean} local True to get the local css position instead of page coordinate
7829 getBottom : function(local){
7831 return this.getY() + this.getHeight();
7833 return (this.getTop(true) + this.getHeight()) || 0;
7838 * Initializes positioning on this element. If a desired position is not passed, it will make the
7839 * the element positioned relative IF it is not already positioned.
7840 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7841 * @param {Number} zIndex (optional) The zIndex to apply
7842 * @param {Number} x (optional) Set the page X position
7843 * @param {Number} y (optional) Set the page Y position
7845 position : function(pos, zIndex, x, y){
7847 if(this.getStyle('position') == 'static'){
7848 this.setStyle('position', 'relative');
7851 this.setStyle("position", pos);
7854 this.setStyle("z-index", zIndex);
7856 if(x !== undefined && y !== undefined){
7858 }else if(x !== undefined){
7860 }else if(y !== undefined){
7866 * Clear positioning back to the default when the document was loaded
7867 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7868 * @return {Roo.Element} this
7870 clearPositioning : function(value){
7878 "position" : "static"
7884 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7885 * snapshot before performing an update and then restoring the element.
7888 getPositioning : function(){
7889 var l = this.getStyle("left");
7890 var t = this.getStyle("top");
7892 "position" : this.getStyle("position"),
7894 "right" : l ? "" : this.getStyle("right"),
7896 "bottom" : t ? "" : this.getStyle("bottom"),
7897 "z-index" : this.getStyle("z-index")
7902 * Gets the width of the border(s) for the specified side(s)
7903 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7904 * passing lr would get the border (l)eft width + the border (r)ight width.
7905 * @return {Number} The width of the sides passed added together
7907 getBorderWidth : function(side){
7908 return this.addStyles(side, El.borders);
7912 * Gets the width of the padding(s) for the specified side(s)
7913 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7914 * passing lr would get the padding (l)eft + the padding (r)ight.
7915 * @return {Number} The padding of the sides passed added together
7917 getPadding : function(side){
7918 return this.addStyles(side, El.paddings);
7922 * Set positioning with an object returned by getPositioning().
7923 * @param {Object} posCfg
7924 * @return {Roo.Element} this
7926 setPositioning : function(pc){
7927 this.applyStyles(pc);
7928 if(pc.right == "auto"){
7929 this.dom.style.right = "";
7931 if(pc.bottom == "auto"){
7932 this.dom.style.bottom = "";
7938 fixDisplay : function(){
7939 if(this.getStyle("display") == "none"){
7940 this.setStyle("visibility", "hidden");
7941 this.setStyle("display", this.originalDisplay); // first try reverting to default
7942 if(this.getStyle("display") == "none"){ // if that fails, default to block
7943 this.setStyle("display", "block");
7949 * Quick set left and top adding default units
7950 * @param {String} left The left CSS property value
7951 * @param {String} top The top CSS property value
7952 * @return {Roo.Element} this
7954 setLeftTop : function(left, top){
7955 this.dom.style.left = this.addUnits(left);
7956 this.dom.style.top = this.addUnits(top);
7961 * Move this element relative to its current position.
7962 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
7963 * @param {Number} distance How far to move the element in pixels
7964 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7965 * @return {Roo.Element} this
7967 move : function(direction, distance, animate){
7968 var xy = this.getXY();
7969 direction = direction.toLowerCase();
7973 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
7977 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
7982 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
7987 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
7994 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
7995 * @return {Roo.Element} this
7998 if(!this.isClipped){
7999 this.isClipped = true;
8000 this.originalClip = {
8001 "o": this.getStyle("overflow"),
8002 "x": this.getStyle("overflow-x"),
8003 "y": this.getStyle("overflow-y")
8005 this.setStyle("overflow", "hidden");
8006 this.setStyle("overflow-x", "hidden");
8007 this.setStyle("overflow-y", "hidden");
8013 * Return clipping (overflow) to original clipping before clip() was called
8014 * @return {Roo.Element} this
8016 unclip : function(){
8018 this.isClipped = false;
8019 var o = this.originalClip;
8020 if(o.o){this.setStyle("overflow", o.o);}
8021 if(o.x){this.setStyle("overflow-x", o.x);}
8022 if(o.y){this.setStyle("overflow-y", o.y);}
8029 * Gets the x,y coordinates specified by the anchor position on the element.
8030 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8031 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8032 * {width: (target width), height: (target height)} (defaults to the element's current size)
8033 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8034 * @return {Array} [x, y] An array containing the element's x and y coordinates
8036 getAnchorXY : function(anchor, local, s){
8037 //Passing a different size is useful for pre-calculating anchors,
8038 //especially for anchored animations that change the el size.
8040 var w, h, vp = false;
8043 if(d == document.body || d == document){
8045 w = D.getViewWidth(); h = D.getViewHeight();
8047 w = this.getWidth(); h = this.getHeight();
8050 w = s.width; h = s.height;
8052 var x = 0, y = 0, r = Math.round;
8053 switch((anchor || "tl").toLowerCase()){
8095 var sc = this.getScroll();
8096 return [x + sc.left, y + sc.top];
8098 //Add the element's offset xy
8099 var o = this.getXY();
8100 return [x+o[0], y+o[1]];
8104 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8105 * supported position values.
8106 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8107 * @param {String} position The position to align to.
8108 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8109 * @return {Array} [x, y]
8111 getAlignToXY : function(el, p, o){
8115 throw "Element.alignTo with an element that doesn't exist";
8117 var c = false; //constrain to viewport
8118 var p1 = "", p2 = "";
8125 }else if(p.indexOf("-") == -1){
8128 p = p.toLowerCase();
8129 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8131 throw "Element.alignTo with an invalid alignment " + p;
8133 p1 = m[1]; p2 = m[2]; c = !!m[3];
8135 //Subtract the aligned el's internal xy from the target's offset xy
8136 //plus custom offset to get the aligned el's new offset xy
8137 var a1 = this.getAnchorXY(p1, true);
8138 var a2 = el.getAnchorXY(p2, false);
8139 var x = a2[0] - a1[0] + o[0];
8140 var y = a2[1] - a1[1] + o[1];
8142 //constrain the aligned el to viewport if necessary
8143 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8144 // 5px of margin for ie
8145 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8147 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8148 //perpendicular to the vp border, allow the aligned el to slide on that border,
8149 //otherwise swap the aligned el to the opposite border of the target.
8150 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8151 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8152 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8153 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8156 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8157 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8159 if((x+w) > dw + scrollX){
8160 x = swapX ? r.left-w : dw+scrollX-w;
8163 x = swapX ? r.right : scrollX;
8165 if((y+h) > dh + scrollY){
8166 y = swapY ? r.top-h : dh+scrollY-h;
8169 y = swapY ? r.bottom : scrollY;
8176 getConstrainToXY : function(){
8177 var os = {top:0, left:0, bottom:0, right: 0};
8179 return function(el, local, offsets, proposedXY){
8181 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8183 var vw, vh, vx = 0, vy = 0;
8184 if(el.dom == document.body || el.dom == document){
8185 vw = Roo.lib.Dom.getViewWidth();
8186 vh = Roo.lib.Dom.getViewHeight();
8188 vw = el.dom.clientWidth;
8189 vh = el.dom.clientHeight;
8191 var vxy = el.getXY();
8197 var s = el.getScroll();
8199 vx += offsets.left + s.left;
8200 vy += offsets.top + s.top;
8202 vw -= offsets.right;
8203 vh -= offsets.bottom;
8208 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8209 var x = xy[0], y = xy[1];
8210 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8212 // only move it if it needs it
8215 // first validate right/bottom
8224 // then make sure top/left isn't negative
8233 return moved ? [x, y] : false;
8238 adjustForConstraints : function(xy, parent, offsets){
8239 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8243 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8244 * document it aligns it to the viewport.
8245 * The position parameter is optional, and can be specified in any one of the following formats:
8247 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8248 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8249 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8250 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8251 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8252 * element's anchor point, and the second value is used as the target's anchor point.</li>
8254 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8255 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8256 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8257 * that specified in order to enforce the viewport constraints.
8258 * Following are all of the supported anchor positions:
8261 ----- -----------------------------
8262 tl The top left corner (default)
8263 t The center of the top edge
8264 tr The top right corner
8265 l The center of the left edge
8266 c In the center of the element
8267 r The center of the right edge
8268 bl The bottom left corner
8269 b The center of the bottom edge
8270 br The bottom right corner
8274 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8275 el.alignTo("other-el");
8277 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8278 el.alignTo("other-el", "tr?");
8280 // align the bottom right corner of el with the center left edge of other-el
8281 el.alignTo("other-el", "br-l?");
8283 // align the center of el with the bottom left corner of other-el and
8284 // adjust the x position by -6 pixels (and the y position by 0)
8285 el.alignTo("other-el", "c-bl", [-6, 0]);
8287 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8288 * @param {String} position The position to align to.
8289 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8290 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8291 * @return {Roo.Element} this
8293 alignTo : function(element, position, offsets, animate){
8294 var xy = this.getAlignToXY(element, position, offsets);
8295 this.setXY(xy, this.preanim(arguments, 3));
8300 * Anchors an element to another element and realigns it when the window is resized.
8301 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8302 * @param {String} position The position to align to.
8303 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8304 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8305 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8306 * is a number, it is used as the buffer delay (defaults to 50ms).
8307 * @param {Function} callback The function to call after the animation finishes
8308 * @return {Roo.Element} this
8310 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8311 var action = function(){
8312 this.alignTo(el, alignment, offsets, animate);
8313 Roo.callback(callback, this);
8315 Roo.EventManager.onWindowResize(action, this);
8316 var tm = typeof monitorScroll;
8317 if(tm != 'undefined'){
8318 Roo.EventManager.on(window, 'scroll', action, this,
8319 {buffer: tm == 'number' ? monitorScroll : 50});
8321 action.call(this); // align immediately
8325 * Clears any opacity settings from this element. Required in some cases for IE.
8326 * @return {Roo.Element} this
8328 clearOpacity : function(){
8329 if (window.ActiveXObject) {
8330 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8331 this.dom.style.filter = "";
8334 this.dom.style.opacity = "";
8335 this.dom.style["-moz-opacity"] = "";
8336 this.dom.style["-khtml-opacity"] = "";
8342 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8343 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8344 * @return {Roo.Element} this
8346 hide : function(animate){
8347 this.setVisible(false, this.preanim(arguments, 0));
8352 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8353 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8354 * @return {Roo.Element} this
8356 show : function(animate){
8357 this.setVisible(true, this.preanim(arguments, 0));
8362 * @private Test if size has a unit, otherwise appends the default
8364 addUnits : function(size){
8365 return Roo.Element.addUnits(size, this.defaultUnit);
8369 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8370 * @return {Roo.Element} this
8372 beginMeasure : function(){
8374 if(el.offsetWidth || el.offsetHeight){
8375 return this; // offsets work already
8378 var p = this.dom, b = document.body; // start with this element
8379 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8380 var pe = Roo.get(p);
8381 if(pe.getStyle('display') == 'none'){
8382 changed.push({el: p, visibility: pe.getStyle("visibility")});
8383 p.style.visibility = "hidden";
8384 p.style.display = "block";
8388 this._measureChanged = changed;
8394 * Restores displays to before beginMeasure was called
8395 * @return {Roo.Element} this
8397 endMeasure : function(){
8398 var changed = this._measureChanged;
8400 for(var i = 0, len = changed.length; i < len; i++) {
8402 r.el.style.visibility = r.visibility;
8403 r.el.style.display = "none";
8405 this._measureChanged = null;
8411 * Update the innerHTML of this element, optionally searching for and processing scripts
8412 * @param {String} html The new HTML
8413 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8414 * @param {Function} callback For async script loading you can be noticed when the update completes
8415 * @return {Roo.Element} this
8417 update : function(html, loadScripts, callback){
8418 if(typeof html == "undefined"){
8421 if(loadScripts !== true){
8422 this.dom.innerHTML = html;
8423 if(typeof callback == "function"){
8431 html += '<span id="' + id + '"></span>';
8433 E.onAvailable(id, function(){
8434 var hd = document.getElementsByTagName("head")[0];
8435 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8436 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8437 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8440 while(match = re.exec(html)){
8441 var attrs = match[1];
8442 var srcMatch = attrs ? attrs.match(srcRe) : false;
8443 if(srcMatch && srcMatch[2]){
8444 var s = document.createElement("script");
8445 s.src = srcMatch[2];
8446 var typeMatch = attrs.match(typeRe);
8447 if(typeMatch && typeMatch[2]){
8448 s.type = typeMatch[2];
8451 }else if(match[2] && match[2].length > 0){
8452 if(window.execScript) {
8453 window.execScript(match[2]);
8461 window.eval(match[2]);
8465 var el = document.getElementById(id);
8466 if(el){el.parentNode.removeChild(el);}
8467 if(typeof callback == "function"){
8471 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8476 * Direct access to the UpdateManager update() method (takes the same parameters).
8477 * @param {String/Function} url The url for this request or a function to call to get the url
8478 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8479 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8480 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8481 * @return {Roo.Element} this
8484 var um = this.getUpdateManager();
8485 um.update.apply(um, arguments);
8490 * Gets this element's UpdateManager
8491 * @return {Roo.UpdateManager} The UpdateManager
8493 getUpdateManager : function(){
8494 if(!this.updateManager){
8495 this.updateManager = new Roo.UpdateManager(this);
8497 return this.updateManager;
8501 * Disables text selection for this element (normalized across browsers)
8502 * @return {Roo.Element} this
8504 unselectable : function(){
8505 this.dom.unselectable = "on";
8506 this.swallowEvent("selectstart", true);
8507 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8508 this.addClass("x-unselectable");
8513 * Calculates the x, y to center this element on the screen
8514 * @return {Array} The x, y values [x, y]
8516 getCenterXY : function(){
8517 return this.getAlignToXY(document, 'c-c');
8521 * Centers the Element in either the viewport, or another Element.
8522 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8524 center : function(centerIn){
8525 this.alignTo(centerIn || document, 'c-c');
8530 * Tests various css rules/browsers to determine if this element uses a border box
8533 isBorderBox : function(){
8534 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8538 * Return a box {x, y, width, height} that can be used to set another elements
8539 * size/location to match this element.
8540 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8541 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8542 * @return {Object} box An object in the format {x, y, width, height}
8544 getBox : function(contentBox, local){
8549 var left = parseInt(this.getStyle("left"), 10) || 0;
8550 var top = parseInt(this.getStyle("top"), 10) || 0;
8553 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8555 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8557 var l = this.getBorderWidth("l")+this.getPadding("l");
8558 var r = this.getBorderWidth("r")+this.getPadding("r");
8559 var t = this.getBorderWidth("t")+this.getPadding("t");
8560 var b = this.getBorderWidth("b")+this.getPadding("b");
8561 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8563 bx.right = bx.x + bx.width;
8564 bx.bottom = bx.y + bx.height;
8569 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8570 for more information about the sides.
8571 * @param {String} sides
8574 getFrameWidth : function(sides, onlyContentBox){
8575 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8579 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8580 * @param {Object} box The box to fill {x, y, width, height}
8581 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8582 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8583 * @return {Roo.Element} this
8585 setBox : function(box, adjust, animate){
8586 var w = box.width, h = box.height;
8587 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8588 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8589 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8591 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8596 * Forces the browser to repaint this element
8597 * @return {Roo.Element} this
8599 repaint : function(){
8601 this.addClass("x-repaint");
8602 setTimeout(function(){
8603 Roo.get(dom).removeClass("x-repaint");
8609 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8610 * then it returns the calculated width of the sides (see getPadding)
8611 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8612 * @return {Object/Number}
8614 getMargins : function(side){
8617 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8618 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8619 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8620 right: parseInt(this.getStyle("margin-right"), 10) || 0
8623 return this.addStyles(side, El.margins);
8628 addStyles : function(sides, styles){
8630 for(var i = 0, len = sides.length; i < len; i++){
8631 v = this.getStyle(styles[sides.charAt(i)]);
8633 w = parseInt(v, 10);
8641 * Creates a proxy element of this element
8642 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8643 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8644 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8645 * @return {Roo.Element} The new proxy element
8647 createProxy : function(config, renderTo, matchBox){
8649 renderTo = Roo.getDom(renderTo);
8651 renderTo = document.body;
8653 config = typeof config == "object" ?
8654 config : {tag : "div", cls: config};
8655 var proxy = Roo.DomHelper.append(renderTo, config, true);
8657 proxy.setBox(this.getBox());
8663 * Puts a mask over this element to disable user interaction. Requires core.css.
8664 * This method can only be applied to elements which accept child nodes.
8665 * @param {String} msg (optional) A message to display in the mask
8666 * @param {String} msgCls (optional) A css class to apply to the msg element
8667 * @return {Element} The mask element
8669 mask : function(msg, msgCls){
8670 if(this.getStyle("position") == "static"){
8671 this.setStyle("position", "relative");
8674 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8676 this.addClass("x-masked");
8677 this._mask.setDisplayed(true);
8678 if(typeof msg == 'string'){
8680 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8682 var mm = this._maskMsg;
8683 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8684 mm.dom.firstChild.innerHTML = msg;
8685 mm.setDisplayed(true);
8688 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8689 this._mask.setHeight(this.getHeight());
8695 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8696 * it is cached for reuse.
8698 unmask : function(removeEl){
8700 if(removeEl === true){
8701 this._mask.remove();
8704 this._maskMsg.remove();
8705 delete this._maskMsg;
8708 this._mask.setDisplayed(false);
8710 this._maskMsg.setDisplayed(false);
8714 this.removeClass("x-masked");
8718 * Returns true if this element is masked
8721 isMasked : function(){
8722 return this._mask && this._mask.isVisible();
8726 * Creates an iframe shim for this element to keep selects and other windowed objects from
8728 * @return {Roo.Element} The new shim element
8730 createShim : function(){
8731 var el = document.createElement('iframe');
8732 el.frameBorder = 'no';
8733 el.className = 'roo-shim';
8734 if(Roo.isIE && Roo.isSecure){
8735 el.src = Roo.SSL_SECURE_URL;
8737 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8738 shim.autoBoxAdjust = false;
8743 * Removes this element from the DOM and deletes it from the cache
8745 remove : function(){
8746 if(this.dom.parentNode){
8747 this.dom.parentNode.removeChild(this.dom);
8749 delete El.cache[this.dom.id];
8753 * Sets up event handlers to add and remove a css class when the mouse is over this element
8754 * @param {String} className
8755 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8756 * mouseout events for children elements
8757 * @return {Roo.Element} this
8759 addClassOnOver : function(className, preventFlicker){
8760 this.on("mouseover", function(){
8761 Roo.fly(this, '_internal').addClass(className);
8763 var removeFn = function(e){
8764 if(preventFlicker !== true || !e.within(this, true)){
8765 Roo.fly(this, '_internal').removeClass(className);
8768 this.on("mouseout", removeFn, this.dom);
8773 * Sets up event handlers to add and remove a css class when this element has the focus
8774 * @param {String} className
8775 * @return {Roo.Element} this
8777 addClassOnFocus : function(className){
8778 this.on("focus", function(){
8779 Roo.fly(this, '_internal').addClass(className);
8781 this.on("blur", function(){
8782 Roo.fly(this, '_internal').removeClass(className);
8787 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
8788 * @param {String} className
8789 * @return {Roo.Element} this
8791 addClassOnClick : function(className){
8793 this.on("mousedown", function(){
8794 Roo.fly(dom, '_internal').addClass(className);
8795 var d = Roo.get(document);
8796 var fn = function(){
8797 Roo.fly(dom, '_internal').removeClass(className);
8798 d.removeListener("mouseup", fn);
8800 d.on("mouseup", fn);
8806 * Stops the specified event from bubbling and optionally prevents the default action
8807 * @param {String} eventName
8808 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8809 * @return {Roo.Element} this
8811 swallowEvent : function(eventName, preventDefault){
8812 var fn = function(e){
8813 e.stopPropagation();
8818 if(eventName instanceof Array){
8819 for(var i = 0, len = eventName.length; i < len; i++){
8820 this.on(eventName[i], fn);
8824 this.on(eventName, fn);
8831 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8834 * Sizes this element to its parent element's dimensions performing
8835 * neccessary box adjustments.
8836 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8837 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8838 * @return {Roo.Element} this
8840 fitToParent : function(monitorResize, targetParent) {
8841 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8842 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8843 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8846 var p = Roo.get(targetParent || this.dom.parentNode);
8847 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8848 if (monitorResize === true) {
8849 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8850 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8856 * Gets the next sibling, skipping text nodes
8857 * @return {HTMLElement} The next sibling or null
8859 getNextSibling : function(){
8860 var n = this.dom.nextSibling;
8861 while(n && n.nodeType != 1){
8868 * Gets the previous sibling, skipping text nodes
8869 * @return {HTMLElement} The previous sibling or null
8871 getPrevSibling : function(){
8872 var n = this.dom.previousSibling;
8873 while(n && n.nodeType != 1){
8874 n = n.previousSibling;
8881 * Appends the passed element(s) to this element
8882 * @param {String/HTMLElement/Array/Element/CompositeElement} el
8883 * @return {Roo.Element} this
8885 appendChild: function(el){
8892 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8893 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
8894 * automatically generated with the specified attributes.
8895 * @param {HTMLElement} insertBefore (optional) a child element of this element
8896 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8897 * @return {Roo.Element} The new child element
8899 createChild: function(config, insertBefore, returnDom){
8900 config = config || {tag:'div'};
8902 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8904 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
8908 * Appends this element to the passed element
8909 * @param {String/HTMLElement/Element} el The new parent element
8910 * @return {Roo.Element} this
8912 appendTo: function(el){
8913 el = Roo.getDom(el);
8914 el.appendChild(this.dom);
8919 * Inserts this element before the passed element in the DOM
8920 * @param {String/HTMLElement/Element} el The element to insert before
8921 * @return {Roo.Element} this
8923 insertBefore: function(el){
8924 el = Roo.getDom(el);
8925 el.parentNode.insertBefore(this.dom, el);
8930 * Inserts this element after the passed element in the DOM
8931 * @param {String/HTMLElement/Element} el The element to insert after
8932 * @return {Roo.Element} this
8934 insertAfter: function(el){
8935 el = Roo.getDom(el);
8936 el.parentNode.insertBefore(this.dom, el.nextSibling);
8941 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8942 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8943 * @return {Roo.Element} The new child
8945 insertFirst: function(el, returnDom){
8947 if(typeof el == 'object' && !el.nodeType){ // dh config
8948 return this.createChild(el, this.dom.firstChild, returnDom);
8950 el = Roo.getDom(el);
8951 this.dom.insertBefore(el, this.dom.firstChild);
8952 return !returnDom ? Roo.get(el) : el;
8957 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
8958 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8959 * @param {String} where (optional) 'before' or 'after' defaults to before
8960 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8961 * @return {Roo.Element} the inserted Element
8963 insertSibling: function(el, where, returnDom){
8964 where = where ? where.toLowerCase() : 'before';
8966 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
8968 if(typeof el == 'object' && !el.nodeType){ // dh config
8969 if(where == 'after' && !this.dom.nextSibling){
8970 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
8972 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
8976 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
8977 where == 'before' ? this.dom : this.dom.nextSibling);
8986 * Creates and wraps this element with another element
8987 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
8988 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8989 * @return {HTMLElement/Element} The newly created wrapper element
8991 wrap: function(config, returnDom){
8993 config = {tag: "div"};
8995 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
8996 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9001 * Replaces the passed element with this element
9002 * @param {String/HTMLElement/Element} el The element to replace
9003 * @return {Roo.Element} this
9005 replace: function(el){
9007 this.insertBefore(el);
9013 * Inserts an html fragment into this element
9014 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9015 * @param {String} html The HTML fragment
9016 * @param {Boolean} returnEl True to return an Roo.Element
9017 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9019 insertHtml : function(where, html, returnEl){
9020 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9021 return returnEl ? Roo.get(el) : el;
9025 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9026 * @param {Object} o The object with the attributes
9027 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9028 * @return {Roo.Element} this
9030 set : function(o, useSet){
9032 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9034 if(attr == "style" || typeof o[attr] == "function") continue;
9036 el.className = o["cls"];
9038 if(useSet) el.setAttribute(attr, o[attr]);
9039 else el[attr] = o[attr];
9043 Roo.DomHelper.applyStyles(el, o.style);
9049 * Convenience method for constructing a KeyMap
9050 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9051 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9052 * @param {Function} fn The function to call
9053 * @param {Object} scope (optional) The scope of the function
9054 * @return {Roo.KeyMap} The KeyMap created
9056 addKeyListener : function(key, fn, scope){
9058 if(typeof key != "object" || key instanceof Array){
9074 return new Roo.KeyMap(this, config);
9078 * Creates a KeyMap for this element
9079 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9080 * @return {Roo.KeyMap} The KeyMap created
9082 addKeyMap : function(config){
9083 return new Roo.KeyMap(this, config);
9087 * Returns true if this element is scrollable.
9090 isScrollable : function(){
9092 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9096 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9097 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9098 * @param {Number} value The new scroll value
9099 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9100 * @return {Element} this
9103 scrollTo : function(side, value, animate){
9104 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9106 this.dom[prop] = value;
9108 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9109 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9115 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9116 * within this element's scrollable range.
9117 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9118 * @param {Number} distance How far to scroll the element in pixels
9119 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9120 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9121 * was scrolled as far as it could go.
9123 scroll : function(direction, distance, animate){
9124 if(!this.isScrollable()){
9128 var l = el.scrollLeft, t = el.scrollTop;
9129 var w = el.scrollWidth, h = el.scrollHeight;
9130 var cw = el.clientWidth, ch = el.clientHeight;
9131 direction = direction.toLowerCase();
9132 var scrolled = false;
9133 var a = this.preanim(arguments, 2);
9138 var v = Math.min(l + distance, w-cw);
9139 this.scrollTo("left", v, a);
9146 var v = Math.max(l - distance, 0);
9147 this.scrollTo("left", v, a);
9155 var v = Math.max(t - distance, 0);
9156 this.scrollTo("top", v, a);
9164 var v = Math.min(t + distance, h-ch);
9165 this.scrollTo("top", v, a);
9174 * Translates the passed page coordinates into left/top css values for this element
9175 * @param {Number/Array} x The page x or an array containing [x, y]
9176 * @param {Number} y The page y
9177 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9179 translatePoints : function(x, y){
9180 if(typeof x == 'object' || x instanceof Array){
9183 var p = this.getStyle('position');
9184 var o = this.getXY();
9186 var l = parseInt(this.getStyle('left'), 10);
9187 var t = parseInt(this.getStyle('top'), 10);
9190 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9193 t = (p == "relative") ? 0 : this.dom.offsetTop;
9196 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9200 * Returns the current scroll position of the element.
9201 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9203 getScroll : function(){
9204 var d = this.dom, doc = document;
9205 if(d == doc || d == doc.body){
9206 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9207 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9208 return {left: l, top: t};
9210 return {left: d.scrollLeft, top: d.scrollTop};
9215 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9216 * are convert to standard 6 digit hex color.
9217 * @param {String} attr The css attribute
9218 * @param {String} defaultValue The default value to use when a valid color isn't found
9219 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9222 getColor : function(attr, defaultValue, prefix){
9223 var v = this.getStyle(attr);
9224 if(!v || v == "transparent" || v == "inherit") {
9225 return defaultValue;
9227 var color = typeof prefix == "undefined" ? "#" : prefix;
9228 if(v.substr(0, 4) == "rgb("){
9229 var rvs = v.slice(4, v.length -1).split(",");
9230 for(var i = 0; i < 3; i++){
9231 var h = parseInt(rvs[i]).toString(16);
9238 if(v.substr(0, 1) == "#"){
9240 for(var i = 1; i < 4; i++){
9241 var c = v.charAt(i);
9244 }else if(v.length == 7){
9245 color += v.substr(1);
9249 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9253 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9254 * gradient background, rounded corners and a 4-way shadow.
9255 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9256 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9257 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9258 * @return {Roo.Element} this
9260 boxWrap : function(cls){
9261 cls = cls || 'x-box';
9262 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9263 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9268 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9269 * @param {String} namespace The namespace in which to look for the attribute
9270 * @param {String} name The attribute name
9271 * @return {String} The attribute value
9273 getAttributeNS : Roo.isIE ? function(ns, name){
9275 var type = typeof d[ns+":"+name];
9276 if(type != 'undefined' && type != 'unknown'){
9277 return d[ns+":"+name];
9280 } : function(ns, name){
9282 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9286 var ep = El.prototype;
9289 * Appends an event handler (Shorthand for addListener)
9290 * @param {String} eventName The type of event to append
9291 * @param {Function} fn The method the event invokes
9292 * @param {Object} scope (optional) The scope (this object) of the fn
9293 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9296 ep.on = ep.addListener;
9298 ep.mon = ep.addListener;
9301 * Removes an event handler from this element (shorthand for removeListener)
9302 * @param {String} eventName the type of event to remove
9303 * @param {Function} fn the method the event invokes
9304 * @return {Roo.Element} this
9307 ep.un = ep.removeListener;
9310 * true to automatically adjust width and height settings for box-model issues (default to true)
9312 ep.autoBoxAdjust = true;
9315 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9318 El.addUnits = function(v, defaultUnit){
9319 if(v === "" || v == "auto"){
9322 if(v === undefined){
9325 if(typeof v == "number" || !El.unitPattern.test(v)){
9326 return v + (defaultUnit || 'px');
9331 // special markup used throughout Roo when box wrapping elements
9332 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9334 * Visibility mode constant - Use visibility to hide element
9340 * Visibility mode constant - Use display to hide element
9346 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9347 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9348 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9360 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9361 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9362 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9363 * @return {Element} The Element object
9366 El.get = function(el){
9368 if(!el){ return null; }
9369 if(typeof el == "string"){ // element id
9370 if(!(elm = document.getElementById(el))){
9373 if(ex = El.cache[el]){
9376 ex = El.cache[el] = new El(elm);
9379 }else if(el.tagName){ // dom element
9383 if(ex = El.cache[id]){
9386 ex = El.cache[id] = new El(el);
9389 }else if(el instanceof El){
9391 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9392 // catch case where it hasn't been appended
9393 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9396 }else if(el.isComposite){
9398 }else if(el instanceof Array){
9399 return El.select(el);
9400 }else if(el == document){
9401 // create a bogus element object representing the document object
9403 var f = function(){};
9404 f.prototype = El.prototype;
9406 docEl.dom = document;
9414 El.uncache = function(el){
9415 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9417 delete El.cache[a[i].id || a[i]];
9423 // Garbage collection - uncache elements/purge listeners on orphaned elements
9424 // so we don't hold a reference and cause the browser to retain them
9425 El.garbageCollect = function(){
9426 if(!Roo.enableGarbageCollector){
9427 clearInterval(El.collectorThread);
9430 for(var eid in El.cache){
9431 var el = El.cache[eid], d = el.dom;
9432 // -------------------------------------------------------
9433 // Determining what is garbage:
9434 // -------------------------------------------------------
9436 // dom node is null, definitely garbage
9437 // -------------------------------------------------------
9439 // no parentNode == direct orphan, definitely garbage
9440 // -------------------------------------------------------
9441 // !d.offsetParent && !document.getElementById(eid)
9442 // display none elements have no offsetParent so we will
9443 // also try to look it up by it's id. However, check
9444 // offsetParent first so we don't do unneeded lookups.
9445 // This enables collection of elements that are not orphans
9446 // directly, but somewhere up the line they have an orphan
9448 // -------------------------------------------------------
9449 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9450 delete El.cache[eid];
9451 if(d && Roo.enableListenerCollection){
9457 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9461 El.Flyweight = function(dom){
9464 El.Flyweight.prototype = El.prototype;
9466 El._flyweights = {};
9468 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9469 * the dom node can be overwritten by other code.
9470 * @param {String/HTMLElement} el The dom node or id
9471 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9472 * prevent conflicts (e.g. internally Roo uses "_internal")
9474 * @return {Element} The shared Element object
9476 El.fly = function(el, named){
9477 named = named || '_global';
9478 el = Roo.getDom(el);
9482 if(!El._flyweights[named]){
9483 El._flyweights[named] = new El.Flyweight();
9485 El._flyweights[named].dom = el;
9486 return El._flyweights[named];
9490 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9491 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9492 * Shorthand of {@link Roo.Element#get}
9493 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9494 * @return {Element} The Element object
9500 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9501 * the dom node can be overwritten by other code.
9502 * Shorthand of {@link Roo.Element#fly}
9503 * @param {String/HTMLElement} el The dom node or id
9504 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9505 * prevent conflicts (e.g. internally Roo uses "_internal")
9507 * @return {Element} The shared Element object
9513 // speedy lookup for elements never to box adjust
9514 var noBoxAdjust = Roo.isStrict ? {
9517 input:1, select:1, textarea:1
9519 if(Roo.isIE || Roo.isGecko){
9520 noBoxAdjust['button'] = 1;
9524 Roo.EventManager.on(window, 'unload', function(){
9526 delete El._flyweights;
9534 Roo.Element.selectorFunction = Roo.DomQuery.select;
9537 Roo.Element.select = function(selector, unique, root){
9539 if(typeof selector == "string"){
9540 els = Roo.Element.selectorFunction(selector, root);
9541 }else if(selector.length !== undefined){
9544 throw "Invalid selector";
9546 if(unique === true){
9547 return new Roo.CompositeElement(els);
9549 return new Roo.CompositeElementLite(els);
9553 * Selects elements based on the passed CSS selector to enable working on them as 1.
9554 * @param {String/Array} selector The CSS selector or an array of elements
9555 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9556 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9557 * @return {CompositeElementLite/CompositeElement}
9561 Roo.select = Roo.Element.select;
9578 * Ext JS Library 1.1.1
9579 * Copyright(c) 2006-2007, Ext JS, LLC.
9581 * Originally Released Under LGPL - original licence link has changed is not relivant.
9584 * <script type="text/javascript">
9589 //Notifies Element that fx methods are available
9590 Roo.enableFx = true;
9594 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9595 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9596 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9597 * Element effects to work.</p><br/>
9599 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9600 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9601 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9602 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9603 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9604 * expected results and should be done with care.</p><br/>
9606 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9607 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9610 ----- -----------------------------
9611 tl The top left corner
9612 t The center of the top edge
9613 tr The top right corner
9614 l The center of the left edge
9615 r The center of the right edge
9616 bl The bottom left corner
9617 b The center of the bottom edge
9618 br The bottom right corner
9620 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9621 * below are common options that can be passed to any Fx method.</b>
9622 * @cfg {Function} callback A function called when the effect is finished
9623 * @cfg {Object} scope The scope of the effect function
9624 * @cfg {String} easing A valid Easing value for the effect
9625 * @cfg {String} afterCls A css class to apply after the effect
9626 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9627 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9628 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9629 * effects that end with the element being visually hidden, ignored otherwise)
9630 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9631 * a function which returns such a specification that will be applied to the Element after the effect finishes
9632 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9633 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
9634 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9638 * Slides the element into view. An anchor point can be optionally passed to set the point of
9639 * origin for the slide effect. This function automatically handles wrapping the element with
9640 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9643 // default: slide the element in from the top
9646 // custom: slide the element in from the right with a 2-second duration
9647 el.slideIn('r', { duration: 2 });
9649 // common config options shown with default values
9655 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9656 * @param {Object} options (optional) Object literal with any of the Fx config options
9657 * @return {Roo.Element} The Element
9659 slideIn : function(anchor, o){
9660 var el = this.getFxEl();
9663 el.queueFx(o, function(){
9665 anchor = anchor || "t";
9667 // fix display to visibility
9670 // restore values after effect
9671 var r = this.getFxRestore();
9672 var b = this.getBox();
9673 // fixed size for slide
9677 var wrap = this.fxWrap(r.pos, o, "hidden");
9679 var st = this.dom.style;
9680 st.visibility = "visible";
9681 st.position = "absolute";
9683 // clear out temp styles after slide and unwrap
9684 var after = function(){
9685 el.fxUnwrap(wrap, r.pos, o);
9687 st.height = r.height;
9690 // time to calc the positions
9691 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9693 switch(anchor.toLowerCase()){
9695 wrap.setSize(b.width, 0);
9696 st.left = st.bottom = "0";
9700 wrap.setSize(0, b.height);
9701 st.right = st.top = "0";
9705 wrap.setSize(0, b.height);
9707 st.left = st.top = "0";
9708 a = {width: bw, points: pt};
9711 wrap.setSize(b.width, 0);
9712 wrap.setY(b.bottom);
9713 st.left = st.top = "0";
9714 a = {height: bh, points: pt};
9718 st.right = st.bottom = "0";
9719 a = {width: bw, height: bh};
9723 wrap.setY(b.y+b.height);
9724 st.right = st.top = "0";
9725 a = {width: bw, height: bh, points: pt};
9729 wrap.setXY([b.right, b.bottom]);
9730 st.left = st.top = "0";
9731 a = {width: bw, height: bh, points: pt};
9735 wrap.setX(b.x+b.width);
9736 st.left = st.bottom = "0";
9737 a = {width: bw, height: bh, points: pt};
9740 this.dom.style.visibility = "visible";
9743 arguments.callee.anim = wrap.fxanim(a,
9753 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9754 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9755 * 'hidden') but block elements will still take up space in the document. The element must be removed
9756 * from the DOM using the 'remove' config option if desired. This function automatically handles
9757 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9760 // default: slide the element out to the top
9763 // custom: slide the element out to the right with a 2-second duration
9764 el.slideOut('r', { duration: 2 });
9766 // common config options shown with default values
9774 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9775 * @param {Object} options (optional) Object literal with any of the Fx config options
9776 * @return {Roo.Element} The Element
9778 slideOut : function(anchor, o){
9779 var el = this.getFxEl();
9782 el.queueFx(o, function(){
9784 anchor = anchor || "t";
9786 // restore values after effect
9787 var r = this.getFxRestore();
9789 var b = this.getBox();
9790 // fixed size for slide
9794 var wrap = this.fxWrap(r.pos, o, "visible");
9796 var st = this.dom.style;
9797 st.visibility = "visible";
9798 st.position = "absolute";
9802 var after = function(){
9804 el.setDisplayed(false);
9809 el.fxUnwrap(wrap, r.pos, o);
9812 st.height = r.height;
9817 var a, zero = {to: 0};
9818 switch(anchor.toLowerCase()){
9820 st.left = st.bottom = "0";
9824 st.right = st.top = "0";
9828 st.left = st.top = "0";
9829 a = {width: zero, points: {to:[b.right, b.y]}};
9832 st.left = st.top = "0";
9833 a = {height: zero, points: {to:[b.x, b.bottom]}};
9836 st.right = st.bottom = "0";
9837 a = {width: zero, height: zero};
9840 st.right = st.top = "0";
9841 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9844 st.left = st.top = "0";
9845 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9848 st.left = st.bottom = "0";
9849 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9853 arguments.callee.anim = wrap.fxanim(a,
9863 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
9864 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
9865 * The element must be removed from the DOM using the 'remove' config option if desired.
9871 // common config options shown with default values
9879 * @param {Object} options (optional) Object literal with any of the Fx config options
9880 * @return {Roo.Element} The Element
9883 var el = this.getFxEl();
9886 el.queueFx(o, function(){
9887 this.clearOpacity();
9890 // restore values after effect
9891 var r = this.getFxRestore();
9892 var st = this.dom.style;
9894 var after = function(){
9896 el.setDisplayed(false);
9903 el.setPositioning(r.pos);
9905 st.height = r.height;
9910 var width = this.getWidth();
9911 var height = this.getHeight();
9913 arguments.callee.anim = this.fxanim({
9914 width : {to: this.adjustWidth(width * 2)},
9915 height : {to: this.adjustHeight(height * 2)},
9916 points : {by: [-(width * .5), -(height * .5)]},
9918 fontSize: {to:200, unit: "%"}
9929 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9930 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
9931 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9937 // all config options shown with default values
9945 * @param {Object} options (optional) Object literal with any of the Fx config options
9946 * @return {Roo.Element} The Element
9948 switchOff : function(o){
9949 var el = this.getFxEl();
9952 el.queueFx(o, function(){
9953 this.clearOpacity();
9956 // restore values after effect
9957 var r = this.getFxRestore();
9958 var st = this.dom.style;
9960 var after = function(){
9962 el.setDisplayed(false);
9968 el.setPositioning(r.pos);
9970 st.height = r.height;
9975 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
9976 this.clearOpacity();
9980 points:{by:[0, this.getHeight() * .5]}
9981 }, o, 'motion', 0.3, 'easeIn', after);
9982 }).defer(100, this);
9989 * Highlights the Element by setting a color (applies to the background-color by default, but can be
9990 * changed using the "attr" config option) and then fading back to the original color. If no original
9991 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
9994 // default: highlight background to yellow
9997 // custom: highlight foreground text to blue for 2 seconds
9998 el.highlight("0000ff", { attr: 'color', duration: 2 });
10000 // common config options shown with default values
10001 el.highlight("ffff9c", {
10002 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10003 endColor: (current color) or "ffffff",
10008 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10009 * @param {Object} options (optional) Object literal with any of the Fx config options
10010 * @return {Roo.Element} The Element
10012 highlight : function(color, o){
10013 var el = this.getFxEl();
10016 el.queueFx(o, function(){
10017 color = color || "ffff9c";
10018 attr = o.attr || "backgroundColor";
10020 this.clearOpacity();
10023 var origColor = this.getColor(attr);
10024 var restoreColor = this.dom.style[attr];
10025 endColor = (o.endColor || origColor) || "ffffff";
10027 var after = function(){
10028 el.dom.style[attr] = restoreColor;
10033 a[attr] = {from: color, to: endColor};
10034 arguments.callee.anim = this.fxanim(a,
10044 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10047 // default: a single light blue ripple
10050 // custom: 3 red ripples lasting 3 seconds total
10051 el.frame("ff0000", 3, { duration: 3 });
10053 // common config options shown with default values
10054 el.frame("C3DAF9", 1, {
10055 duration: 1 //duration of entire animation (not each individual ripple)
10056 // Note: Easing is not configurable and will be ignored if included
10059 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10060 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10061 * @param {Object} options (optional) Object literal with any of the Fx config options
10062 * @return {Roo.Element} The Element
10064 frame : function(color, count, o){
10065 var el = this.getFxEl();
10068 el.queueFx(o, function(){
10069 color = color || "#C3DAF9";
10070 if(color.length == 6){
10071 color = "#" + color;
10073 count = count || 1;
10074 duration = o.duration || 1;
10077 var b = this.getBox();
10078 var animFn = function(){
10079 var proxy = this.createProxy({
10082 visbility:"hidden",
10083 position:"absolute",
10084 "z-index":"35000", // yee haw
10085 border:"0px solid " + color
10088 var scale = Roo.isBorderBox ? 2 : 1;
10090 top:{from:b.y, to:b.y - 20},
10091 left:{from:b.x, to:b.x - 20},
10092 borderWidth:{from:0, to:10},
10093 opacity:{from:1, to:0},
10094 height:{from:b.height, to:(b.height + (20*scale))},
10095 width:{from:b.width, to:(b.width + (20*scale))}
10096 }, duration, function(){
10100 animFn.defer((duration/2)*1000, this);
10111 * Creates a pause before any subsequent queued effects begin. If there are
10112 * no effects queued after the pause it will have no effect.
10117 * @param {Number} seconds The length of time to pause (in seconds)
10118 * @return {Roo.Element} The Element
10120 pause : function(seconds){
10121 var el = this.getFxEl();
10124 el.queueFx(o, function(){
10125 setTimeout(function(){
10127 }, seconds * 1000);
10133 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10134 * using the "endOpacity" config option.
10137 // default: fade in from opacity 0 to 100%
10140 // custom: fade in from opacity 0 to 75% over 2 seconds
10141 el.fadeIn({ endOpacity: .75, duration: 2});
10143 // common config options shown with default values
10145 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10150 * @param {Object} options (optional) Object literal with any of the Fx config options
10151 * @return {Roo.Element} The Element
10153 fadeIn : function(o){
10154 var el = this.getFxEl();
10156 el.queueFx(o, function(){
10157 this.setOpacity(0);
10159 this.dom.style.visibility = 'visible';
10160 var to = o.endOpacity || 1;
10161 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10162 o, null, .5, "easeOut", function(){
10164 this.clearOpacity();
10173 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10174 * using the "endOpacity" config option.
10177 // default: fade out from the element's current opacity to 0
10180 // custom: fade out from the element's current opacity to 25% over 2 seconds
10181 el.fadeOut({ endOpacity: .25, duration: 2});
10183 // common config options shown with default values
10185 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10192 * @param {Object} options (optional) Object literal with any of the Fx config options
10193 * @return {Roo.Element} The Element
10195 fadeOut : function(o){
10196 var el = this.getFxEl();
10198 el.queueFx(o, function(){
10199 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10200 o, null, .5, "easeOut", function(){
10201 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10202 this.dom.style.display = "none";
10204 this.dom.style.visibility = "hidden";
10206 this.clearOpacity();
10214 * Animates the transition of an element's dimensions from a starting height/width
10215 * to an ending height/width.
10218 // change height and width to 100x100 pixels
10219 el.scale(100, 100);
10221 // common config options shown with default values. The height and width will default to
10222 // the element's existing values if passed as null.
10225 [element's height], {
10230 * @param {Number} width The new width (pass undefined to keep the original width)
10231 * @param {Number} height The new height (pass undefined to keep the original height)
10232 * @param {Object} options (optional) Object literal with any of the Fx config options
10233 * @return {Roo.Element} The Element
10235 scale : function(w, h, o){
10236 this.shift(Roo.apply({}, o, {
10244 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10245 * Any of these properties not specified in the config object will not be changed. This effect
10246 * requires that at least one new dimension, position or opacity setting must be passed in on
10247 * the config object in order for the function to have any effect.
10250 // slide the element horizontally to x position 200 while changing the height and opacity
10251 el.shift({ x: 200, height: 50, opacity: .8 });
10253 // common config options shown with default values.
10255 width: [element's width],
10256 height: [element's height],
10257 x: [element's x position],
10258 y: [element's y position],
10259 opacity: [element's opacity],
10264 * @param {Object} options Object literal with any of the Fx config options
10265 * @return {Roo.Element} The Element
10267 shift : function(o){
10268 var el = this.getFxEl();
10270 el.queueFx(o, function(){
10271 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10272 if(w !== undefined){
10273 a.width = {to: this.adjustWidth(w)};
10275 if(h !== undefined){
10276 a.height = {to: this.adjustHeight(h)};
10278 if(x !== undefined || y !== undefined){
10280 x !== undefined ? x : this.getX(),
10281 y !== undefined ? y : this.getY()
10284 if(op !== undefined){
10285 a.opacity = {to: op};
10287 if(o.xy !== undefined){
10288 a.points = {to: o.xy};
10290 arguments.callee.anim = this.fxanim(a,
10291 o, 'motion', .35, "easeOut", function(){
10299 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10300 * ending point of the effect.
10303 // default: slide the element downward while fading out
10306 // custom: slide the element out to the right with a 2-second duration
10307 el.ghost('r', { duration: 2 });
10309 // common config options shown with default values
10317 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10318 * @param {Object} options (optional) Object literal with any of the Fx config options
10319 * @return {Roo.Element} The Element
10321 ghost : function(anchor, o){
10322 var el = this.getFxEl();
10325 el.queueFx(o, function(){
10326 anchor = anchor || "b";
10328 // restore values after effect
10329 var r = this.getFxRestore();
10330 var w = this.getWidth(),
10331 h = this.getHeight();
10333 var st = this.dom.style;
10335 var after = function(){
10337 el.setDisplayed(false);
10343 el.setPositioning(r.pos);
10344 st.width = r.width;
10345 st.height = r.height;
10350 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10351 switch(anchor.toLowerCase()){
10378 arguments.callee.anim = this.fxanim(a,
10388 * Ensures that all effects queued after syncFx is called on the element are
10389 * run concurrently. This is the opposite of {@link #sequenceFx}.
10390 * @return {Roo.Element} The Element
10392 syncFx : function(){
10393 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10402 * Ensures that all effects queued after sequenceFx is called on the element are
10403 * run in sequence. This is the opposite of {@link #syncFx}.
10404 * @return {Roo.Element} The Element
10406 sequenceFx : function(){
10407 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10409 concurrent : false,
10416 nextFx : function(){
10417 var ef = this.fxQueue[0];
10424 * Returns true if the element has any effects actively running or queued, else returns false.
10425 * @return {Boolean} True if element has active effects, else false
10427 hasActiveFx : function(){
10428 return this.fxQueue && this.fxQueue[0];
10432 * Stops any running effects and clears the element's internal effects queue if it contains
10433 * any additional effects that haven't started yet.
10434 * @return {Roo.Element} The Element
10436 stopFx : function(){
10437 if(this.hasActiveFx()){
10438 var cur = this.fxQueue[0];
10439 if(cur && cur.anim && cur.anim.isAnimated()){
10440 this.fxQueue = [cur]; // clear out others
10441 cur.anim.stop(true);
10448 beforeFx : function(o){
10449 if(this.hasActiveFx() && !o.concurrent){
10460 * Returns true if the element is currently blocking so that no other effect can be queued
10461 * until this effect is finished, else returns false if blocking is not set. This is commonly
10462 * used to ensure that an effect initiated by a user action runs to completion prior to the
10463 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10464 * @return {Boolean} True if blocking, else false
10466 hasFxBlock : function(){
10467 var q = this.fxQueue;
10468 return q && q[0] && q[0].block;
10472 queueFx : function(o, fn){
10476 if(!this.hasFxBlock()){
10477 Roo.applyIf(o, this.fxDefaults);
10479 var run = this.beforeFx(o);
10480 fn.block = o.block;
10481 this.fxQueue.push(fn);
10493 fxWrap : function(pos, o, vis){
10495 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10498 wrapXY = this.getXY();
10500 var div = document.createElement("div");
10501 div.style.visibility = vis;
10502 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10503 wrap.setPositioning(pos);
10504 if(wrap.getStyle("position") == "static"){
10505 wrap.position("relative");
10507 this.clearPositioning('auto');
10509 wrap.dom.appendChild(this.dom);
10511 wrap.setXY(wrapXY);
10518 fxUnwrap : function(wrap, pos, o){
10519 this.clearPositioning();
10520 this.setPositioning(pos);
10522 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10528 getFxRestore : function(){
10529 var st = this.dom.style;
10530 return {pos: this.getPositioning(), width: st.width, height : st.height};
10534 afterFx : function(o){
10536 this.applyStyles(o.afterStyle);
10539 this.addClass(o.afterCls);
10541 if(o.remove === true){
10544 Roo.callback(o.callback, o.scope, [this]);
10546 this.fxQueue.shift();
10552 getFxEl : function(){ // support for composite element fx
10553 return Roo.get(this.dom);
10557 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10558 animType = animType || 'run';
10560 var anim = Roo.lib.Anim[animType](
10562 (opt.duration || defaultDur) || .35,
10563 (opt.easing || defaultEase) || 'easeOut',
10565 Roo.callback(cb, this);
10574 // backwords compat
10575 Roo.Fx.resize = Roo.Fx.scale;
10577 //When included, Roo.Fx is automatically applied to Element so that all basic
10578 //effects are available directly via the Element API
10579 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10581 * Ext JS Library 1.1.1
10582 * Copyright(c) 2006-2007, Ext JS, LLC.
10584 * Originally Released Under LGPL - original licence link has changed is not relivant.
10587 * <script type="text/javascript">
10592 * @class Roo.CompositeElement
10593 * Standard composite class. Creates a Roo.Element for every element in the collection.
10595 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10596 * actions will be performed on all the elements in this collection.</b>
10598 * All methods return <i>this</i> and can be chained.
10600 var els = Roo.select("#some-el div.some-class", true);
10601 // or select directly from an existing element
10602 var el = Roo.get('some-el');
10603 el.select('div.some-class', true);
10605 els.setWidth(100); // all elements become 100 width
10606 els.hide(true); // all elements fade out and hide
10608 els.setWidth(100).hide(true);
10611 Roo.CompositeElement = function(els){
10612 this.elements = [];
10613 this.addElements(els);
10615 Roo.CompositeElement.prototype = {
10617 addElements : function(els){
10618 if(!els) return this;
10619 if(typeof els == "string"){
10620 els = Roo.Element.selectorFunction(els);
10622 var yels = this.elements;
10623 var index = yels.length-1;
10624 for(var i = 0, len = els.length; i < len; i++) {
10625 yels[++index] = Roo.get(els[i]);
10631 * Clears this composite and adds the elements returned by the passed selector.
10632 * @param {String/Array} els A string CSS selector, an array of elements or an element
10633 * @return {CompositeElement} this
10635 fill : function(els){
10636 this.elements = [];
10642 * Filters this composite to only elements that match the passed selector.
10643 * @param {String} selector A string CSS selector
10644 * @return {CompositeElement} this
10646 filter : function(selector){
10648 this.each(function(el){
10649 if(el.is(selector)){
10650 els[els.length] = el.dom;
10657 invoke : function(fn, args){
10658 var els = this.elements;
10659 for(var i = 0, len = els.length; i < len; i++) {
10660 Roo.Element.prototype[fn].apply(els[i], args);
10665 * Adds elements to this composite.
10666 * @param {String/Array} els A string CSS selector, an array of elements or an element
10667 * @return {CompositeElement} this
10669 add : function(els){
10670 if(typeof els == "string"){
10671 this.addElements(Roo.Element.selectorFunction(els));
10672 }else if(els.length !== undefined){
10673 this.addElements(els);
10675 this.addElements([els]);
10680 * Calls the passed function passing (el, this, index) for each element in this composite.
10681 * @param {Function} fn The function to call
10682 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10683 * @return {CompositeElement} this
10685 each : function(fn, scope){
10686 var els = this.elements;
10687 for(var i = 0, len = els.length; i < len; i++){
10688 if(fn.call(scope || els[i], els[i], this, i) === false) {
10696 * Returns the Element object at the specified index
10697 * @param {Number} index
10698 * @return {Roo.Element}
10700 item : function(index){
10701 return this.elements[index] || null;
10705 * Returns the first Element
10706 * @return {Roo.Element}
10708 first : function(){
10709 return this.item(0);
10713 * Returns the last Element
10714 * @return {Roo.Element}
10717 return this.item(this.elements.length-1);
10721 * Returns the number of elements in this composite
10724 getCount : function(){
10725 return this.elements.length;
10729 * Returns true if this composite contains the passed element
10732 contains : function(el){
10733 return this.indexOf(el) !== -1;
10737 * Returns true if this composite contains the passed element
10740 indexOf : function(el){
10741 return this.elements.indexOf(Roo.get(el));
10746 * Removes the specified element(s).
10747 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10748 * or an array of any of those.
10749 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10750 * @return {CompositeElement} this
10752 removeElement : function(el, removeDom){
10753 if(el instanceof Array){
10754 for(var i = 0, len = el.length; i < len; i++){
10755 this.removeElement(el[i]);
10759 var index = typeof el == 'number' ? el : this.indexOf(el);
10762 var d = this.elements[index];
10766 d.parentNode.removeChild(d);
10769 this.elements.splice(index, 1);
10775 * Replaces the specified element with the passed element.
10776 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10778 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10779 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10780 * @return {CompositeElement} this
10782 replaceElement : function(el, replacement, domReplace){
10783 var index = typeof el == 'number' ? el : this.indexOf(el);
10786 this.elements[index].replaceWith(replacement);
10788 this.elements.splice(index, 1, Roo.get(replacement))
10795 * Removes all elements.
10797 clear : function(){
10798 this.elements = [];
10802 Roo.CompositeElement.createCall = function(proto, fnName){
10803 if(!proto[fnName]){
10804 proto[fnName] = function(){
10805 return this.invoke(fnName, arguments);
10809 for(var fnName in Roo.Element.prototype){
10810 if(typeof Roo.Element.prototype[fnName] == "function"){
10811 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10817 * Ext JS Library 1.1.1
10818 * Copyright(c) 2006-2007, Ext JS, LLC.
10820 * Originally Released Under LGPL - original licence link has changed is not relivant.
10823 * <script type="text/javascript">
10827 * @class Roo.CompositeElementLite
10828 * @extends Roo.CompositeElement
10829 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10831 var els = Roo.select("#some-el div.some-class");
10832 // or select directly from an existing element
10833 var el = Roo.get('some-el');
10834 el.select('div.some-class');
10836 els.setWidth(100); // all elements become 100 width
10837 els.hide(true); // all elements fade out and hide
10839 els.setWidth(100).hide(true);
10840 </code></pre><br><br>
10841 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10842 * actions will be performed on all the elements in this collection.</b>
10844 Roo.CompositeElementLite = function(els){
10845 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10846 this.el = new Roo.Element.Flyweight();
10848 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10849 addElements : function(els){
10851 if(els instanceof Array){
10852 this.elements = this.elements.concat(els);
10854 var yels = this.elements;
10855 var index = yels.length-1;
10856 for(var i = 0, len = els.length; i < len; i++) {
10857 yels[++index] = els[i];
10863 invoke : function(fn, args){
10864 var els = this.elements;
10866 for(var i = 0, len = els.length; i < len; i++) {
10868 Roo.Element.prototype[fn].apply(el, args);
10873 * Returns a flyweight Element of the dom element object at the specified index
10874 * @param {Number} index
10875 * @return {Roo.Element}
10877 item : function(index){
10878 if(!this.elements[index]){
10881 this.el.dom = this.elements[index];
10885 // fixes scope with flyweight
10886 addListener : function(eventName, handler, scope, opt){
10887 var els = this.elements;
10888 for(var i = 0, len = els.length; i < len; i++) {
10889 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10895 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10896 * passed is the flyweight (shared) Roo.Element instance, so if you require a
10897 * a reference to the dom node, use el.dom.</b>
10898 * @param {Function} fn The function to call
10899 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10900 * @return {CompositeElement} this
10902 each : function(fn, scope){
10903 var els = this.elements;
10905 for(var i = 0, len = els.length; i < len; i++){
10907 if(fn.call(scope || el, el, this, i) === false){
10914 indexOf : function(el){
10915 return this.elements.indexOf(Roo.getDom(el));
10918 replaceElement : function(el, replacement, domReplace){
10919 var index = typeof el == 'number' ? el : this.indexOf(el);
10921 replacement = Roo.getDom(replacement);
10923 var d = this.elements[index];
10924 d.parentNode.insertBefore(replacement, d);
10925 d.parentNode.removeChild(d);
10927 this.elements.splice(index, 1, replacement);
10932 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10936 * Ext JS Library 1.1.1
10937 * Copyright(c) 2006-2007, Ext JS, LLC.
10939 * Originally Released Under LGPL - original licence link has changed is not relivant.
10942 * <script type="text/javascript">
10948 * @class Roo.data.Connection
10949 * @extends Roo.util.Observable
10950 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
10951 * either to a configured URL, or to a URL specified at request time.<br><br>
10953 * Requests made by this class are asynchronous, and will return immediately. No data from
10954 * the server will be available to the statement immediately following the {@link #request} call.
10955 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
10957 * Note: If you are doing a file upload, you will not get a normal response object sent back to
10958 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
10959 * The response object is created using the innerHTML of the IFRAME's document as the responseText
10960 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
10961 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
10962 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
10963 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
10964 * standard DOM methods.
10966 * @param {Object} config a configuration object.
10968 Roo.data.Connection = function(config){
10969 Roo.apply(this, config);
10972 * @event beforerequest
10973 * Fires before a network request is made to retrieve a data object.
10974 * @param {Connection} conn This Connection object.
10975 * @param {Object} options The options config object passed to the {@link #request} method.
10977 "beforerequest" : true,
10979 * @event requestcomplete
10980 * Fires if the request was successfully completed.
10981 * @param {Connection} conn This Connection object.
10982 * @param {Object} response The XHR object containing the response data.
10983 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
10984 * @param {Object} options The options config object passed to the {@link #request} method.
10986 "requestcomplete" : true,
10988 * @event requestexception
10989 * Fires if an error HTTP status was returned from the server.
10990 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
10991 * @param {Connection} conn This Connection object.
10992 * @param {Object} response The XHR object containing the response data.
10993 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
10994 * @param {Object} options The options config object passed to the {@link #request} method.
10996 "requestexception" : true
10998 Roo.data.Connection.superclass.constructor.call(this);
11001 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11003 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11006 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11007 * extra parameters to each request made by this object. (defaults to undefined)
11010 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11011 * to each request made by this object. (defaults to undefined)
11014 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11017 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11021 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11027 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11030 disableCaching: true,
11033 * Sends an HTTP request to a remote server.
11034 * @param {Object} options An object which may contain the following properties:<ul>
11035 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11036 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11037 * request, a url encoded string or a function to call to get either.</li>
11038 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11039 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11040 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11041 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11042 * <li>options {Object} The parameter to the request call.</li>
11043 * <li>success {Boolean} True if the request succeeded.</li>
11044 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11046 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11047 * The callback is passed the following parameters:<ul>
11048 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11049 * <li>options {Object} The parameter to the request call.</li>
11051 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11052 * The callback is passed the following parameters:<ul>
11053 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11054 * <li>options {Object} The parameter to the request call.</li>
11056 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11057 * for the callback function. Defaults to the browser window.</li>
11058 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11059 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11060 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11061 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11062 * params for the post data. Any params will be appended to the URL.</li>
11063 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11065 * @return {Number} transactionId
11067 request : function(o){
11068 if(this.fireEvent("beforerequest", this, o) !== false){
11071 if(typeof p == "function"){
11072 p = p.call(o.scope||window, o);
11074 if(typeof p == "object"){
11075 p = Roo.urlEncode(o.params);
11077 if(this.extraParams){
11078 var extras = Roo.urlEncode(this.extraParams);
11079 p = p ? (p + '&' + extras) : extras;
11082 var url = o.url || this.url;
11083 if(typeof url == 'function'){
11084 url = url.call(o.scope||window, o);
11088 var form = Roo.getDom(o.form);
11089 url = url || form.action;
11091 var enctype = form.getAttribute("enctype");
11092 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11093 return this.doFormUpload(o, p, url);
11095 var f = Roo.lib.Ajax.serializeForm(form);
11096 p = p ? (p + '&' + f) : f;
11099 var hs = o.headers;
11100 if(this.defaultHeaders){
11101 hs = Roo.apply(hs || {}, this.defaultHeaders);
11108 success: this.handleResponse,
11109 failure: this.handleFailure,
11111 argument: {options: o},
11112 timeout : this.timeout
11115 var method = o.method||this.method||(p ? "POST" : "GET");
11117 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11118 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11121 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11125 }else if(this.autoAbort !== false){
11129 if((method == 'GET' && p) || o.xmlData){
11130 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11133 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11134 return this.transId;
11136 Roo.callback(o.callback, o.scope, [o, null, null]);
11142 * Determine whether this object has a request outstanding.
11143 * @param {Number} transactionId (Optional) defaults to the last transaction
11144 * @return {Boolean} True if there is an outstanding request.
11146 isLoading : function(transId){
11148 return Roo.lib.Ajax.isCallInProgress(transId);
11150 return this.transId ? true : false;
11155 * Aborts any outstanding request.
11156 * @param {Number} transactionId (Optional) defaults to the last transaction
11158 abort : function(transId){
11159 if(transId || this.isLoading()){
11160 Roo.lib.Ajax.abort(transId || this.transId);
11165 handleResponse : function(response){
11166 this.transId = false;
11167 var options = response.argument.options;
11168 response.argument = options ? options.argument : null;
11169 this.fireEvent("requestcomplete", this, response, options);
11170 Roo.callback(options.success, options.scope, [response, options]);
11171 Roo.callback(options.callback, options.scope, [options, true, response]);
11175 handleFailure : function(response, e){
11176 this.transId = false;
11177 var options = response.argument.options;
11178 response.argument = options ? options.argument : null;
11179 this.fireEvent("requestexception", this, response, options, e);
11180 Roo.callback(options.failure, options.scope, [response, options]);
11181 Roo.callback(options.callback, options.scope, [options, false, response]);
11185 doFormUpload : function(o, ps, url){
11187 var frame = document.createElement('iframe');
11190 frame.className = 'x-hidden';
11192 frame.src = Roo.SSL_SECURE_URL;
11194 document.body.appendChild(frame);
11197 document.frames[id].name = id;
11200 var form = Roo.getDom(o.form);
11202 form.method = 'POST';
11203 form.enctype = form.encoding = 'multipart/form-data';
11209 if(ps){ // add dynamic params
11211 ps = Roo.urlDecode(ps, false);
11213 if(ps.hasOwnProperty(k)){
11214 hd = document.createElement('input');
11215 hd.type = 'hidden';
11218 form.appendChild(hd);
11225 var r = { // bogus response object
11230 r.argument = o ? o.argument : null;
11235 doc = frame.contentWindow.document;
11237 doc = (frame.contentDocument || window.frames[id].document);
11239 if(doc && doc.body){
11240 r.responseText = doc.body.innerHTML;
11242 if(doc && doc.XMLDocument){
11243 r.responseXML = doc.XMLDocument;
11245 r.responseXML = doc;
11252 Roo.EventManager.removeListener(frame, 'load', cb, this);
11254 this.fireEvent("requestcomplete", this, r, o);
11255 Roo.callback(o.success, o.scope, [r, o]);
11256 Roo.callback(o.callback, o.scope, [o, true, r]);
11258 setTimeout(function(){document.body.removeChild(frame);}, 100);
11261 Roo.EventManager.on(frame, 'load', cb, this);
11264 if(hiddens){ // remove dynamic params
11265 for(var i = 0, len = hiddens.length; i < len; i++){
11266 form.removeChild(hiddens[i]);
11274 * @extends Roo.data.Connection
11275 * Global Ajax request class.
11279 Roo.Ajax = new Roo.data.Connection({
11282 * @cfg {String} url @hide
11285 * @cfg {Object} extraParams @hide
11288 * @cfg {Object} defaultHeaders @hide
11291 * @cfg {String} method (Optional) @hide
11294 * @cfg {Number} timeout (Optional) @hide
11297 * @cfg {Boolean} autoAbort (Optional) @hide
11301 * @cfg {Boolean} disableCaching (Optional) @hide
11305 * @property disableCaching
11306 * True to add a unique cache-buster param to GET requests. (defaults to true)
11311 * The default URL to be used for requests to the server. (defaults to undefined)
11315 * @property extraParams
11316 * An object containing properties which are used as
11317 * extra parameters to each request made by this object. (defaults to undefined)
11321 * @property defaultHeaders
11322 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11327 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11331 * @property timeout
11332 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11337 * @property autoAbort
11338 * Whether a new request should abort any pending requests. (defaults to false)
11344 * Serialize the passed form into a url encoded string
11345 * @param {String/HTMLElement} form
11348 serializeForm : function(form){
11349 return Roo.lib.Ajax.serializeForm(form);
11353 * Ext JS Library 1.1.1
11354 * Copyright(c) 2006-2007, Ext JS, LLC.
11356 * Originally Released Under LGPL - original licence link has changed is not relivant.
11359 * <script type="text/javascript">
11364 * @extends Roo.data.Connection
11365 * Global Ajax request class.
11367 * @instanceOf Roo.data.Connection
11369 Roo.Ajax = new Roo.data.Connection({
11378 * @cfg {String} url @hide
11381 * @cfg {Object} extraParams @hide
11384 * @cfg {Object} defaultHeaders @hide
11387 * @cfg {String} method (Optional) @hide
11390 * @cfg {Number} timeout (Optional) @hide
11393 * @cfg {Boolean} autoAbort (Optional) @hide
11397 * @cfg {Boolean} disableCaching (Optional) @hide
11401 * @property disableCaching
11402 * True to add a unique cache-buster param to GET requests. (defaults to true)
11407 * The default URL to be used for requests to the server. (defaults to undefined)
11411 * @property extraParams
11412 * An object containing properties which are used as
11413 * extra parameters to each request made by this object. (defaults to undefined)
11417 * @property defaultHeaders
11418 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11423 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11427 * @property timeout
11428 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11433 * @property autoAbort
11434 * Whether a new request should abort any pending requests. (defaults to false)
11440 * Serialize the passed form into a url encoded string
11441 * @param {String/HTMLElement} form
11444 serializeForm : function(form){
11445 return Roo.lib.Ajax.serializeForm(form);
11449 * Ext JS Library 1.1.1
11450 * Copyright(c) 2006-2007, Ext JS, LLC.
11452 * Originally Released Under LGPL - original licence link has changed is not relivant.
11455 * <script type="text/javascript">
11460 * @class Roo.UpdateManager
11461 * @extends Roo.util.Observable
11462 * Provides AJAX-style update for Element object.<br><br>
11465 * // Get it from a Roo.Element object
11466 * var el = Roo.get("foo");
11467 * var mgr = el.getUpdateManager();
11468 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11470 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11472 * // or directly (returns the same UpdateManager instance)
11473 * var mgr = new Roo.UpdateManager("myElementId");
11474 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11475 * mgr.on("update", myFcnNeedsToKnow);
11477 // short handed call directly from the element object
11478 Roo.get("foo").load({
11482 text: "Loading Foo..."
11486 * Create new UpdateManager directly.
11487 * @param {String/HTMLElement/Roo.Element} el The element to update
11488 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11490 Roo.UpdateManager = function(el, forceNew){
11492 if(!forceNew && el.updateManager){
11493 return el.updateManager;
11496 * The Element object
11497 * @type Roo.Element
11501 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11504 this.defaultUrl = null;
11508 * @event beforeupdate
11509 * Fired before an update is made, return false from your handler and the update is cancelled.
11510 * @param {Roo.Element} el
11511 * @param {String/Object/Function} url
11512 * @param {String/Object} params
11514 "beforeupdate": true,
11517 * Fired after successful update is made.
11518 * @param {Roo.Element} el
11519 * @param {Object} oResponseObject The response Object
11524 * Fired on update failure.
11525 * @param {Roo.Element} el
11526 * @param {Object} oResponseObject The response Object
11530 var d = Roo.UpdateManager.defaults;
11532 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11535 this.sslBlankUrl = d.sslBlankUrl;
11537 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11540 this.disableCaching = d.disableCaching;
11542 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11545 this.indicatorText = d.indicatorText;
11547 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11550 this.showLoadIndicator = d.showLoadIndicator;
11552 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11555 this.timeout = d.timeout;
11558 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11561 this.loadScripts = d.loadScripts;
11564 * Transaction object of current executing transaction
11566 this.transaction = null;
11571 this.autoRefreshProcId = null;
11573 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11576 this.refreshDelegate = this.refresh.createDelegate(this);
11578 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11581 this.updateDelegate = this.update.createDelegate(this);
11583 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11586 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11590 this.successDelegate = this.processSuccess.createDelegate(this);
11594 this.failureDelegate = this.processFailure.createDelegate(this);
11596 if(!this.renderer){
11598 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11600 this.renderer = new Roo.UpdateManager.BasicRenderer();
11603 Roo.UpdateManager.superclass.constructor.call(this);
11606 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11608 * Get the Element this UpdateManager is bound to
11609 * @return {Roo.Element} The element
11611 getEl : function(){
11615 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11616 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11619 url: "your-url.php",<br/>
11620 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11621 callback: yourFunction,<br/>
11622 scope: yourObject, //(optional scope) <br/>
11623 discardUrl: false, <br/>
11624 nocache: false,<br/>
11625 text: "Loading...",<br/>
11627 scripts: false<br/>
11630 * The only required property is url. The optional properties nocache, text and scripts
11631 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11632 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11633 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11634 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11636 update : function(url, params, callback, discardUrl){
11637 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11638 var method = this.method, cfg;
11639 if(typeof url == "object"){ // must be config object
11642 params = params || cfg.params;
11643 callback = callback || cfg.callback;
11644 discardUrl = discardUrl || cfg.discardUrl;
11645 if(callback && cfg.scope){
11646 callback = callback.createDelegate(cfg.scope);
11648 if(typeof cfg.method != "undefined"){method = cfg.method;};
11649 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11650 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11651 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11652 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11654 this.showLoading();
11656 this.defaultUrl = url;
11658 if(typeof url == "function"){
11659 url = url.call(this);
11662 method = method || (params ? "POST" : "GET");
11663 if(method == "GET"){
11664 url = this.prepareUrl(url);
11667 var o = Roo.apply(cfg ||{}, {
11670 success: this.successDelegate,
11671 failure: this.failureDelegate,
11672 callback: undefined,
11673 timeout: (this.timeout*1000),
11674 argument: {"url": url, "form": null, "callback": callback, "params": params}
11677 this.transaction = Roo.Ajax.request(o);
11682 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11683 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11684 * @param {String/HTMLElement} form The form Id or form element
11685 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11686 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11687 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11689 formUpdate : function(form, url, reset, callback){
11690 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11691 if(typeof url == "function"){
11692 url = url.call(this);
11694 form = Roo.getDom(form);
11695 this.transaction = Roo.Ajax.request({
11698 success: this.successDelegate,
11699 failure: this.failureDelegate,
11700 timeout: (this.timeout*1000),
11701 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11703 this.showLoading.defer(1, this);
11708 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11709 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11711 refresh : function(callback){
11712 if(this.defaultUrl == null){
11715 this.update(this.defaultUrl, null, callback, true);
11719 * Set this element to auto refresh.
11720 * @param {Number} interval How often to update (in seconds).
11721 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11722 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11723 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11724 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11726 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11728 this.update(url || this.defaultUrl, params, callback, true);
11730 if(this.autoRefreshProcId){
11731 clearInterval(this.autoRefreshProcId);
11733 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11737 * Stop auto refresh on this element.
11739 stopAutoRefresh : function(){
11740 if(this.autoRefreshProcId){
11741 clearInterval(this.autoRefreshProcId);
11742 delete this.autoRefreshProcId;
11746 isAutoRefreshing : function(){
11747 return this.autoRefreshProcId ? true : false;
11750 * Called to update the element to "Loading" state. Override to perform custom action.
11752 showLoading : function(){
11753 if(this.showLoadIndicator){
11754 this.el.update(this.indicatorText);
11759 * Adds unique parameter to query string if disableCaching = true
11762 prepareUrl : function(url){
11763 if(this.disableCaching){
11764 var append = "_dc=" + (new Date().getTime());
11765 if(url.indexOf("?") !== -1){
11766 url += "&" + append;
11768 url += "?" + append;
11777 processSuccess : function(response){
11778 this.transaction = null;
11779 if(response.argument.form && response.argument.reset){
11780 try{ // put in try/catch since some older FF releases had problems with this
11781 response.argument.form.reset();
11784 if(this.loadScripts){
11785 this.renderer.render(this.el, response, this,
11786 this.updateComplete.createDelegate(this, [response]));
11788 this.renderer.render(this.el, response, this);
11789 this.updateComplete(response);
11793 updateComplete : function(response){
11794 this.fireEvent("update", this.el, response);
11795 if(typeof response.argument.callback == "function"){
11796 response.argument.callback(this.el, true, response);
11803 processFailure : function(response){
11804 this.transaction = null;
11805 this.fireEvent("failure", this.el, response);
11806 if(typeof response.argument.callback == "function"){
11807 response.argument.callback(this.el, false, response);
11812 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11813 * @param {Object} renderer The object implementing the render() method
11815 setRenderer : function(renderer){
11816 this.renderer = renderer;
11819 getRenderer : function(){
11820 return this.renderer;
11824 * Set the defaultUrl used for updates
11825 * @param {String/Function} defaultUrl The url or a function to call to get the url
11827 setDefaultUrl : function(defaultUrl){
11828 this.defaultUrl = defaultUrl;
11832 * Aborts the executing transaction
11834 abort : function(){
11835 if(this.transaction){
11836 Roo.Ajax.abort(this.transaction);
11841 * Returns true if an update is in progress
11842 * @return {Boolean}
11844 isUpdating : function(){
11845 if(this.transaction){
11846 return Roo.Ajax.isLoading(this.transaction);
11853 * @class Roo.UpdateManager.defaults
11854 * @static (not really - but it helps the doc tool)
11855 * The defaults collection enables customizing the default properties of UpdateManager
11857 Roo.UpdateManager.defaults = {
11859 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11865 * True to process scripts by default (Defaults to false).
11868 loadScripts : false,
11871 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11874 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11876 * Whether to append unique parameter on get request to disable caching (Defaults to false).
11879 disableCaching : false,
11881 * Whether to show indicatorText when loading (Defaults to true).
11884 showLoadIndicator : true,
11886 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
11889 indicatorText : '<div class="loading-indicator">Loading...</div>'
11893 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11895 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11896 * @param {String/HTMLElement/Roo.Element} el The element to update
11897 * @param {String} url The url
11898 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11899 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11902 * @member Roo.UpdateManager
11904 Roo.UpdateManager.updateElement = function(el, url, params, options){
11905 var um = Roo.get(el, true).getUpdateManager();
11906 Roo.apply(um, options);
11907 um.update(url, params, options ? options.callback : null);
11909 // alias for backwards compat
11910 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11912 * @class Roo.UpdateManager.BasicRenderer
11913 * Default Content renderer. Updates the elements innerHTML with the responseText.
11915 Roo.UpdateManager.BasicRenderer = function(){};
11917 Roo.UpdateManager.BasicRenderer.prototype = {
11919 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11920 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11921 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11922 * @param {Roo.Element} el The element being rendered
11923 * @param {Object} response The YUI Connect response object
11924 * @param {UpdateManager} updateManager The calling update manager
11925 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11927 render : function(el, response, updateManager, callback){
11928 el.update(response.responseText, updateManager.loadScripts, callback);
11933 * Ext JS Library 1.1.1
11934 * Copyright(c) 2006-2007, Ext JS, LLC.
11936 * Originally Released Under LGPL - original licence link has changed is not relivant.
11939 * <script type="text/javascript">
11943 * @class Roo.util.DelayedTask
11944 * Provides a convenient method of performing setTimeout where a new
11945 * timeout cancels the old timeout. An example would be performing validation on a keypress.
11946 * You can use this class to buffer
11947 * the keypress events for a certain number of milliseconds, and perform only if they stop
11948 * for that amount of time.
11949 * @constructor The parameters to this constructor serve as defaults and are not required.
11950 * @param {Function} fn (optional) The default function to timeout
11951 * @param {Object} scope (optional) The default scope of that timeout
11952 * @param {Array} args (optional) The default Array of arguments
11954 Roo.util.DelayedTask = function(fn, scope, args){
11955 var id = null, d, t;
11957 var call = function(){
11958 var now = new Date().getTime();
11962 fn.apply(scope, args || []);
11966 * Cancels any pending timeout and queues a new one
11967 * @param {Number} delay The milliseconds to delay
11968 * @param {Function} newFn (optional) Overrides function passed to constructor
11969 * @param {Object} newScope (optional) Overrides scope passed to constructor
11970 * @param {Array} newArgs (optional) Overrides args passed to constructor
11972 this.delay = function(delay, newFn, newScope, newArgs){
11973 if(id && delay != d){
11977 t = new Date().getTime();
11979 scope = newScope || scope;
11980 args = newArgs || args;
11982 id = setInterval(call, d);
11987 * Cancel the last queued timeout
11989 this.cancel = function(){
11997 * Ext JS Library 1.1.1
11998 * Copyright(c) 2006-2007, Ext JS, LLC.
12000 * Originally Released Under LGPL - original licence link has changed is not relivant.
12003 * <script type="text/javascript">
12007 Roo.util.TaskRunner = function(interval){
12008 interval = interval || 10;
12009 var tasks = [], removeQueue = [];
12011 var running = false;
12013 var stopThread = function(){
12019 var startThread = function(){
12022 id = setInterval(runTasks, interval);
12026 var removeTask = function(task){
12027 removeQueue.push(task);
12033 var runTasks = function(){
12034 if(removeQueue.length > 0){
12035 for(var i = 0, len = removeQueue.length; i < len; i++){
12036 tasks.remove(removeQueue[i]);
12039 if(tasks.length < 1){
12044 var now = new Date().getTime();
12045 for(var i = 0, len = tasks.length; i < len; ++i){
12047 var itime = now - t.taskRunTime;
12048 if(t.interval <= itime){
12049 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12050 t.taskRunTime = now;
12051 if(rt === false || t.taskRunCount === t.repeat){
12056 if(t.duration && t.duration <= (now - t.taskStartTime)){
12063 * Queues a new task.
12064 * @param {Object} task
12066 this.start = function(task){
12068 task.taskStartTime = new Date().getTime();
12069 task.taskRunTime = 0;
12070 task.taskRunCount = 0;
12075 this.stop = function(task){
12080 this.stopAll = function(){
12082 for(var i = 0, len = tasks.length; i < len; i++){
12083 if(tasks[i].onStop){
12092 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12094 * Ext JS Library 1.1.1
12095 * Copyright(c) 2006-2007, Ext JS, LLC.
12097 * Originally Released Under LGPL - original licence link has changed is not relivant.
12100 * <script type="text/javascript">
12105 * @class Roo.util.MixedCollection
12106 * @extends Roo.util.Observable
12107 * A Collection class that maintains both numeric indexes and keys and exposes events.
12109 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12110 * collection (defaults to false)
12111 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12112 * and return the key value for that item. This is used when available to look up the key on items that
12113 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12114 * equivalent to providing an implementation for the {@link #getKey} method.
12116 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12124 * Fires when the collection is cleared.
12129 * Fires when an item is added to the collection.
12130 * @param {Number} index The index at which the item was added.
12131 * @param {Object} o The item added.
12132 * @param {String} key The key associated with the added item.
12137 * Fires when an item is replaced in the collection.
12138 * @param {String} key he key associated with the new added.
12139 * @param {Object} old The item being replaced.
12140 * @param {Object} new The new item.
12145 * Fires when an item is removed from the collection.
12146 * @param {Object} o The item being removed.
12147 * @param {String} key (optional) The key associated with the removed item.
12152 this.allowFunctions = allowFunctions === true;
12154 this.getKey = keyFn;
12156 Roo.util.MixedCollection.superclass.constructor.call(this);
12159 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12160 allowFunctions : false,
12163 * Adds an item to the collection.
12164 * @param {String} key The key to associate with the item
12165 * @param {Object} o The item to add.
12166 * @return {Object} The item added.
12168 add : function(key, o){
12169 if(arguments.length == 1){
12171 key = this.getKey(o);
12173 if(typeof key == "undefined" || key === null){
12175 this.items.push(o);
12176 this.keys.push(null);
12178 var old = this.map[key];
12180 return this.replace(key, o);
12183 this.items.push(o);
12185 this.keys.push(key);
12187 this.fireEvent("add", this.length-1, o, key);
12192 * MixedCollection has a generic way to fetch keys if you implement getKey.
12195 var mc = new Roo.util.MixedCollection();
12196 mc.add(someEl.dom.id, someEl);
12197 mc.add(otherEl.dom.id, otherEl);
12201 var mc = new Roo.util.MixedCollection();
12202 mc.getKey = function(el){
12208 // or via the constructor
12209 var mc = new Roo.util.MixedCollection(false, function(el){
12215 * @param o {Object} The item for which to find the key.
12216 * @return {Object} The key for the passed item.
12218 getKey : function(o){
12223 * Replaces an item in the collection.
12224 * @param {String} key The key associated with the item to replace, or the item to replace.
12225 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12226 * @return {Object} The new item.
12228 replace : function(key, o){
12229 if(arguments.length == 1){
12231 key = this.getKey(o);
12233 var old = this.item(key);
12234 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12235 return this.add(key, o);
12237 var index = this.indexOfKey(key);
12238 this.items[index] = o;
12240 this.fireEvent("replace", key, old, o);
12245 * Adds all elements of an Array or an Object to the collection.
12246 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12247 * an Array of values, each of which are added to the collection.
12249 addAll : function(objs){
12250 if(arguments.length > 1 || objs instanceof Array){
12251 var args = arguments.length > 1 ? arguments : objs;
12252 for(var i = 0, len = args.length; i < len; i++){
12256 for(var key in objs){
12257 if(this.allowFunctions || typeof objs[key] != "function"){
12258 this.add(key, objs[key]);
12265 * Executes the specified function once for every item in the collection, passing each
12266 * item as the first and only parameter. returning false from the function will stop the iteration.
12267 * @param {Function} fn The function to execute for each item.
12268 * @param {Object} scope (optional) The scope in which to execute the function.
12270 each : function(fn, scope){
12271 var items = [].concat(this.items); // each safe for removal
12272 for(var i = 0, len = items.length; i < len; i++){
12273 if(fn.call(scope || items[i], items[i], i, len) === false){
12280 * Executes the specified function once for every key in the collection, passing each
12281 * key, and its associated item as the first two parameters.
12282 * @param {Function} fn The function to execute for each item.
12283 * @param {Object} scope (optional) The scope in which to execute the function.
12285 eachKey : function(fn, scope){
12286 for(var i = 0, len = this.keys.length; i < len; i++){
12287 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12292 * Returns the first item in the collection which elicits a true return value from the
12293 * passed selection function.
12294 * @param {Function} fn The selection function to execute for each item.
12295 * @param {Object} scope (optional) The scope in which to execute the function.
12296 * @return {Object} The first item in the collection which returned true from the selection function.
12298 find : function(fn, scope){
12299 for(var i = 0, len = this.items.length; i < len; i++){
12300 if(fn.call(scope || window, this.items[i], this.keys[i])){
12301 return this.items[i];
12308 * Inserts an item at the specified index in the collection.
12309 * @param {Number} index The index to insert the item at.
12310 * @param {String} key The key to associate with the new item, or the item itself.
12311 * @param {Object} o (optional) If the second parameter was a key, the new item.
12312 * @return {Object} The item inserted.
12314 insert : function(index, key, o){
12315 if(arguments.length == 2){
12317 key = this.getKey(o);
12319 if(index >= this.length){
12320 return this.add(key, o);
12323 this.items.splice(index, 0, o);
12324 if(typeof key != "undefined" && key != null){
12327 this.keys.splice(index, 0, key);
12328 this.fireEvent("add", index, o, key);
12333 * Removed an item from the collection.
12334 * @param {Object} o The item to remove.
12335 * @return {Object} The item removed.
12337 remove : function(o){
12338 return this.removeAt(this.indexOf(o));
12342 * Remove an item from a specified index in the collection.
12343 * @param {Number} index The index within the collection of the item to remove.
12345 removeAt : function(index){
12346 if(index < this.length && index >= 0){
12348 var o = this.items[index];
12349 this.items.splice(index, 1);
12350 var key = this.keys[index];
12351 if(typeof key != "undefined"){
12352 delete this.map[key];
12354 this.keys.splice(index, 1);
12355 this.fireEvent("remove", o, key);
12360 * Removed an item associated with the passed key fom the collection.
12361 * @param {String} key The key of the item to remove.
12363 removeKey : function(key){
12364 return this.removeAt(this.indexOfKey(key));
12368 * Returns the number of items in the collection.
12369 * @return {Number} the number of items in the collection.
12371 getCount : function(){
12372 return this.length;
12376 * Returns index within the collection of the passed Object.
12377 * @param {Object} o The item to find the index of.
12378 * @return {Number} index of the item.
12380 indexOf : function(o){
12381 if(!this.items.indexOf){
12382 for(var i = 0, len = this.items.length; i < len; i++){
12383 if(this.items[i] == o) return i;
12387 return this.items.indexOf(o);
12392 * Returns index within the collection of the passed key.
12393 * @param {String} key The key to find the index of.
12394 * @return {Number} index of the key.
12396 indexOfKey : function(key){
12397 if(!this.keys.indexOf){
12398 for(var i = 0, len = this.keys.length; i < len; i++){
12399 if(this.keys[i] == key) return i;
12403 return this.keys.indexOf(key);
12408 * Returns the item associated with the passed key OR index. Key has priority over index.
12409 * @param {String/Number} key The key or index of the item.
12410 * @return {Object} The item associated with the passed key.
12412 item : function(key){
12413 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12414 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12418 * Returns the item at the specified index.
12419 * @param {Number} index The index of the item.
12422 itemAt : function(index){
12423 return this.items[index];
12427 * Returns the item associated with the passed key.
12428 * @param {String/Number} key The key of the item.
12429 * @return {Object} The item associated with the passed key.
12431 key : function(key){
12432 return this.map[key];
12436 * Returns true if the collection contains the passed Object as an item.
12437 * @param {Object} o The Object to look for in the collection.
12438 * @return {Boolean} True if the collection contains the Object as an item.
12440 contains : function(o){
12441 return this.indexOf(o) != -1;
12445 * Returns true if the collection contains the passed Object as a key.
12446 * @param {String} key The key to look for in the collection.
12447 * @return {Boolean} True if the collection contains the Object as a key.
12449 containsKey : function(key){
12450 return typeof this.map[key] != "undefined";
12454 * Removes all items from the collection.
12456 clear : function(){
12461 this.fireEvent("clear");
12465 * Returns the first item in the collection.
12466 * @return {Object} the first item in the collection..
12468 first : function(){
12469 return this.items[0];
12473 * Returns the last item in the collection.
12474 * @return {Object} the last item in the collection..
12477 return this.items[this.length-1];
12480 _sort : function(property, dir, fn){
12481 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12482 fn = fn || function(a, b){
12485 var c = [], k = this.keys, items = this.items;
12486 for(var i = 0, len = items.length; i < len; i++){
12487 c[c.length] = {key: k[i], value: items[i], index: i};
12489 c.sort(function(a, b){
12490 var v = fn(a[property], b[property]) * dsc;
12492 v = (a.index < b.index ? -1 : 1);
12496 for(var i = 0, len = c.length; i < len; i++){
12497 items[i] = c[i].value;
12500 this.fireEvent("sort", this);
12504 * Sorts this collection with the passed comparison function
12505 * @param {String} direction (optional) "ASC" or "DESC"
12506 * @param {Function} fn (optional) comparison function
12508 sort : function(dir, fn){
12509 this._sort("value", dir, fn);
12513 * Sorts this collection by keys
12514 * @param {String} direction (optional) "ASC" or "DESC"
12515 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12517 keySort : function(dir, fn){
12518 this._sort("key", dir, fn || function(a, b){
12519 return String(a).toUpperCase()-String(b).toUpperCase();
12524 * Returns a range of items in this collection
12525 * @param {Number} startIndex (optional) defaults to 0
12526 * @param {Number} endIndex (optional) default to the last item
12527 * @return {Array} An array of items
12529 getRange : function(start, end){
12530 var items = this.items;
12531 if(items.length < 1){
12534 start = start || 0;
12535 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12538 for(var i = start; i <= end; i++) {
12539 r[r.length] = items[i];
12542 for(var i = start; i >= end; i--) {
12543 r[r.length] = items[i];
12550 * Filter the <i>objects</i> in this collection by a specific property.
12551 * Returns a new collection that has been filtered.
12552 * @param {String} property A property on your objects
12553 * @param {String/RegExp} value Either string that the property values
12554 * should start with or a RegExp to test against the property
12555 * @return {MixedCollection} The new filtered collection
12557 filter : function(property, value){
12558 if(!value.exec){ // not a regex
12559 value = String(value);
12560 if(value.length == 0){
12561 return this.clone();
12563 value = new RegExp("^" + Roo.escapeRe(value), "i");
12565 return this.filterBy(function(o){
12566 return o && value.test(o[property]);
12571 * Filter by a function. * Returns a new collection that has been filtered.
12572 * The passed function will be called with each
12573 * object in the collection. If the function returns true, the value is included
12574 * otherwise it is filtered.
12575 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12576 * @param {Object} scope (optional) The scope of the function (defaults to this)
12577 * @return {MixedCollection} The new filtered collection
12579 filterBy : function(fn, scope){
12580 var r = new Roo.util.MixedCollection();
12581 r.getKey = this.getKey;
12582 var k = this.keys, it = this.items;
12583 for(var i = 0, len = it.length; i < len; i++){
12584 if(fn.call(scope||this, it[i], k[i])){
12585 r.add(k[i], it[i]);
12592 * Creates a duplicate of this collection
12593 * @return {MixedCollection}
12595 clone : function(){
12596 var r = new Roo.util.MixedCollection();
12597 var k = this.keys, it = this.items;
12598 for(var i = 0, len = it.length; i < len; i++){
12599 r.add(k[i], it[i]);
12601 r.getKey = this.getKey;
12606 * Returns the item associated with the passed key or index.
12608 * @param {String/Number} key The key or index of the item.
12609 * @return {Object} The item associated with the passed key.
12611 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12613 * Ext JS Library 1.1.1
12614 * Copyright(c) 2006-2007, Ext JS, LLC.
12616 * Originally Released Under LGPL - original licence link has changed is not relivant.
12619 * <script type="text/javascript">
12622 * @class Roo.util.JSON
12623 * Modified version of Douglas Crockford"s json.js that doesn"t
12624 * mess with the Object prototype
12625 * http://www.json.org/js.html
12628 Roo.util.JSON = new (function(){
12629 var useHasOwn = {}.hasOwnProperty ? true : false;
12631 // crashes Safari in some instances
12632 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12634 var pad = function(n) {
12635 return n < 10 ? "0" + n : n;
12648 var encodeString = function(s){
12649 if (/["\\\x00-\x1f]/.test(s)) {
12650 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12655 c = b.charCodeAt();
12657 Math.floor(c / 16).toString(16) +
12658 (c % 16).toString(16);
12661 return '"' + s + '"';
12664 var encodeArray = function(o){
12665 var a = ["["], b, i, l = o.length, v;
12666 for (i = 0; i < l; i += 1) {
12668 switch (typeof v) {
12677 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12685 var encodeDate = function(o){
12686 return '"' + o.getFullYear() + "-" +
12687 pad(o.getMonth() + 1) + "-" +
12688 pad(o.getDate()) + "T" +
12689 pad(o.getHours()) + ":" +
12690 pad(o.getMinutes()) + ":" +
12691 pad(o.getSeconds()) + '"';
12695 * Encodes an Object, Array or other value
12696 * @param {Mixed} o The variable to encode
12697 * @return {String} The JSON string
12699 this.encode = function(o){
12700 if(typeof o == "undefined" || o === null){
12702 }else if(o instanceof Array){
12703 return encodeArray(o);
12704 }else if(o instanceof Date){
12705 return encodeDate(o);
12706 }else if(typeof o == "string"){
12707 return encodeString(o);
12708 }else if(typeof o == "number"){
12709 return isFinite(o) ? String(o) : "null";
12710 }else if(typeof o == "boolean"){
12713 var a = ["{"], b, i, v;
12715 if(!useHasOwn || o.hasOwnProperty(i)) {
12717 switch (typeof v) {
12726 a.push(this.encode(i), ":",
12727 v === null ? "null" : this.encode(v));
12738 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12739 * @param {String} json The JSON string
12740 * @return {Object} The resulting object
12742 this.decode = function(json){
12746 return eval("(" + json + ')');
12750 * Shorthand for {@link Roo.util.JSON#encode}
12751 * @member Roo encode
12753 Roo.encode = Roo.util.JSON.encode;
12755 * Shorthand for {@link Roo.util.JSON#decode}
12756 * @member Roo decode
12758 Roo.decode = Roo.util.JSON.decode;
12761 * Ext JS Library 1.1.1
12762 * Copyright(c) 2006-2007, Ext JS, LLC.
12764 * Originally Released Under LGPL - original licence link has changed is not relivant.
12767 * <script type="text/javascript">
12771 * @class Roo.util.Format
12772 * Reusable data formatting functions
12775 Roo.util.Format = function(){
12776 var trimRe = /^\s+|\s+$/g;
12779 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12780 * @param {String} value The string to truncate
12781 * @param {Number} length The maximum length to allow before truncating
12782 * @return {String} The converted text
12784 ellipsis : function(value, len){
12785 if(value && value.length > len){
12786 return value.substr(0, len-3)+"...";
12792 * Checks a reference and converts it to empty string if it is undefined
12793 * @param {Mixed} value Reference to check
12794 * @return {Mixed} Empty string if converted, otherwise the original value
12796 undef : function(value){
12797 return typeof value != "undefined" ? value : "";
12801 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12802 * @param {String} value The string to encode
12803 * @return {String} The encoded text
12805 htmlEncode : function(value){
12806 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12810 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12811 * @param {String} value The string to decode
12812 * @return {String} The decoded text
12814 htmlDecode : function(value){
12815 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12819 * Trims any whitespace from either side of a string
12820 * @param {String} value The text to trim
12821 * @return {String} The trimmed text
12823 trim : function(value){
12824 return String(value).replace(trimRe, "");
12828 * Returns a substring from within an original string
12829 * @param {String} value The original text
12830 * @param {Number} start The start index of the substring
12831 * @param {Number} length The length of the substring
12832 * @return {String} The substring
12834 substr : function(value, start, length){
12835 return String(value).substr(start, length);
12839 * Converts a string to all lower case letters
12840 * @param {String} value The text to convert
12841 * @return {String} The converted text
12843 lowercase : function(value){
12844 return String(value).toLowerCase();
12848 * Converts a string to all upper case letters
12849 * @param {String} value The text to convert
12850 * @return {String} The converted text
12852 uppercase : function(value){
12853 return String(value).toUpperCase();
12857 * Converts the first character only of a string to upper case
12858 * @param {String} value The text to convert
12859 * @return {String} The converted text
12861 capitalize : function(value){
12862 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12866 call : function(value, fn){
12867 if(arguments.length > 2){
12868 var args = Array.prototype.slice.call(arguments, 2);
12869 args.unshift(value);
12871 return /** eval:var:value */ eval(fn).apply(window, args);
12873 /** eval:var:value */
12874 return /** eval:var:value */ eval(fn).call(window, value);
12879 * Format a number as US currency
12880 * @param {Number/String} value The numeric value to format
12881 * @return {String} The formatted currency string
12883 usMoney : function(v){
12884 v = (Math.round((v-0)*100))/100;
12885 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12887 var ps = v.split('.');
12889 var sub = ps[1] ? '.'+ ps[1] : '.00';
12890 var r = /(\d+)(\d{3})/;
12891 while (r.test(whole)) {
12892 whole = whole.replace(r, '$1' + ',' + '$2');
12894 return "$" + whole + sub ;
12898 * Parse a value into a formatted date using the specified format pattern.
12899 * @param {Mixed} value The value to format
12900 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12901 * @return {String} The formatted date string
12903 date : function(v, format){
12907 if(!(v instanceof Date)){
12908 v = new Date(Date.parse(v));
12910 return v.dateFormat(format || "m/d/Y");
12914 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12915 * @param {String} format Any valid date format string
12916 * @return {Function} The date formatting function
12918 dateRenderer : function(format){
12919 return function(v){
12920 return Roo.util.Format.date(v, format);
12925 stripTagsRE : /<\/?[^>]+>/gi,
12928 * Strips all HTML tags
12929 * @param {Mixed} value The text from which to strip tags
12930 * @return {String} The stripped text
12932 stripTags : function(v){
12933 return !v ? v : String(v).replace(this.stripTagsRE, "");
12938 * Ext JS Library 1.1.1
12939 * Copyright(c) 2006-2007, Ext JS, LLC.
12941 * Originally Released Under LGPL - original licence link has changed is not relivant.
12944 * <script type="text/javascript">
12951 * @class Roo.MasterTemplate
12952 * @extends Roo.Template
12953 * Provides a template that can have child templates. The syntax is:
12955 var t = new Roo.MasterTemplate(
12956 '<select name="{name}">',
12957 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
12960 t.add('options', {value: 'foo', text: 'bar'});
12961 // or you can add multiple child elements in one shot
12962 t.addAll('options', [
12963 {value: 'foo', text: 'bar'},
12964 {value: 'foo2', text: 'bar2'},
12965 {value: 'foo3', text: 'bar3'}
12967 // then append, applying the master template values
12968 t.append('my-form', {name: 'my-select'});
12970 * A name attribute for the child template is not required if you have only one child
12971 * template or you want to refer to them by index.
12973 Roo.MasterTemplate = function(){
12974 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
12975 this.originalHtml = this.html;
12977 var m, re = this.subTemplateRe;
12980 while(m = re.exec(this.html)){
12981 var name = m[1], content = m[2];
12986 tpl : new Roo.Template(content)
12989 st[name] = st[subIndex];
12991 st[subIndex].tpl.compile();
12992 st[subIndex].tpl.call = this.call.createDelegate(this);
12995 this.subCount = subIndex;
12998 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13000 * The regular expression used to match sub templates
13004 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13007 * Applies the passed values to a child template.
13008 * @param {String/Number} name (optional) The name or index of the child template
13009 * @param {Array/Object} values The values to be applied to the template
13010 * @return {MasterTemplate} this
13012 add : function(name, values){
13013 if(arguments.length == 1){
13014 values = arguments[0];
13017 var s = this.subs[name];
13018 s.buffer[s.buffer.length] = s.tpl.apply(values);
13023 * Applies all the passed values to a child template.
13024 * @param {String/Number} name (optional) The name or index of the child template
13025 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13026 * @param {Boolean} reset (optional) True to reset the template first
13027 * @return {MasterTemplate} this
13029 fill : function(name, values, reset){
13031 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13039 for(var i = 0, len = values.length; i < len; i++){
13040 this.add(name, values[i]);
13046 * Resets the template for reuse
13047 * @return {MasterTemplate} this
13049 reset : function(){
13051 for(var i = 0; i < this.subCount; i++){
13057 applyTemplate : function(values){
13059 var replaceIndex = -1;
13060 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13061 return s[++replaceIndex].buffer.join("");
13063 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13066 apply : function(){
13067 return this.applyTemplate.apply(this, arguments);
13070 compile : function(){return this;}
13074 * Alias for fill().
13077 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13079 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13080 * var tpl = Roo.MasterTemplate.from('element-id');
13081 * @param {String/HTMLElement} el
13082 * @param {Object} config
13085 Roo.MasterTemplate.from = function(el, config){
13086 el = Roo.getDom(el);
13087 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13090 * Ext JS Library 1.1.1
13091 * Copyright(c) 2006-2007, Ext JS, LLC.
13093 * Originally Released Under LGPL - original licence link has changed is not relivant.
13096 * <script type="text/javascript">
13101 * @class Roo.util.CSS
13102 * Utility class for manipulating CSS rules
13105 Roo.util.CSS = function(){
13107 var doc = document;
13109 var camelRe = /(-[a-z])/gi;
13110 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13114 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13115 * tag and appended to the HEAD of the document.
13116 * @param {String} cssText The text containing the css rules
13117 * @param {String} id An id to add to the stylesheet for later removal
13118 * @return {StyleSheet}
13120 createStyleSheet : function(cssText, id){
13122 var head = doc.getElementsByTagName("head")[0];
13123 var rules = doc.createElement("style");
13124 rules.setAttribute("type", "text/css");
13126 rules.setAttribute("id", id);
13129 head.appendChild(rules);
13130 ss = rules.styleSheet;
13131 ss.cssText = cssText;
13134 rules.appendChild(doc.createTextNode(cssText));
13136 rules.cssText = cssText;
13138 head.appendChild(rules);
13139 ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13141 this.cacheStyleSheet(ss);
13146 * Removes a style or link tag by id
13147 * @param {String} id The id of the tag
13149 removeStyleSheet : function(id){
13150 var existing = doc.getElementById(id);
13152 existing.parentNode.removeChild(existing);
13157 * Dynamically swaps an existing stylesheet reference for a new one
13158 * @param {String} id The id of an existing link tag to remove
13159 * @param {String} url The href of the new stylesheet to include
13161 swapStyleSheet : function(id, url){
13162 this.removeStyleSheet(id);
13163 var ss = doc.createElement("link");
13164 ss.setAttribute("rel", "stylesheet");
13165 ss.setAttribute("type", "text/css");
13166 ss.setAttribute("id", id);
13167 ss.setAttribute("href", url);
13168 doc.getElementsByTagName("head")[0].appendChild(ss);
13172 * Refresh the rule cache if you have dynamically added stylesheets
13173 * @return {Object} An object (hash) of rules indexed by selector
13175 refreshCache : function(){
13176 return this.getRules(true);
13180 cacheStyleSheet : function(ss){
13184 try{// try catch for cross domain access issue
13185 var ssRules = ss.cssRules || ss.rules;
13186 for(var j = ssRules.length-1; j >= 0; --j){
13187 rules[ssRules[j].selectorText] = ssRules[j];
13193 * Gets all css rules for the document
13194 * @param {Boolean} refreshCache true to refresh the internal cache
13195 * @return {Object} An object (hash) of rules indexed by selector
13197 getRules : function(refreshCache){
13198 if(rules == null || refreshCache){
13200 var ds = doc.styleSheets;
13201 for(var i =0, len = ds.length; i < len; i++){
13203 this.cacheStyleSheet(ds[i]);
13211 * Gets an an individual CSS rule by selector(s)
13212 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13213 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13214 * @return {CSSRule} The CSS rule or null if one is not found
13216 getRule : function(selector, refreshCache){
13217 var rs = this.getRules(refreshCache);
13218 if(!(selector instanceof Array)){
13219 return rs[selector];
13221 for(var i = 0; i < selector.length; i++){
13222 if(rs[selector[i]]){
13223 return rs[selector[i]];
13231 * Updates a rule property
13232 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13233 * @param {String} property The css property
13234 * @param {String} value The new value for the property
13235 * @return {Boolean} true If a rule was found and updated
13237 updateRule : function(selector, property, value){
13238 if(!(selector instanceof Array)){
13239 var rule = this.getRule(selector);
13241 rule.style[property.replace(camelRe, camelFn)] = value;
13245 for(var i = 0; i < selector.length; i++){
13246 if(this.updateRule(selector[i], property, value)){
13256 * Ext JS Library 1.1.1
13257 * Copyright(c) 2006-2007, Ext JS, LLC.
13259 * Originally Released Under LGPL - original licence link has changed is not relivant.
13262 * <script type="text/javascript">
13268 * @class Roo.util.ClickRepeater
13269 * @extends Roo.util.Observable
13271 * A wrapper class which can be applied to any element. Fires a "click" event while the
13272 * mouse is pressed. The interval between firings may be specified in the config but
13273 * defaults to 10 milliseconds.
13275 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13277 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13278 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13279 * Similar to an autorepeat key delay.
13280 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13281 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13282 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13283 * "interval" and "delay" are ignored. "immediate" is honored.
13284 * @cfg {Boolean} preventDefault True to prevent the default click event
13285 * @cfg {Boolean} stopDefault True to stop the default click event
13288 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13289 * 2007-02-02 jvs Renamed to ClickRepeater
13290 * 2007-02-03 jvs Modifications for FF Mac and Safari
13293 * @param {String/HTMLElement/Element} el The element to listen on
13294 * @param {Object} config
13296 Roo.util.ClickRepeater = function(el, config)
13298 this.el = Roo.get(el);
13299 this.el.unselectable();
13301 Roo.apply(this, config);
13306 * Fires when the mouse button is depressed.
13307 * @param {Roo.util.ClickRepeater} this
13309 "mousedown" : true,
13312 * Fires on a specified interval during the time the element is pressed.
13313 * @param {Roo.util.ClickRepeater} this
13318 * Fires when the mouse key is released.
13319 * @param {Roo.util.ClickRepeater} this
13324 this.el.on("mousedown", this.handleMouseDown, this);
13325 if(this.preventDefault || this.stopDefault){
13326 this.el.on("click", function(e){
13327 if(this.preventDefault){
13328 e.preventDefault();
13330 if(this.stopDefault){
13336 // allow inline handler
13338 this.on("click", this.handler, this.scope || this);
13341 Roo.util.ClickRepeater.superclass.constructor.call(this);
13344 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13347 preventDefault : true,
13348 stopDefault : false,
13352 handleMouseDown : function(){
13353 clearTimeout(this.timer);
13355 if(this.pressClass){
13356 this.el.addClass(this.pressClass);
13358 this.mousedownTime = new Date();
13360 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13361 this.el.on("mouseout", this.handleMouseOut, this);
13363 this.fireEvent("mousedown", this);
13364 this.fireEvent("click", this);
13366 this.timer = this.click.defer(this.delay || this.interval, this);
13370 click : function(){
13371 this.fireEvent("click", this);
13372 this.timer = this.click.defer(this.getInterval(), this);
13376 getInterval: function(){
13377 if(!this.accelerate){
13378 return this.interval;
13380 var pressTime = this.mousedownTime.getElapsed();
13381 if(pressTime < 500){
13383 }else if(pressTime < 1700){
13385 }else if(pressTime < 2600){
13387 }else if(pressTime < 3500){
13389 }else if(pressTime < 4400){
13391 }else if(pressTime < 5300){
13393 }else if(pressTime < 6200){
13401 handleMouseOut : function(){
13402 clearTimeout(this.timer);
13403 if(this.pressClass){
13404 this.el.removeClass(this.pressClass);
13406 this.el.on("mouseover", this.handleMouseReturn, this);
13410 handleMouseReturn : function(){
13411 this.el.un("mouseover", this.handleMouseReturn);
13412 if(this.pressClass){
13413 this.el.addClass(this.pressClass);
13419 handleMouseUp : function(){
13420 clearTimeout(this.timer);
13421 this.el.un("mouseover", this.handleMouseReturn);
13422 this.el.un("mouseout", this.handleMouseOut);
13423 Roo.get(document).un("mouseup", this.handleMouseUp);
13424 this.el.removeClass(this.pressClass);
13425 this.fireEvent("mouseup", this);
13429 * Ext JS Library 1.1.1
13430 * Copyright(c) 2006-2007, Ext JS, LLC.
13432 * Originally Released Under LGPL - original licence link has changed is not relivant.
13435 * <script type="text/javascript">
13440 * @class Roo.KeyNav
13441 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13442 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13443 * way to implement custom navigation schemes for any UI component.</p>
13444 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13445 * pageUp, pageDown, del, home, end. Usage:</p>
13447 var nav = new Roo.KeyNav("my-element", {
13448 "left" : function(e){
13449 this.moveLeft(e.ctrlKey);
13451 "right" : function(e){
13452 this.moveRight(e.ctrlKey);
13454 "enter" : function(e){
13461 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13462 * @param {Object} config The config
13464 Roo.KeyNav = function(el, config){
13465 this.el = Roo.get(el);
13466 Roo.apply(this, config);
13467 if(!this.disabled){
13468 this.disabled = true;
13473 Roo.KeyNav.prototype = {
13475 * @cfg {Boolean} disabled
13476 * True to disable this KeyNav instance (defaults to false)
13480 * @cfg {String} defaultEventAction
13481 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13482 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13483 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13485 defaultEventAction: "stopEvent",
13487 * @cfg {Boolean} forceKeyDown
13488 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13489 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13490 * handle keydown instead of keypress.
13492 forceKeyDown : false,
13495 prepareEvent : function(e){
13496 var k = e.getKey();
13497 var h = this.keyToHandler[k];
13498 //if(h && this[h]){
13499 // e.stopPropagation();
13501 if(Roo.isSafari && h && k >= 37 && k <= 40){
13507 relay : function(e){
13508 var k = e.getKey();
13509 var h = this.keyToHandler[k];
13511 if(this.doRelay(e, this[h], h) !== true){
13512 e[this.defaultEventAction]();
13518 doRelay : function(e, h, hname){
13519 return h.call(this.scope || this, e);
13522 // possible handlers
13536 // quick lookup hash
13553 * Enable this KeyNav
13555 enable: function(){
13557 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13558 // the EventObject will normalize Safari automatically
13559 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13560 this.el.on("keydown", this.relay, this);
13562 this.el.on("keydown", this.prepareEvent, this);
13563 this.el.on("keypress", this.relay, this);
13565 this.disabled = false;
13570 * Disable this KeyNav
13572 disable: function(){
13573 if(!this.disabled){
13574 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13575 this.el.un("keydown", this.relay);
13577 this.el.un("keydown", this.prepareEvent);
13578 this.el.un("keypress", this.relay);
13580 this.disabled = true;
13585 * Ext JS Library 1.1.1
13586 * Copyright(c) 2006-2007, Ext JS, LLC.
13588 * Originally Released Under LGPL - original licence link has changed is not relivant.
13591 * <script type="text/javascript">
13596 * @class Roo.KeyMap
13597 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13598 * The constructor accepts the same config object as defined by {@link #addBinding}.
13599 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13600 * combination it will call the function with this signature (if the match is a multi-key
13601 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13602 * A KeyMap can also handle a string representation of keys.<br />
13605 // map one key by key code
13606 var map = new Roo.KeyMap("my-element", {
13607 key: 13, // or Roo.EventObject.ENTER
13612 // map multiple keys to one action by string
13613 var map = new Roo.KeyMap("my-element", {
13619 // map multiple keys to multiple actions by strings and array of codes
13620 var map = new Roo.KeyMap("my-element", [
13623 fn: function(){ alert("Return was pressed"); }
13626 fn: function(){ alert('a, b or c was pressed'); }
13631 fn: function(){ alert('Control + shift + tab was pressed.'); }
13635 * <b>Note: A KeyMap starts enabled</b>
13637 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13638 * @param {Object} config The config (see {@link #addBinding})
13639 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13641 Roo.KeyMap = function(el, config, eventName){
13642 this.el = Roo.get(el);
13643 this.eventName = eventName || "keydown";
13644 this.bindings = [];
13646 this.addBinding(config);
13651 Roo.KeyMap.prototype = {
13653 * True to stop the event from bubbling and prevent the default browser action if the
13654 * key was handled by the KeyMap (defaults to false)
13660 * Add a new binding to this KeyMap. The following config object properties are supported:
13662 Property Type Description
13663 ---------- --------------- ----------------------------------------------------------------------
13664 key String/Array A single keycode or an array of keycodes to handle
13665 shift Boolean True to handle key only when shift is pressed (defaults to false)
13666 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13667 alt Boolean True to handle key only when alt is pressed (defaults to false)
13668 fn Function The function to call when KeyMap finds the expected key combination
13669 scope Object The scope of the callback function
13675 var map = new Roo.KeyMap(document, {
13676 key: Roo.EventObject.ENTER,
13681 //Add a new binding to the existing KeyMap later
13689 * @param {Object/Array} config A single KeyMap config or an array of configs
13691 addBinding : function(config){
13692 if(config instanceof Array){
13693 for(var i = 0, len = config.length; i < len; i++){
13694 this.addBinding(config[i]);
13698 var keyCode = config.key,
13699 shift = config.shift,
13700 ctrl = config.ctrl,
13703 scope = config.scope;
13704 if(typeof keyCode == "string"){
13706 var keyString = keyCode.toUpperCase();
13707 for(var j = 0, len = keyString.length; j < len; j++){
13708 ks.push(keyString.charCodeAt(j));
13712 var keyArray = keyCode instanceof Array;
13713 var handler = function(e){
13714 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13715 var k = e.getKey();
13717 for(var i = 0, len = keyCode.length; i < len; i++){
13718 if(keyCode[i] == k){
13719 if(this.stopEvent){
13722 fn.call(scope || window, k, e);
13728 if(this.stopEvent){
13731 fn.call(scope || window, k, e);
13736 this.bindings.push(handler);
13740 * Shorthand for adding a single key listener
13741 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13742 * following options:
13743 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13744 * @param {Function} fn The function to call
13745 * @param {Object} scope (optional) The scope of the function
13747 on : function(key, fn, scope){
13748 var keyCode, shift, ctrl, alt;
13749 if(typeof key == "object" && !(key instanceof Array)){
13768 handleKeyDown : function(e){
13769 if(this.enabled){ //just in case
13770 var b = this.bindings;
13771 for(var i = 0, len = b.length; i < len; i++){
13772 b[i].call(this, e);
13778 * Returns true if this KeyMap is enabled
13779 * @return {Boolean}
13781 isEnabled : function(){
13782 return this.enabled;
13786 * Enables this KeyMap
13788 enable: function(){
13790 this.el.on(this.eventName, this.handleKeyDown, this);
13791 this.enabled = true;
13796 * Disable this KeyMap
13798 disable: function(){
13800 this.el.removeListener(this.eventName, this.handleKeyDown, this);
13801 this.enabled = false;
13806 * Ext JS Library 1.1.1
13807 * Copyright(c) 2006-2007, Ext JS, LLC.
13809 * Originally Released Under LGPL - original licence link has changed is not relivant.
13812 * <script type="text/javascript">
13817 * @class Roo.util.TextMetrics
13818 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13819 * wide, in pixels, a given block of text will be.
13822 Roo.util.TextMetrics = function(){
13826 * Measures the size of the specified text
13827 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13828 * that can affect the size of the rendered text
13829 * @param {String} text The text to measure
13830 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13831 * in order to accurately measure the text height
13832 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13834 measure : function(el, text, fixedWidth){
13836 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13839 shared.setFixedWidth(fixedWidth || 'auto');
13840 return shared.getSize(text);
13844 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13845 * the overhead of multiple calls to initialize the style properties on each measurement.
13846 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13847 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13848 * in order to accurately measure the text height
13849 * @return {Roo.util.TextMetrics.Instance} instance The new instance
13851 createInstance : function(el, fixedWidth){
13852 return Roo.util.TextMetrics.Instance(el, fixedWidth);
13857 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13858 var ml = new Roo.Element(document.createElement('div'));
13859 document.body.appendChild(ml.dom);
13860 ml.position('absolute');
13861 ml.setLeftTop(-1000, -1000);
13865 ml.setWidth(fixedWidth);
13870 * Returns the size of the specified text based on the internal element's style and width properties
13871 * @param {String} text The text to measure
13872 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13874 getSize : function(text){
13876 var s = ml.getSize();
13882 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13883 * that can affect the size of the rendered text
13884 * @param {String/HTMLElement} el The element, dom node or id
13886 bind : function(el){
13888 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13893 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
13894 * to set a fixed width in order to accurately measure the text height.
13895 * @param {Number} width The width to set on the element
13897 setFixedWidth : function(width){
13898 ml.setWidth(width);
13902 * Returns the measured width of the specified text
13903 * @param {String} text The text to measure
13904 * @return {Number} width The width in pixels
13906 getWidth : function(text){
13907 ml.dom.style.width = 'auto';
13908 return this.getSize(text).width;
13912 * Returns the measured height of the specified text. For multiline text, be sure to call
13913 * {@link #setFixedWidth} if necessary.
13914 * @param {String} text The text to measure
13915 * @return {Number} height The height in pixels
13917 getHeight : function(text){
13918 return this.getSize(text).height;
13922 instance.bind(bindTo);
13927 // backwards compat
13928 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13930 * Ext JS Library 1.1.1
13931 * Copyright(c) 2006-2007, Ext JS, LLC.
13933 * Originally Released Under LGPL - original licence link has changed is not relivant.
13936 * <script type="text/javascript">
13940 * @class Roo.state.Provider
13941 * Abstract base class for state provider implementations. This class provides methods
13942 * for encoding and decoding <b>typed</b> variables including dates and defines the
13943 * Provider interface.
13945 Roo.state.Provider = function(){
13947 * @event statechange
13948 * Fires when a state change occurs.
13949 * @param {Provider} this This state provider
13950 * @param {String} key The state key which was changed
13951 * @param {String} value The encoded value for the state
13954 "statechange": true
13957 Roo.state.Provider.superclass.constructor.call(this);
13959 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
13961 * Returns the current value for a key
13962 * @param {String} name The key name
13963 * @param {Mixed} defaultValue A default value to return if the key's value is not found
13964 * @return {Mixed} The state data
13966 get : function(name, defaultValue){
13967 return typeof this.state[name] == "undefined" ?
13968 defaultValue : this.state[name];
13972 * Clears a value from the state
13973 * @param {String} name The key name
13975 clear : function(name){
13976 delete this.state[name];
13977 this.fireEvent("statechange", this, name, null);
13981 * Sets the value for a key
13982 * @param {String} name The key name
13983 * @param {Mixed} value The value to set
13985 set : function(name, value){
13986 this.state[name] = value;
13987 this.fireEvent("statechange", this, name, value);
13991 * Decodes a string previously encoded with {@link #encodeValue}.
13992 * @param {String} value The value to decode
13993 * @return {Mixed} The decoded value
13995 decodeValue : function(cookie){
13996 var re = /^(a|n|d|b|s|o)\:(.*)$/;
13997 var matches = re.exec(unescape(cookie));
13998 if(!matches || !matches[1]) return; // non state cookie
13999 var type = matches[1];
14000 var v = matches[2];
14003 return parseFloat(v);
14005 return new Date(Date.parse(v));
14010 var values = v.split("^");
14011 for(var i = 0, len = values.length; i < len; i++){
14012 all.push(this.decodeValue(values[i]));
14017 var values = v.split("^");
14018 for(var i = 0, len = values.length; i < len; i++){
14019 var kv = values[i].split("=");
14020 all[kv[0]] = this.decodeValue(kv[1]);
14029 * Encodes a value including type information. Decode with {@link #decodeValue}.
14030 * @param {Mixed} value The value to encode
14031 * @return {String} The encoded value
14033 encodeValue : function(v){
14035 if(typeof v == "number"){
14037 }else if(typeof v == "boolean"){
14038 enc = "b:" + (v ? "1" : "0");
14039 }else if(v instanceof Date){
14040 enc = "d:" + v.toGMTString();
14041 }else if(v instanceof Array){
14043 for(var i = 0, len = v.length; i < len; i++){
14044 flat += this.encodeValue(v[i]);
14045 if(i != len-1) flat += "^";
14048 }else if(typeof v == "object"){
14051 if(typeof v[key] != "function"){
14052 flat += key + "=" + this.encodeValue(v[key]) + "^";
14055 enc = "o:" + flat.substring(0, flat.length-1);
14059 return escape(enc);
14065 * Ext JS Library 1.1.1
14066 * Copyright(c) 2006-2007, Ext JS, LLC.
14068 * Originally Released Under LGPL - original licence link has changed is not relivant.
14071 * <script type="text/javascript">
14074 * @class Roo.state.Manager
14075 * This is the global state manager. By default all components that are "state aware" check this class
14076 * for state information if you don't pass them a custom state provider. In order for this class
14077 * to be useful, it must be initialized with a provider when your application initializes.
14079 // in your initialization function
14081 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14083 // supposed you have a {@link Roo.BorderLayout}
14084 var layout = new Roo.BorderLayout(...);
14085 layout.restoreState();
14086 // or a {Roo.BasicDialog}
14087 var dialog = new Roo.BasicDialog(...);
14088 dialog.restoreState();
14092 Roo.state.Manager = function(){
14093 var provider = new Roo.state.Provider();
14097 * Configures the default state provider for your application
14098 * @param {Provider} stateProvider The state provider to set
14100 setProvider : function(stateProvider){
14101 provider = stateProvider;
14105 * Returns the current value for a key
14106 * @param {String} name The key name
14107 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14108 * @return {Mixed} The state data
14110 get : function(key, defaultValue){
14111 return provider.get(key, defaultValue);
14115 * Sets the value for a key
14116 * @param {String} name The key name
14117 * @param {Mixed} value The state data
14119 set : function(key, value){
14120 provider.set(key, value);
14124 * Clears a value from the state
14125 * @param {String} name The key name
14127 clear : function(key){
14128 provider.clear(key);
14132 * Gets the currently configured state provider
14133 * @return {Provider} The state provider
14135 getProvider : function(){
14142 * Ext JS Library 1.1.1
14143 * Copyright(c) 2006-2007, Ext JS, LLC.
14145 * Originally Released Under LGPL - original licence link has changed is not relivant.
14148 * <script type="text/javascript">
14151 * @class Roo.state.CookieProvider
14152 * @extends Roo.state.Provider
14153 * The default Provider implementation which saves state via cookies.
14156 var cp = new Roo.state.CookieProvider({
14158 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14159 domain: "roojs.com"
14161 Roo.state.Manager.setProvider(cp);
14163 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14164 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14165 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14166 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14167 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14168 * domain the page is running on including the 'www' like 'www.roojs.com')
14169 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14171 * Create a new CookieProvider
14172 * @param {Object} config The configuration object
14174 Roo.state.CookieProvider = function(config){
14175 Roo.state.CookieProvider.superclass.constructor.call(this);
14177 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14178 this.domain = null;
14179 this.secure = false;
14180 Roo.apply(this, config);
14181 this.state = this.readCookies();
14184 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14186 set : function(name, value){
14187 if(typeof value == "undefined" || value === null){
14191 this.setCookie(name, value);
14192 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14196 clear : function(name){
14197 this.clearCookie(name);
14198 Roo.state.CookieProvider.superclass.clear.call(this, name);
14202 readCookies : function(){
14204 var c = document.cookie + ";";
14205 var re = /\s?(.*?)=(.*?);/g;
14207 while((matches = re.exec(c)) != null){
14208 var name = matches[1];
14209 var value = matches[2];
14210 if(name && name.substring(0,3) == "ys-"){
14211 cookies[name.substr(3)] = this.decodeValue(value);
14218 setCookie : function(name, value){
14219 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14220 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14221 ((this.path == null) ? "" : ("; path=" + this.path)) +
14222 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14223 ((this.secure == true) ? "; secure" : "");
14227 clearCookie : function(name){
14228 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14229 ((this.path == null) ? "" : ("; path=" + this.path)) +
14230 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14231 ((this.secure == true) ? "; secure" : "");
14235 * Ext JS Library 1.1.1
14236 * Copyright(c) 2006-2007, Ext JS, LLC.
14238 * Originally Released Under LGPL - original licence link has changed is not relivant.
14241 * <script type="text/javascript">
14247 * These classes are derivatives of the similarly named classes in the YUI Library.
14248 * The original license:
14249 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14250 * Code licensed under the BSD License:
14251 * http://developer.yahoo.net/yui/license.txt
14256 var Event=Roo.EventManager;
14257 var Dom=Roo.lib.Dom;
14260 * @class Roo.dd.DragDrop
14261 * Defines the interface and base operation of items that that can be
14262 * dragged or can be drop targets. It was designed to be extended, overriding
14263 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14264 * Up to three html elements can be associated with a DragDrop instance:
14266 * <li>linked element: the element that is passed into the constructor.
14267 * This is the element which defines the boundaries for interaction with
14268 * other DragDrop objects.</li>
14269 * <li>handle element(s): The drag operation only occurs if the element that
14270 * was clicked matches a handle element. By default this is the linked
14271 * element, but there are times that you will want only a portion of the
14272 * linked element to initiate the drag operation, and the setHandleElId()
14273 * method provides a way to define this.</li>
14274 * <li>drag element: this represents the element that would be moved along
14275 * with the cursor during a drag operation. By default, this is the linked
14276 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14277 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14280 * This class should not be instantiated until the onload event to ensure that
14281 * the associated elements are available.
14282 * The following would define a DragDrop obj that would interact with any
14283 * other DragDrop obj in the "group1" group:
14285 * dd = new Roo.dd.DragDrop("div1", "group1");
14287 * Since none of the event handlers have been implemented, nothing would
14288 * actually happen if you were to run the code above. Normally you would
14289 * override this class or one of the default implementations, but you can
14290 * also override the methods you want on an instance of the class...
14292 * dd.onDragDrop = function(e, id) {
14293 * alert("dd was dropped on " + id);
14297 * @param {String} id of the element that is linked to this instance
14298 * @param {String} sGroup the group of related DragDrop objects
14299 * @param {object} config an object containing configurable attributes
14300 * Valid properties for DragDrop:
14301 * padding, isTarget, maintainOffset, primaryButtonOnly
14303 Roo.dd.DragDrop = function(id, sGroup, config) {
14305 this.init(id, sGroup, config);
14309 Roo.dd.DragDrop.prototype = {
14312 * The id of the element associated with this object. This is what we
14313 * refer to as the "linked element" because the size and position of
14314 * this element is used to determine when the drag and drop objects have
14322 * Configuration attributes passed into the constructor
14329 * The id of the element that will be dragged. By default this is same
14330 * as the linked element , but could be changed to another element. Ex:
14332 * @property dragElId
14339 * the id of the element that initiates the drag operation. By default
14340 * this is the linked element, but could be changed to be a child of this
14341 * element. This lets us do things like only starting the drag when the
14342 * header element within the linked html element is clicked.
14343 * @property handleElId
14350 * An associative array of HTML tags that will be ignored if clicked.
14351 * @property invalidHandleTypes
14352 * @type {string: string}
14354 invalidHandleTypes: null,
14357 * An associative array of ids for elements that will be ignored if clicked
14358 * @property invalidHandleIds
14359 * @type {string: string}
14361 invalidHandleIds: null,
14364 * An indexted array of css class names for elements that will be ignored
14366 * @property invalidHandleClasses
14369 invalidHandleClasses: null,
14372 * The linked element's absolute X position at the time the drag was
14374 * @property startPageX
14381 * The linked element's absolute X position at the time the drag was
14383 * @property startPageY
14390 * The group defines a logical collection of DragDrop objects that are
14391 * related. Instances only get events when interacting with other
14392 * DragDrop object in the same group. This lets us define multiple
14393 * groups using a single DragDrop subclass if we want.
14395 * @type {string: string}
14400 * Individual drag/drop instances can be locked. This will prevent
14401 * onmousedown start drag.
14409 * Lock this instance
14412 lock: function() { this.locked = true; },
14415 * Unlock this instace
14418 unlock: function() { this.locked = false; },
14421 * By default, all insances can be a drop target. This can be disabled by
14422 * setting isTarget to false.
14429 * The padding configured for this drag and drop object for calculating
14430 * the drop zone intersection with this object.
14437 * Cached reference to the linked element
14438 * @property _domRef
14444 * Internal typeof flag
14445 * @property __ygDragDrop
14448 __ygDragDrop: true,
14451 * Set to true when horizontal contraints are applied
14452 * @property constrainX
14459 * Set to true when vertical contraints are applied
14460 * @property constrainY
14467 * The left constraint
14475 * The right constraint
14483 * The up constraint
14492 * The down constraint
14500 * Maintain offsets when we resetconstraints. Set to true when you want
14501 * the position of the element relative to its parent to stay the same
14502 * when the page changes
14504 * @property maintainOffset
14507 maintainOffset: false,
14510 * Array of pixel locations the element will snap to if we specified a
14511 * horizontal graduation/interval. This array is generated automatically
14512 * when you define a tick interval.
14519 * Array of pixel locations the element will snap to if we specified a
14520 * vertical graduation/interval. This array is generated automatically
14521 * when you define a tick interval.
14528 * By default the drag and drop instance will only respond to the primary
14529 * button click (left button for a right-handed mouse). Set to true to
14530 * allow drag and drop to start with any mouse click that is propogated
14532 * @property primaryButtonOnly
14535 primaryButtonOnly: true,
14538 * The availabe property is false until the linked dom element is accessible.
14539 * @property available
14545 * By default, drags can only be initiated if the mousedown occurs in the
14546 * region the linked element is. This is done in part to work around a
14547 * bug in some browsers that mis-report the mousedown if the previous
14548 * mouseup happened outside of the window. This property is set to true
14549 * if outer handles are defined.
14551 * @property hasOuterHandles
14555 hasOuterHandles: false,
14558 * Code that executes immediately before the startDrag event
14559 * @method b4StartDrag
14562 b4StartDrag: function(x, y) { },
14565 * Abstract method called after a drag/drop object is clicked
14566 * and the drag or mousedown time thresholds have beeen met.
14567 * @method startDrag
14568 * @param {int} X click location
14569 * @param {int} Y click location
14571 startDrag: function(x, y) { /* override this */ },
14574 * Code that executes immediately before the onDrag event
14578 b4Drag: function(e) { },
14581 * Abstract method called during the onMouseMove event while dragging an
14584 * @param {Event} e the mousemove event
14586 onDrag: function(e) { /* override this */ },
14589 * Abstract method called when this element fist begins hovering over
14590 * another DragDrop obj
14591 * @method onDragEnter
14592 * @param {Event} e the mousemove event
14593 * @param {String|DragDrop[]} id In POINT mode, the element
14594 * id this is hovering over. In INTERSECT mode, an array of one or more
14595 * dragdrop items being hovered over.
14597 onDragEnter: function(e, id) { /* override this */ },
14600 * Code that executes immediately before the onDragOver event
14601 * @method b4DragOver
14604 b4DragOver: function(e) { },
14607 * Abstract method called when this element is hovering over another
14609 * @method onDragOver
14610 * @param {Event} e the mousemove event
14611 * @param {String|DragDrop[]} id In POINT mode, the element
14612 * id this is hovering over. In INTERSECT mode, an array of dd items
14613 * being hovered over.
14615 onDragOver: function(e, id) { /* override this */ },
14618 * Code that executes immediately before the onDragOut event
14619 * @method b4DragOut
14622 b4DragOut: function(e) { },
14625 * Abstract method called when we are no longer hovering over an element
14626 * @method onDragOut
14627 * @param {Event} e the mousemove event
14628 * @param {String|DragDrop[]} id In POINT mode, the element
14629 * id this was hovering over. In INTERSECT mode, an array of dd items
14630 * that the mouse is no longer over.
14632 onDragOut: function(e, id) { /* override this */ },
14635 * Code that executes immediately before the onDragDrop event
14636 * @method b4DragDrop
14639 b4DragDrop: function(e) { },
14642 * Abstract method called when this item is dropped on another DragDrop
14644 * @method onDragDrop
14645 * @param {Event} e the mouseup event
14646 * @param {String|DragDrop[]} id In POINT mode, the element
14647 * id this was dropped on. In INTERSECT mode, an array of dd items this
14650 onDragDrop: function(e, id) { /* override this */ },
14653 * Abstract method called when this item is dropped on an area with no
14655 * @method onInvalidDrop
14656 * @param {Event} e the mouseup event
14658 onInvalidDrop: function(e) { /* override this */ },
14661 * Code that executes immediately before the endDrag event
14662 * @method b4EndDrag
14665 b4EndDrag: function(e) { },
14668 * Fired when we are done dragging the object
14670 * @param {Event} e the mouseup event
14672 endDrag: function(e) { /* override this */ },
14675 * Code executed immediately before the onMouseDown event
14676 * @method b4MouseDown
14677 * @param {Event} e the mousedown event
14680 b4MouseDown: function(e) { },
14683 * Event handler that fires when a drag/drop obj gets a mousedown
14684 * @method onMouseDown
14685 * @param {Event} e the mousedown event
14687 onMouseDown: function(e) { /* override this */ },
14690 * Event handler that fires when a drag/drop obj gets a mouseup
14691 * @method onMouseUp
14692 * @param {Event} e the mouseup event
14694 onMouseUp: function(e) { /* override this */ },
14697 * Override the onAvailable method to do what is needed after the initial
14698 * position was determined.
14699 * @method onAvailable
14701 onAvailable: function () {
14705 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14708 defaultPadding : {left:0, right:0, top:0, bottom:0},
14711 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14715 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14716 { dragElId: "existingProxyDiv" });
14717 dd.startDrag = function(){
14718 this.constrainTo("parent-id");
14721 * Or you can initalize it using the {@link Roo.Element} object:
14723 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14724 startDrag : function(){
14725 this.constrainTo("parent-id");
14729 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14730 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14731 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14732 * an object containing the sides to pad. For example: {right:10, bottom:10}
14733 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14735 constrainTo : function(constrainTo, pad, inContent){
14736 if(typeof pad == "number"){
14737 pad = {left: pad, right:pad, top:pad, bottom:pad};
14739 pad = pad || this.defaultPadding;
14740 var b = Roo.get(this.getEl()).getBox();
14741 var ce = Roo.get(constrainTo);
14742 var s = ce.getScroll();
14743 var c, cd = ce.dom;
14744 if(cd == document.body){
14745 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14748 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14752 var topSpace = b.y - c.y;
14753 var leftSpace = b.x - c.x;
14755 this.resetConstraints();
14756 this.setXConstraint(leftSpace - (pad.left||0), // left
14757 c.width - leftSpace - b.width - (pad.right||0) //right
14759 this.setYConstraint(topSpace - (pad.top||0), //top
14760 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14765 * Returns a reference to the linked element
14767 * @return {HTMLElement} the html element
14769 getEl: function() {
14770 if (!this._domRef) {
14771 this._domRef = Roo.getDom(this.id);
14774 return this._domRef;
14778 * Returns a reference to the actual element to drag. By default this is
14779 * the same as the html element, but it can be assigned to another
14780 * element. An example of this can be found in Roo.dd.DDProxy
14781 * @method getDragEl
14782 * @return {HTMLElement} the html element
14784 getDragEl: function() {
14785 return Roo.getDom(this.dragElId);
14789 * Sets up the DragDrop object. Must be called in the constructor of any
14790 * Roo.dd.DragDrop subclass
14792 * @param id the id of the linked element
14793 * @param {String} sGroup the group of related items
14794 * @param {object} config configuration attributes
14796 init: function(id, sGroup, config) {
14797 this.initTarget(id, sGroup, config);
14798 Event.on(this.id, "mousedown", this.handleMouseDown, this);
14799 // Event.on(this.id, "selectstart", Event.preventDefault);
14803 * Initializes Targeting functionality only... the object does not
14804 * get a mousedown handler.
14805 * @method initTarget
14806 * @param id the id of the linked element
14807 * @param {String} sGroup the group of related items
14808 * @param {object} config configuration attributes
14810 initTarget: function(id, sGroup, config) {
14812 // configuration attributes
14813 this.config = config || {};
14815 // create a local reference to the drag and drop manager
14816 this.DDM = Roo.dd.DDM;
14817 // initialize the groups array
14820 // assume that we have an element reference instead of an id if the
14821 // parameter is not a string
14822 if (typeof id !== "string") {
14829 // add to an interaction group
14830 this.addToGroup((sGroup) ? sGroup : "default");
14832 // We don't want to register this as the handle with the manager
14833 // so we just set the id rather than calling the setter.
14834 this.handleElId = id;
14836 // the linked element is the element that gets dragged by default
14837 this.setDragElId(id);
14839 // by default, clicked anchors will not start drag operations.
14840 this.invalidHandleTypes = { A: "A" };
14841 this.invalidHandleIds = {};
14842 this.invalidHandleClasses = [];
14844 this.applyConfig();
14846 this.handleOnAvailable();
14850 * Applies the configuration parameters that were passed into the constructor.
14851 * This is supposed to happen at each level through the inheritance chain. So
14852 * a DDProxy implentation will execute apply config on DDProxy, DD, and
14853 * DragDrop in order to get all of the parameters that are available in
14855 * @method applyConfig
14857 applyConfig: function() {
14859 // configurable properties:
14860 // padding, isTarget, maintainOffset, primaryButtonOnly
14861 this.padding = this.config.padding || [0, 0, 0, 0];
14862 this.isTarget = (this.config.isTarget !== false);
14863 this.maintainOffset = (this.config.maintainOffset);
14864 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
14869 * Executed when the linked element is available
14870 * @method handleOnAvailable
14873 handleOnAvailable: function() {
14874 this.available = true;
14875 this.resetConstraints();
14876 this.onAvailable();
14880 * Configures the padding for the target zone in px. Effectively expands
14881 * (or reduces) the virtual object size for targeting calculations.
14882 * Supports css-style shorthand; if only one parameter is passed, all sides
14883 * will have that padding, and if only two are passed, the top and bottom
14884 * will have the first param, the left and right the second.
14885 * @method setPadding
14886 * @param {int} iTop Top pad
14887 * @param {int} iRight Right pad
14888 * @param {int} iBot Bot pad
14889 * @param {int} iLeft Left pad
14891 setPadding: function(iTop, iRight, iBot, iLeft) {
14892 // this.padding = [iLeft, iRight, iTop, iBot];
14893 if (!iRight && 0 !== iRight) {
14894 this.padding = [iTop, iTop, iTop, iTop];
14895 } else if (!iBot && 0 !== iBot) {
14896 this.padding = [iTop, iRight, iTop, iRight];
14898 this.padding = [iTop, iRight, iBot, iLeft];
14903 * Stores the initial placement of the linked element.
14904 * @method setInitialPosition
14905 * @param {int} diffX the X offset, default 0
14906 * @param {int} diffY the Y offset, default 0
14908 setInitPosition: function(diffX, diffY) {
14909 var el = this.getEl();
14911 if (!this.DDM.verifyEl(el)) {
14915 var dx = diffX || 0;
14916 var dy = diffY || 0;
14918 var p = Dom.getXY( el );
14920 this.initPageX = p[0] - dx;
14921 this.initPageY = p[1] - dy;
14923 this.lastPageX = p[0];
14924 this.lastPageY = p[1];
14927 this.setStartPosition(p);
14931 * Sets the start position of the element. This is set when the obj
14932 * is initialized, the reset when a drag is started.
14933 * @method setStartPosition
14934 * @param pos current position (from previous lookup)
14937 setStartPosition: function(pos) {
14938 var p = pos || Dom.getXY( this.getEl() );
14939 this.deltaSetXY = null;
14941 this.startPageX = p[0];
14942 this.startPageY = p[1];
14946 * Add this instance to a group of related drag/drop objects. All
14947 * instances belong to at least one group, and can belong to as many
14948 * groups as needed.
14949 * @method addToGroup
14950 * @param sGroup {string} the name of the group
14952 addToGroup: function(sGroup) {
14953 this.groups[sGroup] = true;
14954 this.DDM.regDragDrop(this, sGroup);
14958 * Remove's this instance from the supplied interaction group
14959 * @method removeFromGroup
14960 * @param {string} sGroup The group to drop
14962 removeFromGroup: function(sGroup) {
14963 if (this.groups[sGroup]) {
14964 delete this.groups[sGroup];
14967 this.DDM.removeDDFromGroup(this, sGroup);
14971 * Allows you to specify that an element other than the linked element
14972 * will be moved with the cursor during a drag
14973 * @method setDragElId
14974 * @param id {string} the id of the element that will be used to initiate the drag
14976 setDragElId: function(id) {
14977 this.dragElId = id;
14981 * Allows you to specify a child of the linked element that should be
14982 * used to initiate the drag operation. An example of this would be if
14983 * you have a content div with text and links. Clicking anywhere in the
14984 * content area would normally start the drag operation. Use this method
14985 * to specify that an element inside of the content div is the element
14986 * that starts the drag operation.
14987 * @method setHandleElId
14988 * @param id {string} the id of the element that will be used to
14989 * initiate the drag.
14991 setHandleElId: function(id) {
14992 if (typeof id !== "string") {
14995 this.handleElId = id;
14996 this.DDM.regHandle(this.id, id);
15000 * Allows you to set an element outside of the linked element as a drag
15002 * @method setOuterHandleElId
15003 * @param id the id of the element that will be used to initiate the drag
15005 setOuterHandleElId: function(id) {
15006 if (typeof id !== "string") {
15009 Event.on(id, "mousedown",
15010 this.handleMouseDown, this);
15011 this.setHandleElId(id);
15013 this.hasOuterHandles = true;
15017 * Remove all drag and drop hooks for this element
15020 unreg: function() {
15021 Event.un(this.id, "mousedown",
15022 this.handleMouseDown);
15023 this._domRef = null;
15024 this.DDM._remove(this);
15027 destroy : function(){
15032 * Returns true if this instance is locked, or the drag drop mgr is locked
15033 * (meaning that all drag/drop is disabled on the page.)
15035 * @return {boolean} true if this obj or all drag/drop is locked, else
15038 isLocked: function() {
15039 return (this.DDM.isLocked() || this.locked);
15043 * Fired when this object is clicked
15044 * @method handleMouseDown
15046 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15049 handleMouseDown: function(e, oDD){
15050 if (this.primaryButtonOnly && e.button != 0) {
15054 if (this.isLocked()) {
15058 this.DDM.refreshCache(this.groups);
15060 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15061 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15063 if (this.clickValidator(e)) {
15065 // set the initial element position
15066 this.setStartPosition();
15069 this.b4MouseDown(e);
15070 this.onMouseDown(e);
15072 this.DDM.handleMouseDown(e, this);
15074 this.DDM.stopEvent(e);
15082 clickValidator: function(e) {
15083 var target = e.getTarget();
15084 return ( this.isValidHandleChild(target) &&
15085 (this.id == this.handleElId ||
15086 this.DDM.handleWasClicked(target, this.id)) );
15090 * Allows you to specify a tag name that should not start a drag operation
15091 * when clicked. This is designed to facilitate embedding links within a
15092 * drag handle that do something other than start the drag.
15093 * @method addInvalidHandleType
15094 * @param {string} tagName the type of element to exclude
15096 addInvalidHandleType: function(tagName) {
15097 var type = tagName.toUpperCase();
15098 this.invalidHandleTypes[type] = type;
15102 * Lets you to specify an element id for a child of a drag handle
15103 * that should not initiate a drag
15104 * @method addInvalidHandleId
15105 * @param {string} id the element id of the element you wish to ignore
15107 addInvalidHandleId: function(id) {
15108 if (typeof id !== "string") {
15111 this.invalidHandleIds[id] = id;
15115 * Lets you specify a css class of elements that will not initiate a drag
15116 * @method addInvalidHandleClass
15117 * @param {string} cssClass the class of the elements you wish to ignore
15119 addInvalidHandleClass: function(cssClass) {
15120 this.invalidHandleClasses.push(cssClass);
15124 * Unsets an excluded tag name set by addInvalidHandleType
15125 * @method removeInvalidHandleType
15126 * @param {string} tagName the type of element to unexclude
15128 removeInvalidHandleType: function(tagName) {
15129 var type = tagName.toUpperCase();
15130 // this.invalidHandleTypes[type] = null;
15131 delete this.invalidHandleTypes[type];
15135 * Unsets an invalid handle id
15136 * @method removeInvalidHandleId
15137 * @param {string} id the id of the element to re-enable
15139 removeInvalidHandleId: function(id) {
15140 if (typeof id !== "string") {
15143 delete this.invalidHandleIds[id];
15147 * Unsets an invalid css class
15148 * @method removeInvalidHandleClass
15149 * @param {string} cssClass the class of the element(s) you wish to
15152 removeInvalidHandleClass: function(cssClass) {
15153 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15154 if (this.invalidHandleClasses[i] == cssClass) {
15155 delete this.invalidHandleClasses[i];
15161 * Checks the tag exclusion list to see if this click should be ignored
15162 * @method isValidHandleChild
15163 * @param {HTMLElement} node the HTMLElement to evaluate
15164 * @return {boolean} true if this is a valid tag type, false if not
15166 isValidHandleChild: function(node) {
15169 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15172 nodeName = node.nodeName.toUpperCase();
15174 nodeName = node.nodeName;
15176 valid = valid && !this.invalidHandleTypes[nodeName];
15177 valid = valid && !this.invalidHandleIds[node.id];
15179 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15180 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15189 * Create the array of horizontal tick marks if an interval was specified
15190 * in setXConstraint().
15191 * @method setXTicks
15194 setXTicks: function(iStartX, iTickSize) {
15196 this.xTickSize = iTickSize;
15200 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15202 this.xTicks[this.xTicks.length] = i;
15207 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15209 this.xTicks[this.xTicks.length] = i;
15214 this.xTicks.sort(this.DDM.numericSort) ;
15218 * Create the array of vertical tick marks if an interval was specified in
15219 * setYConstraint().
15220 * @method setYTicks
15223 setYTicks: function(iStartY, iTickSize) {
15225 this.yTickSize = iTickSize;
15229 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15231 this.yTicks[this.yTicks.length] = i;
15236 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15238 this.yTicks[this.yTicks.length] = i;
15243 this.yTicks.sort(this.DDM.numericSort) ;
15247 * By default, the element can be dragged any place on the screen. Use
15248 * this method to limit the horizontal travel of the element. Pass in
15249 * 0,0 for the parameters if you want to lock the drag to the y axis.
15250 * @method setXConstraint
15251 * @param {int} iLeft the number of pixels the element can move to the left
15252 * @param {int} iRight the number of pixels the element can move to the
15254 * @param {int} iTickSize optional parameter for specifying that the
15256 * should move iTickSize pixels at a time.
15258 setXConstraint: function(iLeft, iRight, iTickSize) {
15259 this.leftConstraint = iLeft;
15260 this.rightConstraint = iRight;
15262 this.minX = this.initPageX - iLeft;
15263 this.maxX = this.initPageX + iRight;
15264 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15266 this.constrainX = true;
15270 * Clears any constraints applied to this instance. Also clears ticks
15271 * since they can't exist independent of a constraint at this time.
15272 * @method clearConstraints
15274 clearConstraints: function() {
15275 this.constrainX = false;
15276 this.constrainY = false;
15281 * Clears any tick interval defined for this instance
15282 * @method clearTicks
15284 clearTicks: function() {
15285 this.xTicks = null;
15286 this.yTicks = null;
15287 this.xTickSize = 0;
15288 this.yTickSize = 0;
15292 * By default, the element can be dragged any place on the screen. Set
15293 * this to limit the vertical travel of the element. Pass in 0,0 for the
15294 * parameters if you want to lock the drag to the x axis.
15295 * @method setYConstraint
15296 * @param {int} iUp the number of pixels the element can move up
15297 * @param {int} iDown the number of pixels the element can move down
15298 * @param {int} iTickSize optional parameter for specifying that the
15299 * element should move iTickSize pixels at a time.
15301 setYConstraint: function(iUp, iDown, iTickSize) {
15302 this.topConstraint = iUp;
15303 this.bottomConstraint = iDown;
15305 this.minY = this.initPageY - iUp;
15306 this.maxY = this.initPageY + iDown;
15307 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15309 this.constrainY = true;
15314 * resetConstraints must be called if you manually reposition a dd element.
15315 * @method resetConstraints
15316 * @param {boolean} maintainOffset
15318 resetConstraints: function() {
15321 // Maintain offsets if necessary
15322 if (this.initPageX || this.initPageX === 0) {
15323 // figure out how much this thing has moved
15324 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15325 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15327 this.setInitPosition(dx, dy);
15329 // This is the first time we have detected the element's position
15331 this.setInitPosition();
15334 if (this.constrainX) {
15335 this.setXConstraint( this.leftConstraint,
15336 this.rightConstraint,
15340 if (this.constrainY) {
15341 this.setYConstraint( this.topConstraint,
15342 this.bottomConstraint,
15348 * Normally the drag element is moved pixel by pixel, but we can specify
15349 * that it move a number of pixels at a time. This method resolves the
15350 * location when we have it set up like this.
15352 * @param {int} val where we want to place the object
15353 * @param {int[]} tickArray sorted array of valid points
15354 * @return {int} the closest tick
15357 getTick: function(val, tickArray) {
15360 // If tick interval is not defined, it is effectively 1 pixel,
15361 // so we return the value passed to us.
15363 } else if (tickArray[0] >= val) {
15364 // The value is lower than the first tick, so we return the first
15366 return tickArray[0];
15368 for (var i=0, len=tickArray.length; i<len; ++i) {
15370 if (tickArray[next] && tickArray[next] >= val) {
15371 var diff1 = val - tickArray[i];
15372 var diff2 = tickArray[next] - val;
15373 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15377 // The value is larger than the last tick, so we return the last
15379 return tickArray[tickArray.length - 1];
15386 * @return {string} string representation of the dd obj
15388 toString: function() {
15389 return ("DragDrop " + this.id);
15397 * Ext JS Library 1.1.1
15398 * Copyright(c) 2006-2007, Ext JS, LLC.
15400 * Originally Released Under LGPL - original licence link has changed is not relivant.
15403 * <script type="text/javascript">
15408 * The drag and drop utility provides a framework for building drag and drop
15409 * applications. In addition to enabling drag and drop for specific elements,
15410 * the drag and drop elements are tracked by the manager class, and the
15411 * interactions between the various elements are tracked during the drag and
15412 * the implementing code is notified about these important moments.
15415 // Only load the library once. Rewriting the manager class would orphan
15416 // existing drag and drop instances.
15417 if (!Roo.dd.DragDropMgr) {
15420 * @class Roo.dd.DragDropMgr
15421 * DragDropMgr is a singleton that tracks the element interaction for
15422 * all DragDrop items in the window. Generally, you will not call
15423 * this class directly, but it does have helper methods that could
15424 * be useful in your DragDrop implementations.
15427 Roo.dd.DragDropMgr = function() {
15429 var Event = Roo.EventManager;
15434 * Two dimensional Array of registered DragDrop objects. The first
15435 * dimension is the DragDrop item group, the second the DragDrop
15438 * @type {string: string}
15445 * Array of element ids defined as drag handles. Used to determine
15446 * if the element that generated the mousedown event is actually the
15447 * handle and not the html element itself.
15448 * @property handleIds
15449 * @type {string: string}
15456 * the DragDrop object that is currently being dragged
15457 * @property dragCurrent
15465 * the DragDrop object(s) that are being hovered over
15466 * @property dragOvers
15474 * the X distance between the cursor and the object being dragged
15483 * the Y distance between the cursor and the object being dragged
15492 * Flag to determine if we should prevent the default behavior of the
15493 * events we define. By default this is true, but this can be set to
15494 * false if you need the default behavior (not recommended)
15495 * @property preventDefault
15499 preventDefault: true,
15502 * Flag to determine if we should stop the propagation of the events
15503 * we generate. This is true by default but you may want to set it to
15504 * false if the html element contains other features that require the
15506 * @property stopPropagation
15510 stopPropagation: true,
15513 * Internal flag that is set to true when drag and drop has been
15515 * @property initialized
15522 * All drag and drop can be disabled.
15530 * Called the first time an element is registered.
15536 this.initialized = true;
15540 * In point mode, drag and drop interaction is defined by the
15541 * location of the cursor during the drag/drop
15549 * In intersect mode, drag and drop interactio nis defined by the
15550 * overlap of two or more drag and drop objects.
15551 * @property INTERSECT
15558 * The current drag and drop mode. Default: POINT
15566 * Runs method on all drag and drop objects
15567 * @method _execOnAll
15571 _execOnAll: function(sMethod, args) {
15572 for (var i in this.ids) {
15573 for (var j in this.ids[i]) {
15574 var oDD = this.ids[i][j];
15575 if (! this.isTypeOfDD(oDD)) {
15578 oDD[sMethod].apply(oDD, args);
15584 * Drag and drop initialization. Sets up the global event handlers
15589 _onLoad: function() {
15594 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15595 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15596 Event.on(window, "unload", this._onUnload, this, true);
15597 Event.on(window, "resize", this._onResize, this, true);
15598 // Event.on(window, "mouseout", this._test);
15603 * Reset constraints on all drag and drop objs
15604 * @method _onResize
15608 _onResize: function(e) {
15609 this._execOnAll("resetConstraints", []);
15613 * Lock all drag and drop functionality
15617 lock: function() { this.locked = true; },
15620 * Unlock all drag and drop functionality
15624 unlock: function() { this.locked = false; },
15627 * Is drag and drop locked?
15629 * @return {boolean} True if drag and drop is locked, false otherwise.
15632 isLocked: function() { return this.locked; },
15635 * Location cache that is set for all drag drop objects when a drag is
15636 * initiated, cleared when the drag is finished.
15637 * @property locationCache
15644 * Set useCache to false if you want to force object the lookup of each
15645 * drag and drop linked element constantly during a drag.
15646 * @property useCache
15653 * The number of pixels that the mouse needs to move after the
15654 * mousedown before the drag is initiated. Default=3;
15655 * @property clickPixelThresh
15659 clickPixelThresh: 3,
15662 * The number of milliseconds after the mousedown event to initiate the
15663 * drag if we don't get a mouseup event. Default=1000
15664 * @property clickTimeThresh
15668 clickTimeThresh: 350,
15671 * Flag that indicates that either the drag pixel threshold or the
15672 * mousdown time threshold has been met
15673 * @property dragThreshMet
15678 dragThreshMet: false,
15681 * Timeout used for the click time threshold
15682 * @property clickTimeout
15687 clickTimeout: null,
15690 * The X position of the mousedown event stored for later use when a
15691 * drag threshold is met.
15700 * The Y position of the mousedown event stored for later use when a
15701 * drag threshold is met.
15710 * Each DragDrop instance must be registered with the DragDropMgr.
15711 * This is executed in DragDrop.init()
15712 * @method regDragDrop
15713 * @param {DragDrop} oDD the DragDrop object to register
15714 * @param {String} sGroup the name of the group this element belongs to
15717 regDragDrop: function(oDD, sGroup) {
15718 if (!this.initialized) { this.init(); }
15720 if (!this.ids[sGroup]) {
15721 this.ids[sGroup] = {};
15723 this.ids[sGroup][oDD.id] = oDD;
15727 * Removes the supplied dd instance from the supplied group. Executed
15728 * by DragDrop.removeFromGroup, so don't call this function directly.
15729 * @method removeDDFromGroup
15733 removeDDFromGroup: function(oDD, sGroup) {
15734 if (!this.ids[sGroup]) {
15735 this.ids[sGroup] = {};
15738 var obj = this.ids[sGroup];
15739 if (obj && obj[oDD.id]) {
15740 delete obj[oDD.id];
15745 * Unregisters a drag and drop item. This is executed in
15746 * DragDrop.unreg, use that method instead of calling this directly.
15751 _remove: function(oDD) {
15752 for (var g in oDD.groups) {
15753 if (g && this.ids[g][oDD.id]) {
15754 delete this.ids[g][oDD.id];
15757 delete this.handleIds[oDD.id];
15761 * Each DragDrop handle element must be registered. This is done
15762 * automatically when executing DragDrop.setHandleElId()
15763 * @method regHandle
15764 * @param {String} sDDId the DragDrop id this element is a handle for
15765 * @param {String} sHandleId the id of the element that is the drag
15769 regHandle: function(sDDId, sHandleId) {
15770 if (!this.handleIds[sDDId]) {
15771 this.handleIds[sDDId] = {};
15773 this.handleIds[sDDId][sHandleId] = sHandleId;
15777 * Utility function to determine if a given element has been
15778 * registered as a drag drop item.
15779 * @method isDragDrop
15780 * @param {String} id the element id to check
15781 * @return {boolean} true if this element is a DragDrop item,
15785 isDragDrop: function(id) {
15786 return ( this.getDDById(id) ) ? true : false;
15790 * Returns the drag and drop instances that are in all groups the
15791 * passed in instance belongs to.
15792 * @method getRelated
15793 * @param {DragDrop} p_oDD the obj to get related data for
15794 * @param {boolean} bTargetsOnly if true, only return targetable objs
15795 * @return {DragDrop[]} the related instances
15798 getRelated: function(p_oDD, bTargetsOnly) {
15800 for (var i in p_oDD.groups) {
15801 for (j in this.ids[i]) {
15802 var dd = this.ids[i][j];
15803 if (! this.isTypeOfDD(dd)) {
15806 if (!bTargetsOnly || dd.isTarget) {
15807 oDDs[oDDs.length] = dd;
15816 * Returns true if the specified dd target is a legal target for
15817 * the specifice drag obj
15818 * @method isLegalTarget
15819 * @param {DragDrop} the drag obj
15820 * @param {DragDrop} the target
15821 * @return {boolean} true if the target is a legal target for the
15825 isLegalTarget: function (oDD, oTargetDD) {
15826 var targets = this.getRelated(oDD, true);
15827 for (var i=0, len=targets.length;i<len;++i) {
15828 if (targets[i].id == oTargetDD.id) {
15837 * My goal is to be able to transparently determine if an object is
15838 * typeof DragDrop, and the exact subclass of DragDrop. typeof
15839 * returns "object", oDD.constructor.toString() always returns
15840 * "DragDrop" and not the name of the subclass. So for now it just
15841 * evaluates a well-known variable in DragDrop.
15842 * @method isTypeOfDD
15843 * @param {Object} the object to evaluate
15844 * @return {boolean} true if typeof oDD = DragDrop
15847 isTypeOfDD: function (oDD) {
15848 return (oDD && oDD.__ygDragDrop);
15852 * Utility function to determine if a given element has been
15853 * registered as a drag drop handle for the given Drag Drop object.
15855 * @param {String} id the element id to check
15856 * @return {boolean} true if this element is a DragDrop handle, false
15860 isHandle: function(sDDId, sHandleId) {
15861 return ( this.handleIds[sDDId] &&
15862 this.handleIds[sDDId][sHandleId] );
15866 * Returns the DragDrop instance for a given id
15867 * @method getDDById
15868 * @param {String} id the id of the DragDrop object
15869 * @return {DragDrop} the drag drop object, null if it is not found
15872 getDDById: function(id) {
15873 for (var i in this.ids) {
15874 if (this.ids[i][id]) {
15875 return this.ids[i][id];
15882 * Fired after a registered DragDrop object gets the mousedown event.
15883 * Sets up the events required to track the object being dragged
15884 * @method handleMouseDown
15885 * @param {Event} e the event
15886 * @param oDD the DragDrop object being dragged
15890 handleMouseDown: function(e, oDD) {
15892 Roo.QuickTips.disable();
15894 this.currentTarget = e.getTarget();
15896 this.dragCurrent = oDD;
15898 var el = oDD.getEl();
15900 // track start position
15901 this.startX = e.getPageX();
15902 this.startY = e.getPageY();
15904 this.deltaX = this.startX - el.offsetLeft;
15905 this.deltaY = this.startY - el.offsetTop;
15907 this.dragThreshMet = false;
15909 this.clickTimeout = setTimeout(
15911 var DDM = Roo.dd.DDM;
15912 DDM.startDrag(DDM.startX, DDM.startY);
15914 this.clickTimeThresh );
15918 * Fired when either the drag pixel threshol or the mousedown hold
15919 * time threshold has been met.
15920 * @method startDrag
15921 * @param x {int} the X position of the original mousedown
15922 * @param y {int} the Y position of the original mousedown
15925 startDrag: function(x, y) {
15926 clearTimeout(this.clickTimeout);
15927 if (this.dragCurrent) {
15928 this.dragCurrent.b4StartDrag(x, y);
15929 this.dragCurrent.startDrag(x, y);
15931 this.dragThreshMet = true;
15935 * Internal function to handle the mouseup event. Will be invoked
15936 * from the context of the document.
15937 * @method handleMouseUp
15938 * @param {Event} e the event
15942 handleMouseUp: function(e) {
15945 Roo.QuickTips.enable();
15947 if (! this.dragCurrent) {
15951 clearTimeout(this.clickTimeout);
15953 if (this.dragThreshMet) {
15954 this.fireEvents(e, true);
15964 * Utility to stop event propagation and event default, if these
15965 * features are turned on.
15966 * @method stopEvent
15967 * @param {Event} e the event as returned by this.getEvent()
15970 stopEvent: function(e){
15971 if(this.stopPropagation) {
15972 e.stopPropagation();
15975 if (this.preventDefault) {
15976 e.preventDefault();
15981 * Internal function to clean up event handlers after the drag
15982 * operation is complete
15984 * @param {Event} e the event
15988 stopDrag: function(e) {
15989 // Fire the drag end event for the item that was dragged
15990 if (this.dragCurrent) {
15991 if (this.dragThreshMet) {
15992 this.dragCurrent.b4EndDrag(e);
15993 this.dragCurrent.endDrag(e);
15996 this.dragCurrent.onMouseUp(e);
15999 this.dragCurrent = null;
16000 this.dragOvers = {};
16004 * Internal function to handle the mousemove event. Will be invoked
16005 * from the context of the html element.
16007 * @TODO figure out what we can do about mouse events lost when the
16008 * user drags objects beyond the window boundary. Currently we can
16009 * detect this in internet explorer by verifying that the mouse is
16010 * down during the mousemove event. Firefox doesn't give us the
16011 * button state on the mousemove event.
16012 * @method handleMouseMove
16013 * @param {Event} e the event
16017 handleMouseMove: function(e) {
16018 if (! this.dragCurrent) {
16022 // var button = e.which || e.button;
16024 // check for IE mouseup outside of page boundary
16025 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16027 return this.handleMouseUp(e);
16030 if (!this.dragThreshMet) {
16031 var diffX = Math.abs(this.startX - e.getPageX());
16032 var diffY = Math.abs(this.startY - e.getPageY());
16033 if (diffX > this.clickPixelThresh ||
16034 diffY > this.clickPixelThresh) {
16035 this.startDrag(this.startX, this.startY);
16039 if (this.dragThreshMet) {
16040 this.dragCurrent.b4Drag(e);
16041 this.dragCurrent.onDrag(e);
16042 if(!this.dragCurrent.moveOnly){
16043 this.fireEvents(e, false);
16053 * Iterates over all of the DragDrop elements to find ones we are
16054 * hovering over or dropping on
16055 * @method fireEvents
16056 * @param {Event} e the event
16057 * @param {boolean} isDrop is this a drop op or a mouseover op?
16061 fireEvents: function(e, isDrop) {
16062 var dc = this.dragCurrent;
16064 // If the user did the mouse up outside of the window, we could
16065 // get here even though we have ended the drag.
16066 if (!dc || dc.isLocked()) {
16070 var pt = e.getPoint();
16072 // cache the previous dragOver array
16078 var enterEvts = [];
16080 // Check to see if the object(s) we were hovering over is no longer
16081 // being hovered over so we can fire the onDragOut event
16082 for (var i in this.dragOvers) {
16084 var ddo = this.dragOvers[i];
16086 if (! this.isTypeOfDD(ddo)) {
16090 if (! this.isOverTarget(pt, ddo, this.mode)) {
16091 outEvts.push( ddo );
16094 oldOvers[i] = true;
16095 delete this.dragOvers[i];
16098 for (var sGroup in dc.groups) {
16100 if ("string" != typeof sGroup) {
16104 for (i in this.ids[sGroup]) {
16105 var oDD = this.ids[sGroup][i];
16106 if (! this.isTypeOfDD(oDD)) {
16110 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16111 if (this.isOverTarget(pt, oDD, this.mode)) {
16112 // look for drop interactions
16114 dropEvts.push( oDD );
16115 // look for drag enter and drag over interactions
16118 // initial drag over: dragEnter fires
16119 if (!oldOvers[oDD.id]) {
16120 enterEvts.push( oDD );
16121 // subsequent drag overs: dragOver fires
16123 overEvts.push( oDD );
16126 this.dragOvers[oDD.id] = oDD;
16134 if (outEvts.length) {
16135 dc.b4DragOut(e, outEvts);
16136 dc.onDragOut(e, outEvts);
16139 if (enterEvts.length) {
16140 dc.onDragEnter(e, enterEvts);
16143 if (overEvts.length) {
16144 dc.b4DragOver(e, overEvts);
16145 dc.onDragOver(e, overEvts);
16148 if (dropEvts.length) {
16149 dc.b4DragDrop(e, dropEvts);
16150 dc.onDragDrop(e, dropEvts);
16154 // fire dragout events
16156 for (i=0, len=outEvts.length; i<len; ++i) {
16157 dc.b4DragOut(e, outEvts[i].id);
16158 dc.onDragOut(e, outEvts[i].id);
16161 // fire enter events
16162 for (i=0,len=enterEvts.length; i<len; ++i) {
16163 // dc.b4DragEnter(e, oDD.id);
16164 dc.onDragEnter(e, enterEvts[i].id);
16167 // fire over events
16168 for (i=0,len=overEvts.length; i<len; ++i) {
16169 dc.b4DragOver(e, overEvts[i].id);
16170 dc.onDragOver(e, overEvts[i].id);
16173 // fire drop events
16174 for (i=0, len=dropEvts.length; i<len; ++i) {
16175 dc.b4DragDrop(e, dropEvts[i].id);
16176 dc.onDragDrop(e, dropEvts[i].id);
16181 // notify about a drop that did not find a target
16182 if (isDrop && !dropEvts.length) {
16183 dc.onInvalidDrop(e);
16189 * Helper function for getting the best match from the list of drag
16190 * and drop objects returned by the drag and drop events when we are
16191 * in INTERSECT mode. It returns either the first object that the
16192 * cursor is over, or the object that has the greatest overlap with
16193 * the dragged element.
16194 * @method getBestMatch
16195 * @param {DragDrop[]} dds The array of drag and drop objects
16197 * @return {DragDrop} The best single match
16200 getBestMatch: function(dds) {
16202 // Return null if the input is not what we expect
16203 //if (!dds || !dds.length || dds.length == 0) {
16205 // If there is only one item, it wins
16206 //} else if (dds.length == 1) {
16208 var len = dds.length;
16213 // Loop through the targeted items
16214 for (var i=0; i<len; ++i) {
16216 // If the cursor is over the object, it wins. If the
16217 // cursor is over multiple matches, the first one we come
16219 if (dd.cursorIsOver) {
16222 // Otherwise the object with the most overlap wins
16225 winner.overlap.getArea() < dd.overlap.getArea()) {
16236 * Refreshes the cache of the top-left and bottom-right points of the
16237 * drag and drop objects in the specified group(s). This is in the
16238 * format that is stored in the drag and drop instance, so typical
16241 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16245 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16247 * @TODO this really should be an indexed array. Alternatively this
16248 * method could accept both.
16249 * @method refreshCache
16250 * @param {Object} groups an associative array of groups to refresh
16253 refreshCache: function(groups) {
16254 for (var sGroup in groups) {
16255 if ("string" != typeof sGroup) {
16258 for (var i in this.ids[sGroup]) {
16259 var oDD = this.ids[sGroup][i];
16261 if (this.isTypeOfDD(oDD)) {
16262 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16263 var loc = this.getLocation(oDD);
16265 this.locationCache[oDD.id] = loc;
16267 delete this.locationCache[oDD.id];
16268 // this will unregister the drag and drop object if
16269 // the element is not in a usable state
16278 * This checks to make sure an element exists and is in the DOM. The
16279 * main purpose is to handle cases where innerHTML is used to remove
16280 * drag and drop objects from the DOM. IE provides an 'unspecified
16281 * error' when trying to access the offsetParent of such an element
16283 * @param {HTMLElement} el the element to check
16284 * @return {boolean} true if the element looks usable
16287 verifyEl: function(el) {
16292 parent = el.offsetParent;
16295 parent = el.offsetParent;
16306 * Returns a Region object containing the drag and drop element's position
16307 * and size, including the padding configured for it
16308 * @method getLocation
16309 * @param {DragDrop} oDD the drag and drop object to get the
16311 * @return {Roo.lib.Region} a Region object representing the total area
16312 * the element occupies, including any padding
16313 * the instance is configured for.
16316 getLocation: function(oDD) {
16317 if (! this.isTypeOfDD(oDD)) {
16321 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16324 pos= Roo.lib.Dom.getXY(el);
16332 x2 = x1 + el.offsetWidth;
16334 y2 = y1 + el.offsetHeight;
16336 t = y1 - oDD.padding[0];
16337 r = x2 + oDD.padding[1];
16338 b = y2 + oDD.padding[2];
16339 l = x1 - oDD.padding[3];
16341 return new Roo.lib.Region( t, r, b, l );
16345 * Checks the cursor location to see if it over the target
16346 * @method isOverTarget
16347 * @param {Roo.lib.Point} pt The point to evaluate
16348 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16349 * @return {boolean} true if the mouse is over the target
16353 isOverTarget: function(pt, oTarget, intersect) {
16354 // use cache if available
16355 var loc = this.locationCache[oTarget.id];
16356 if (!loc || !this.useCache) {
16357 loc = this.getLocation(oTarget);
16358 this.locationCache[oTarget.id] = loc;
16366 oTarget.cursorIsOver = loc.contains( pt );
16368 // DragDrop is using this as a sanity check for the initial mousedown
16369 // in this case we are done. In POINT mode, if the drag obj has no
16370 // contraints, we are also done. Otherwise we need to evaluate the
16371 // location of the target as related to the actual location of the
16372 // dragged element.
16373 var dc = this.dragCurrent;
16374 if (!dc || !dc.getTargetCoord ||
16375 (!intersect && !dc.constrainX && !dc.constrainY)) {
16376 return oTarget.cursorIsOver;
16379 oTarget.overlap = null;
16381 // Get the current location of the drag element, this is the
16382 // location of the mouse event less the delta that represents
16383 // where the original mousedown happened on the element. We
16384 // need to consider constraints and ticks as well.
16385 var pos = dc.getTargetCoord(pt.x, pt.y);
16387 var el = dc.getDragEl();
16388 var curRegion = new Roo.lib.Region( pos.y,
16389 pos.x + el.offsetWidth,
16390 pos.y + el.offsetHeight,
16393 var overlap = curRegion.intersect(loc);
16396 oTarget.overlap = overlap;
16397 return (intersect) ? true : oTarget.cursorIsOver;
16404 * unload event handler
16405 * @method _onUnload
16409 _onUnload: function(e, me) {
16410 Roo.dd.DragDropMgr.unregAll();
16414 * Cleans up the drag and drop events and objects.
16419 unregAll: function() {
16421 if (this.dragCurrent) {
16423 this.dragCurrent = null;
16426 this._execOnAll("unreg", []);
16428 for (i in this.elementCache) {
16429 delete this.elementCache[i];
16432 this.elementCache = {};
16437 * A cache of DOM elements
16438 * @property elementCache
16445 * Get the wrapper for the DOM element specified
16446 * @method getElWrapper
16447 * @param {String} id the id of the element to get
16448 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16450 * @deprecated This wrapper isn't that useful
16453 getElWrapper: function(id) {
16454 var oWrapper = this.elementCache[id];
16455 if (!oWrapper || !oWrapper.el) {
16456 oWrapper = this.elementCache[id] =
16457 new this.ElementWrapper(Roo.getDom(id));
16463 * Returns the actual DOM element
16464 * @method getElement
16465 * @param {String} id the id of the elment to get
16466 * @return {Object} The element
16467 * @deprecated use Roo.getDom instead
16470 getElement: function(id) {
16471 return Roo.getDom(id);
16475 * Returns the style property for the DOM element (i.e.,
16476 * document.getElById(id).style)
16478 * @param {String} id the id of the elment to get
16479 * @return {Object} The style property of the element
16480 * @deprecated use Roo.getDom instead
16483 getCss: function(id) {
16484 var el = Roo.getDom(id);
16485 return (el) ? el.style : null;
16489 * Inner class for cached elements
16490 * @class DragDropMgr.ElementWrapper
16495 ElementWrapper: function(el) {
16500 this.el = el || null;
16505 this.id = this.el && el.id;
16507 * A reference to the style property
16510 this.css = this.el && el.style;
16514 * Returns the X position of an html element
16516 * @param el the element for which to get the position
16517 * @return {int} the X coordinate
16519 * @deprecated use Roo.lib.Dom.getX instead
16522 getPosX: function(el) {
16523 return Roo.lib.Dom.getX(el);
16527 * Returns the Y position of an html element
16529 * @param el the element for which to get the position
16530 * @return {int} the Y coordinate
16531 * @deprecated use Roo.lib.Dom.getY instead
16534 getPosY: function(el) {
16535 return Roo.lib.Dom.getY(el);
16539 * Swap two nodes. In IE, we use the native method, for others we
16540 * emulate the IE behavior
16542 * @param n1 the first node to swap
16543 * @param n2 the other node to swap
16546 swapNode: function(n1, n2) {
16550 var p = n2.parentNode;
16551 var s = n2.nextSibling;
16554 p.insertBefore(n1, n2);
16555 } else if (n2 == n1.nextSibling) {
16556 p.insertBefore(n2, n1);
16558 n1.parentNode.replaceChild(n2, n1);
16559 p.insertBefore(n1, s);
16565 * Returns the current scroll position
16566 * @method getScroll
16570 getScroll: function () {
16571 var t, l, dde=document.documentElement, db=document.body;
16572 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16574 l = dde.scrollLeft;
16581 return { top: t, left: l };
16585 * Returns the specified element style property
16587 * @param {HTMLElement} el the element
16588 * @param {string} styleProp the style property
16589 * @return {string} The value of the style property
16590 * @deprecated use Roo.lib.Dom.getStyle
16593 getStyle: function(el, styleProp) {
16594 return Roo.fly(el).getStyle(styleProp);
16598 * Gets the scrollTop
16599 * @method getScrollTop
16600 * @return {int} the document's scrollTop
16603 getScrollTop: function () { return this.getScroll().top; },
16606 * Gets the scrollLeft
16607 * @method getScrollLeft
16608 * @return {int} the document's scrollTop
16611 getScrollLeft: function () { return this.getScroll().left; },
16614 * Sets the x/y position of an element to the location of the
16617 * @param {HTMLElement} moveEl The element to move
16618 * @param {HTMLElement} targetEl The position reference element
16621 moveToEl: function (moveEl, targetEl) {
16622 var aCoord = Roo.lib.Dom.getXY(targetEl);
16623 Roo.lib.Dom.setXY(moveEl, aCoord);
16627 * Numeric array sort function
16628 * @method numericSort
16631 numericSort: function(a, b) { return (a - b); },
16635 * @property _timeoutCount
16642 * Trying to make the load order less important. Without this we get
16643 * an error if this file is loaded before the Event Utility.
16644 * @method _addListeners
16648 _addListeners: function() {
16649 var DDM = Roo.dd.DDM;
16650 if ( Roo.lib.Event && document ) {
16653 if (DDM._timeoutCount > 2000) {
16655 setTimeout(DDM._addListeners, 10);
16656 if (document && document.body) {
16657 DDM._timeoutCount += 1;
16664 * Recursively searches the immediate parent and all child nodes for
16665 * the handle element in order to determine wheter or not it was
16667 * @method handleWasClicked
16668 * @param node the html element to inspect
16671 handleWasClicked: function(node, id) {
16672 if (this.isHandle(id, node.id)) {
16675 // check to see if this is a text node child of the one we want
16676 var p = node.parentNode;
16679 if (this.isHandle(id, p.id)) {
16694 // shorter alias, save a few bytes
16695 Roo.dd.DDM = Roo.dd.DragDropMgr;
16696 Roo.dd.DDM._addListeners();
16700 * Ext JS Library 1.1.1
16701 * Copyright(c) 2006-2007, Ext JS, LLC.
16703 * Originally Released Under LGPL - original licence link has changed is not relivant.
16706 * <script type="text/javascript">
16711 * A DragDrop implementation where the linked element follows the
16712 * mouse cursor during a drag.
16713 * @extends Roo.dd.DragDrop
16715 * @param {String} id the id of the linked element
16716 * @param {String} sGroup the group of related DragDrop items
16717 * @param {object} config an object containing configurable attributes
16718 * Valid properties for DD:
16721 Roo.dd.DD = function(id, sGroup, config) {
16723 this.init(id, sGroup, config);
16727 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16730 * When set to true, the utility automatically tries to scroll the browser
16731 * window wehn a drag and drop element is dragged near the viewport boundary.
16732 * Defaults to true.
16739 * Sets the pointer offset to the distance between the linked element's top
16740 * left corner and the location the element was clicked
16741 * @method autoOffset
16742 * @param {int} iPageX the X coordinate of the click
16743 * @param {int} iPageY the Y coordinate of the click
16745 autoOffset: function(iPageX, iPageY) {
16746 var x = iPageX - this.startPageX;
16747 var y = iPageY - this.startPageY;
16748 this.setDelta(x, y);
16752 * Sets the pointer offset. You can call this directly to force the
16753 * offset to be in a particular location (e.g., pass in 0,0 to set it
16754 * to the center of the object)
16756 * @param {int} iDeltaX the distance from the left
16757 * @param {int} iDeltaY the distance from the top
16759 setDelta: function(iDeltaX, iDeltaY) {
16760 this.deltaX = iDeltaX;
16761 this.deltaY = iDeltaY;
16765 * Sets the drag element to the location of the mousedown or click event,
16766 * maintaining the cursor location relative to the location on the element
16767 * that was clicked. Override this if you want to place the element in a
16768 * location other than where the cursor is.
16769 * @method setDragElPos
16770 * @param {int} iPageX the X coordinate of the mousedown or drag event
16771 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16773 setDragElPos: function(iPageX, iPageY) {
16774 // the first time we do this, we are going to check to make sure
16775 // the element has css positioning
16777 var el = this.getDragEl();
16778 this.alignElWithMouse(el, iPageX, iPageY);
16782 * Sets the element to the location of the mousedown or click event,
16783 * maintaining the cursor location relative to the location on the element
16784 * that was clicked. Override this if you want to place the element in a
16785 * location other than where the cursor is.
16786 * @method alignElWithMouse
16787 * @param {HTMLElement} el the element to move
16788 * @param {int} iPageX the X coordinate of the mousedown or drag event
16789 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16791 alignElWithMouse: function(el, iPageX, iPageY) {
16792 var oCoord = this.getTargetCoord(iPageX, iPageY);
16793 var fly = el.dom ? el : Roo.fly(el);
16794 if (!this.deltaSetXY) {
16795 var aCoord = [oCoord.x, oCoord.y];
16797 var newLeft = fly.getLeft(true);
16798 var newTop = fly.getTop(true);
16799 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
16801 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
16804 this.cachePosition(oCoord.x, oCoord.y);
16805 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
16810 * Saves the most recent position so that we can reset the constraints and
16811 * tick marks on-demand. We need to know this so that we can calculate the
16812 * number of pixels the element is offset from its original position.
16813 * @method cachePosition
16814 * @param iPageX the current x position (optional, this just makes it so we
16815 * don't have to look it up again)
16816 * @param iPageY the current y position (optional, this just makes it so we
16817 * don't have to look it up again)
16819 cachePosition: function(iPageX, iPageY) {
16821 this.lastPageX = iPageX;
16822 this.lastPageY = iPageY;
16824 var aCoord = Roo.lib.Dom.getXY(this.getEl());
16825 this.lastPageX = aCoord[0];
16826 this.lastPageY = aCoord[1];
16831 * Auto-scroll the window if the dragged object has been moved beyond the
16832 * visible window boundary.
16833 * @method autoScroll
16834 * @param {int} x the drag element's x position
16835 * @param {int} y the drag element's y position
16836 * @param {int} h the height of the drag element
16837 * @param {int} w the width of the drag element
16840 autoScroll: function(x, y, h, w) {
16843 // The client height
16844 var clientH = Roo.lib.Dom.getViewWidth();
16846 // The client width
16847 var clientW = Roo.lib.Dom.getViewHeight();
16849 // The amt scrolled down
16850 var st = this.DDM.getScrollTop();
16852 // The amt scrolled right
16853 var sl = this.DDM.getScrollLeft();
16855 // Location of the bottom of the element
16858 // Location of the right of the element
16861 // The distance from the cursor to the bottom of the visible area,
16862 // adjusted so that we don't scroll if the cursor is beyond the
16863 // element drag constraints
16864 var toBot = (clientH + st - y - this.deltaY);
16866 // The distance from the cursor to the right of the visible area
16867 var toRight = (clientW + sl - x - this.deltaX);
16870 // How close to the edge the cursor must be before we scroll
16871 // var thresh = (document.all) ? 100 : 40;
16874 // How many pixels to scroll per autoscroll op. This helps to reduce
16875 // clunky scrolling. IE is more sensitive about this ... it needs this
16876 // value to be higher.
16877 var scrAmt = (document.all) ? 80 : 30;
16879 // Scroll down if we are near the bottom of the visible page and the
16880 // obj extends below the crease
16881 if ( bot > clientH && toBot < thresh ) {
16882 window.scrollTo(sl, st + scrAmt);
16885 // Scroll up if the window is scrolled down and the top of the object
16886 // goes above the top border
16887 if ( y < st && st > 0 && y - st < thresh ) {
16888 window.scrollTo(sl, st - scrAmt);
16891 // Scroll right if the obj is beyond the right border and the cursor is
16892 // near the border.
16893 if ( right > clientW && toRight < thresh ) {
16894 window.scrollTo(sl + scrAmt, st);
16897 // Scroll left if the window has been scrolled to the right and the obj
16898 // extends past the left border
16899 if ( x < sl && sl > 0 && x - sl < thresh ) {
16900 window.scrollTo(sl - scrAmt, st);
16906 * Finds the location the element should be placed if we want to move
16907 * it to where the mouse location less the click offset would place us.
16908 * @method getTargetCoord
16909 * @param {int} iPageX the X coordinate of the click
16910 * @param {int} iPageY the Y coordinate of the click
16911 * @return an object that contains the coordinates (Object.x and Object.y)
16914 getTargetCoord: function(iPageX, iPageY) {
16917 var x = iPageX - this.deltaX;
16918 var y = iPageY - this.deltaY;
16920 if (this.constrainX) {
16921 if (x < this.minX) { x = this.minX; }
16922 if (x > this.maxX) { x = this.maxX; }
16925 if (this.constrainY) {
16926 if (y < this.minY) { y = this.minY; }
16927 if (y > this.maxY) { y = this.maxY; }
16930 x = this.getTick(x, this.xTicks);
16931 y = this.getTick(y, this.yTicks);
16938 * Sets up config options specific to this class. Overrides
16939 * Roo.dd.DragDrop, but all versions of this method through the
16940 * inheritance chain are called
16942 applyConfig: function() {
16943 Roo.dd.DD.superclass.applyConfig.call(this);
16944 this.scroll = (this.config.scroll !== false);
16948 * Event that fires prior to the onMouseDown event. Overrides
16951 b4MouseDown: function(e) {
16952 // this.resetConstraints();
16953 this.autoOffset(e.getPageX(),
16958 * Event that fires prior to the onDrag event. Overrides
16961 b4Drag: function(e) {
16962 this.setDragElPos(e.getPageX(),
16966 toString: function() {
16967 return ("DD " + this.id);
16970 //////////////////////////////////////////////////////////////////////////
16971 // Debugging ygDragDrop events that can be overridden
16972 //////////////////////////////////////////////////////////////////////////
16974 startDrag: function(x, y) {
16977 onDrag: function(e) {
16980 onDragEnter: function(e, id) {
16983 onDragOver: function(e, id) {
16986 onDragOut: function(e, id) {
16989 onDragDrop: function(e, id) {
16992 endDrag: function(e) {
16999 * Ext JS Library 1.1.1
17000 * Copyright(c) 2006-2007, Ext JS, LLC.
17002 * Originally Released Under LGPL - original licence link has changed is not relivant.
17005 * <script type="text/javascript">
17009 * @class Roo.dd.DDProxy
17010 * A DragDrop implementation that inserts an empty, bordered div into
17011 * the document that follows the cursor during drag operations. At the time of
17012 * the click, the frame div is resized to the dimensions of the linked html
17013 * element, and moved to the exact location of the linked element.
17015 * References to the "frame" element refer to the single proxy element that
17016 * was created to be dragged in place of all DDProxy elements on the
17019 * @extends Roo.dd.DD
17021 * @param {String} id the id of the linked html element
17022 * @param {String} sGroup the group of related DragDrop objects
17023 * @param {object} config an object containing configurable attributes
17024 * Valid properties for DDProxy in addition to those in DragDrop:
17025 * resizeFrame, centerFrame, dragElId
17027 Roo.dd.DDProxy = function(id, sGroup, config) {
17029 this.init(id, sGroup, config);
17035 * The default drag frame div id
17036 * @property Roo.dd.DDProxy.dragElId
17040 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17042 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17045 * By default we resize the drag frame to be the same size as the element
17046 * we want to drag (this is to get the frame effect). We can turn it off
17047 * if we want a different behavior.
17048 * @property resizeFrame
17054 * By default the frame is positioned exactly where the drag element is, so
17055 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17056 * you do not have constraints on the obj is to have the drag frame centered
17057 * around the cursor. Set centerFrame to true for this effect.
17058 * @property centerFrame
17061 centerFrame: false,
17064 * Creates the proxy element if it does not yet exist
17065 * @method createFrame
17067 createFrame: function() {
17069 var body = document.body;
17071 if (!body || !body.firstChild) {
17072 setTimeout( function() { self.createFrame(); }, 50 );
17076 var div = this.getDragEl();
17079 div = document.createElement("div");
17080 div.id = this.dragElId;
17083 s.position = "absolute";
17084 s.visibility = "hidden";
17086 s.border = "2px solid #aaa";
17089 // appendChild can blow up IE if invoked prior to the window load event
17090 // while rendering a table. It is possible there are other scenarios
17091 // that would cause this to happen as well.
17092 body.insertBefore(div, body.firstChild);
17097 * Initialization for the drag frame element. Must be called in the
17098 * constructor of all subclasses
17099 * @method initFrame
17101 initFrame: function() {
17102 this.createFrame();
17105 applyConfig: function() {
17106 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17108 this.resizeFrame = (this.config.resizeFrame !== false);
17109 this.centerFrame = (this.config.centerFrame);
17110 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17114 * Resizes the drag frame to the dimensions of the clicked object, positions
17115 * it over the object, and finally displays it
17116 * @method showFrame
17117 * @param {int} iPageX X click position
17118 * @param {int} iPageY Y click position
17121 showFrame: function(iPageX, iPageY) {
17122 var el = this.getEl();
17123 var dragEl = this.getDragEl();
17124 var s = dragEl.style;
17126 this._resizeProxy();
17128 if (this.centerFrame) {
17129 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17130 Math.round(parseInt(s.height, 10)/2) );
17133 this.setDragElPos(iPageX, iPageY);
17135 Roo.fly(dragEl).show();
17139 * The proxy is automatically resized to the dimensions of the linked
17140 * element when a drag is initiated, unless resizeFrame is set to false
17141 * @method _resizeProxy
17144 _resizeProxy: function() {
17145 if (this.resizeFrame) {
17146 var el = this.getEl();
17147 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17151 // overrides Roo.dd.DragDrop
17152 b4MouseDown: function(e) {
17153 var x = e.getPageX();
17154 var y = e.getPageY();
17155 this.autoOffset(x, y);
17156 this.setDragElPos(x, y);
17159 // overrides Roo.dd.DragDrop
17160 b4StartDrag: function(x, y) {
17161 // show the drag frame
17162 this.showFrame(x, y);
17165 // overrides Roo.dd.DragDrop
17166 b4EndDrag: function(e) {
17167 Roo.fly(this.getDragEl()).hide();
17170 // overrides Roo.dd.DragDrop
17171 // By default we try to move the element to the last location of the frame.
17172 // This is so that the default behavior mirrors that of Roo.dd.DD.
17173 endDrag: function(e) {
17175 var lel = this.getEl();
17176 var del = this.getDragEl();
17178 // Show the drag frame briefly so we can get its position
17179 del.style.visibility = "";
17182 // Hide the linked element before the move to get around a Safari
17184 lel.style.visibility = "hidden";
17185 Roo.dd.DDM.moveToEl(lel, del);
17186 del.style.visibility = "hidden";
17187 lel.style.visibility = "";
17192 beforeMove : function(){
17196 afterDrag : function(){
17200 toString: function() {
17201 return ("DDProxy " + this.id);
17207 * Ext JS Library 1.1.1
17208 * Copyright(c) 2006-2007, Ext JS, LLC.
17210 * Originally Released Under LGPL - original licence link has changed is not relivant.
17213 * <script type="text/javascript">
17217 * @class Roo.dd.DDTarget
17218 * A DragDrop implementation that does not move, but can be a drop
17219 * target. You would get the same result by simply omitting implementation
17220 * for the event callbacks, but this way we reduce the processing cost of the
17221 * event listener and the callbacks.
17222 * @extends Roo.dd.DragDrop
17224 * @param {String} id the id of the element that is a drop target
17225 * @param {String} sGroup the group of related DragDrop objects
17226 * @param {object} config an object containing configurable attributes
17227 * Valid properties for DDTarget in addition to those in
17231 Roo.dd.DDTarget = function(id, sGroup, config) {
17233 this.initTarget(id, sGroup, config);
17237 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17238 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17239 toString: function() {
17240 return ("DDTarget " + this.id);
17245 * Ext JS Library 1.1.1
17246 * Copyright(c) 2006-2007, Ext JS, LLC.
17248 * Originally Released Under LGPL - original licence link has changed is not relivant.
17251 * <script type="text/javascript">
17256 * @class Roo.dd.ScrollManager
17257 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17258 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17261 Roo.dd.ScrollManager = function(){
17262 var ddm = Roo.dd.DragDropMgr;
17267 var onStop = function(e){
17272 var triggerRefresh = function(){
17273 if(ddm.dragCurrent){
17274 ddm.refreshCache(ddm.dragCurrent.groups);
17278 var doScroll = function(){
17279 if(ddm.dragCurrent){
17280 var dds = Roo.dd.ScrollManager;
17282 if(proc.el.scroll(proc.dir, dds.increment)){
17286 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17291 var clearProc = function(){
17293 clearInterval(proc.id);
17300 var startProc = function(el, dir){
17304 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17307 var onFire = function(e, isDrop){
17308 if(isDrop || !ddm.dragCurrent){ return; }
17309 var dds = Roo.dd.ScrollManager;
17310 if(!dragEl || dragEl != ddm.dragCurrent){
17311 dragEl = ddm.dragCurrent;
17312 // refresh regions on drag start
17313 dds.refreshCache();
17316 var xy = Roo.lib.Event.getXY(e);
17317 var pt = new Roo.lib.Point(xy[0], xy[1]);
17318 for(var id in els){
17319 var el = els[id], r = el._region;
17320 if(r && r.contains(pt) && el.isScrollable()){
17321 if(r.bottom - pt.y <= dds.thresh){
17323 startProc(el, "down");
17326 }else if(r.right - pt.x <= dds.thresh){
17328 startProc(el, "left");
17331 }else if(pt.y - r.top <= dds.thresh){
17333 startProc(el, "up");
17336 }else if(pt.x - r.left <= dds.thresh){
17338 startProc(el, "right");
17347 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17348 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17352 * Registers new overflow element(s) to auto scroll
17353 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17355 register : function(el){
17356 if(el instanceof Array){
17357 for(var i = 0, len = el.length; i < len; i++) {
17358 this.register(el[i]);
17367 * Unregisters overflow element(s) so they are no longer scrolled
17368 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17370 unregister : function(el){
17371 if(el instanceof Array){
17372 for(var i = 0, len = el.length; i < len; i++) {
17373 this.unregister(el[i]);
17382 * The number of pixels from the edge of a container the pointer needs to be to
17383 * trigger scrolling (defaults to 25)
17389 * The number of pixels to scroll in each scroll increment (defaults to 50)
17395 * The frequency of scrolls in milliseconds (defaults to 500)
17401 * True to animate the scroll (defaults to true)
17407 * The animation duration in seconds -
17408 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17414 * Manually trigger a cache refresh.
17416 refreshCache : function(){
17417 for(var id in els){
17418 if(typeof els[id] == 'object'){ // for people extending the object prototype
17419 els[id]._region = els[id].getRegion();
17426 * Ext JS Library 1.1.1
17427 * Copyright(c) 2006-2007, Ext JS, LLC.
17429 * Originally Released Under LGPL - original licence link has changed is not relivant.
17432 * <script type="text/javascript">
17437 * @class Roo.dd.Registry
17438 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17439 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17442 Roo.dd.Registry = function(){
17445 var autoIdSeed = 0;
17447 var getId = function(el, autogen){
17448 if(typeof el == "string"){
17452 if(!id && autogen !== false){
17453 id = "roodd-" + (++autoIdSeed);
17461 * Register a drag drop element
17462 * @param {String|HTMLElement} element The id or DOM node to register
17463 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17464 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17465 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17466 * populated in the data object (if applicable):
17468 Value Description<br />
17469 --------- ------------------------------------------<br />
17470 handles Array of DOM nodes that trigger dragging<br />
17471 for the element being registered<br />
17472 isHandle True if the element passed in triggers<br />
17473 dragging itself, else false
17476 register : function(el, data){
17478 if(typeof el == "string"){
17479 el = document.getElementById(el);
17482 elements[getId(el)] = data;
17483 if(data.isHandle !== false){
17484 handles[data.ddel.id] = data;
17487 var hs = data.handles;
17488 for(var i = 0, len = hs.length; i < len; i++){
17489 handles[getId(hs[i])] = data;
17495 * Unregister a drag drop element
17496 * @param {String|HTMLElement} element The id or DOM node to unregister
17498 unregister : function(el){
17499 var id = getId(el, false);
17500 var data = elements[id];
17502 delete elements[id];
17504 var hs = data.handles;
17505 for(var i = 0, len = hs.length; i < len; i++){
17506 delete handles[getId(hs[i], false)];
17513 * Returns the handle registered for a DOM Node by id
17514 * @param {String|HTMLElement} id The DOM node or id to look up
17515 * @return {Object} handle The custom handle data
17517 getHandle : function(id){
17518 if(typeof id != "string"){ // must be element?
17521 return handles[id];
17525 * Returns the handle that is registered for the DOM node that is the target of the event
17526 * @param {Event} e The event
17527 * @return {Object} handle The custom handle data
17529 getHandleFromEvent : function(e){
17530 var t = Roo.lib.Event.getTarget(e);
17531 return t ? handles[t.id] : null;
17535 * Returns a custom data object that is registered for a DOM node by id
17536 * @param {String|HTMLElement} id The DOM node or id to look up
17537 * @return {Object} data The custom data
17539 getTarget : function(id){
17540 if(typeof id != "string"){ // must be element?
17543 return elements[id];
17547 * Returns a custom data object that is registered for the DOM node that is the target of the event
17548 * @param {Event} e The event
17549 * @return {Object} data The custom data
17551 getTargetFromEvent : function(e){
17552 var t = Roo.lib.Event.getTarget(e);
17553 return t ? elements[t.id] || handles[t.id] : null;
17558 * Ext JS Library 1.1.1
17559 * Copyright(c) 2006-2007, Ext JS, LLC.
17561 * Originally Released Under LGPL - original licence link has changed is not relivant.
17564 * <script type="text/javascript">
17569 * @class Roo.dd.StatusProxy
17570 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17571 * default drag proxy used by all Roo.dd components.
17573 * @param {Object} config
17575 Roo.dd.StatusProxy = function(config){
17576 Roo.apply(this, config);
17577 this.id = this.id || Roo.id();
17578 this.el = new Roo.Layer({
17580 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17581 {tag: "div", cls: "x-dd-drop-icon"},
17582 {tag: "div", cls: "x-dd-drag-ghost"}
17585 shadow: !config || config.shadow !== false
17587 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17588 this.dropStatus = this.dropNotAllowed;
17591 Roo.dd.StatusProxy.prototype = {
17593 * @cfg {String} dropAllowed
17594 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17596 dropAllowed : "x-dd-drop-ok",
17598 * @cfg {String} dropNotAllowed
17599 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17601 dropNotAllowed : "x-dd-drop-nodrop",
17604 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17605 * over the current target element.
17606 * @param {String} cssClass The css class for the new drop status indicator image
17608 setStatus : function(cssClass){
17609 cssClass = cssClass || this.dropNotAllowed;
17610 if(this.dropStatus != cssClass){
17611 this.el.replaceClass(this.dropStatus, cssClass);
17612 this.dropStatus = cssClass;
17617 * Resets the status indicator to the default dropNotAllowed value
17618 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17620 reset : function(clearGhost){
17621 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17622 this.dropStatus = this.dropNotAllowed;
17624 this.ghost.update("");
17629 * Updates the contents of the ghost element
17630 * @param {String} html The html that will replace the current innerHTML of the ghost element
17632 update : function(html){
17633 if(typeof html == "string"){
17634 this.ghost.update(html);
17636 this.ghost.update("");
17637 html.style.margin = "0";
17638 this.ghost.dom.appendChild(html);
17640 // ensure float = none set?? cant remember why though.
17641 var el = this.ghost.dom.firstChild;
17643 Roo.fly(el).setStyle('float', 'none');
17648 * Returns the underlying proxy {@link Roo.Layer}
17649 * @return {Roo.Layer} el
17651 getEl : function(){
17656 * Returns the ghost element
17657 * @return {Roo.Element} el
17659 getGhost : function(){
17665 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17667 hide : function(clear){
17675 * Stops the repair animation if it's currently running
17678 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17684 * Displays this proxy
17691 * Force the Layer to sync its shadow and shim positions to the element
17698 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17699 * invalid drop operation by the item being dragged.
17700 * @param {Array} xy The XY position of the element ([x, y])
17701 * @param {Function} callback The function to call after the repair is complete
17702 * @param {Object} scope The scope in which to execute the callback
17704 repair : function(xy, callback, scope){
17705 this.callback = callback;
17706 this.scope = scope;
17707 if(xy && this.animRepair !== false){
17708 this.el.addClass("x-dd-drag-repair");
17709 this.el.hideUnders(true);
17710 this.anim = this.el.shift({
17711 duration: this.repairDuration || .5,
17715 callback: this.afterRepair,
17719 this.afterRepair();
17724 afterRepair : function(){
17726 if(typeof this.callback == "function"){
17727 this.callback.call(this.scope || this);
17729 this.callback = null;
17734 * Ext JS Library 1.1.1
17735 * Copyright(c) 2006-2007, Ext JS, LLC.
17737 * Originally Released Under LGPL - original licence link has changed is not relivant.
17740 * <script type="text/javascript">
17744 * @class Roo.dd.DragSource
17745 * @extends Roo.dd.DDProxy
17746 * A simple class that provides the basic implementation needed to make any element draggable.
17748 * @param {String/HTMLElement/Element} el The container element
17749 * @param {Object} config
17751 Roo.dd.DragSource = function(el, config){
17752 this.el = Roo.get(el);
17753 this.dragData = {};
17755 Roo.apply(this, config);
17758 this.proxy = new Roo.dd.StatusProxy();
17761 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17762 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17764 this.dragging = false;
17767 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17769 * @cfg {String} dropAllowed
17770 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17772 dropAllowed : "x-dd-drop-ok",
17774 * @cfg {String} dropNotAllowed
17775 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17777 dropNotAllowed : "x-dd-drop-nodrop",
17780 * Returns the data object associated with this drag source
17781 * @return {Object} data An object containing arbitrary data
17783 getDragData : function(e){
17784 return this.dragData;
17788 onDragEnter : function(e, id){
17789 var target = Roo.dd.DragDropMgr.getDDById(id);
17790 this.cachedTarget = target;
17791 if(this.beforeDragEnter(target, e, id) !== false){
17792 if(target.isNotifyTarget){
17793 var status = target.notifyEnter(this, e, this.dragData);
17794 this.proxy.setStatus(status);
17796 this.proxy.setStatus(this.dropAllowed);
17799 if(this.afterDragEnter){
17801 * An empty function by default, but provided so that you can perform a custom action
17802 * when the dragged item enters the drop target by providing an implementation.
17803 * @param {Roo.dd.DragDrop} target The drop target
17804 * @param {Event} e The event object
17805 * @param {String} id The id of the dragged element
17806 * @method afterDragEnter
17808 this.afterDragEnter(target, e, id);
17814 * An empty function by default, but provided so that you can perform a custom action
17815 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
17816 * @param {Roo.dd.DragDrop} target The drop target
17817 * @param {Event} e The event object
17818 * @param {String} id The id of the dragged element
17819 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17821 beforeDragEnter : function(target, e, id){
17826 alignElWithMouse: function() {
17827 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
17832 onDragOver : function(e, id){
17833 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17834 if(this.beforeDragOver(target, e, id) !== false){
17835 if(target.isNotifyTarget){
17836 var status = target.notifyOver(this, e, this.dragData);
17837 this.proxy.setStatus(status);
17840 if(this.afterDragOver){
17842 * An empty function by default, but provided so that you can perform a custom action
17843 * while the dragged item is over the drop target by providing an implementation.
17844 * @param {Roo.dd.DragDrop} target The drop target
17845 * @param {Event} e The event object
17846 * @param {String} id The id of the dragged element
17847 * @method afterDragOver
17849 this.afterDragOver(target, e, id);
17855 * An empty function by default, but provided so that you can perform a custom action
17856 * while the dragged item is over the drop target and optionally cancel the onDragOver.
17857 * @param {Roo.dd.DragDrop} target The drop target
17858 * @param {Event} e The event object
17859 * @param {String} id The id of the dragged element
17860 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17862 beforeDragOver : function(target, e, id){
17867 onDragOut : function(e, id){
17868 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17869 if(this.beforeDragOut(target, e, id) !== false){
17870 if(target.isNotifyTarget){
17871 target.notifyOut(this, e, this.dragData);
17873 this.proxy.reset();
17874 if(this.afterDragOut){
17876 * An empty function by default, but provided so that you can perform a custom action
17877 * after the dragged item is dragged out of the target without dropping.
17878 * @param {Roo.dd.DragDrop} target The drop target
17879 * @param {Event} e The event object
17880 * @param {String} id The id of the dragged element
17881 * @method afterDragOut
17883 this.afterDragOut(target, e, id);
17886 this.cachedTarget = null;
17890 * An empty function by default, but provided so that you can perform a custom action before the dragged
17891 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
17892 * @param {Roo.dd.DragDrop} target The drop target
17893 * @param {Event} e The event object
17894 * @param {String} id The id of the dragged element
17895 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17897 beforeDragOut : function(target, e, id){
17902 onDragDrop : function(e, id){
17903 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17904 if(this.beforeDragDrop(target, e, id) !== false){
17905 if(target.isNotifyTarget){
17906 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
17907 this.onValidDrop(target, e, id);
17909 this.onInvalidDrop(target, e, id);
17912 this.onValidDrop(target, e, id);
17915 if(this.afterDragDrop){
17917 * An empty function by default, but provided so that you can perform a custom action
17918 * after a valid drag drop has occurred by providing an implementation.
17919 * @param {Roo.dd.DragDrop} target The drop target
17920 * @param {Event} e The event object
17921 * @param {String} id The id of the dropped element
17922 * @method afterDragDrop
17924 this.afterDragDrop(target, e, id);
17927 delete this.cachedTarget;
17931 * An empty function by default, but provided so that you can perform a custom action before the dragged
17932 * item is dropped onto the target and optionally cancel the onDragDrop.
17933 * @param {Roo.dd.DragDrop} target The drop target
17934 * @param {Event} e The event object
17935 * @param {String} id The id of the dragged element
17936 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
17938 beforeDragDrop : function(target, e, id){
17943 onValidDrop : function(target, e, id){
17945 if(this.afterValidDrop){
17947 * An empty function by default, but provided so that you can perform a custom action
17948 * after a valid drop has occurred by providing an implementation.
17949 * @param {Object} target The target DD
17950 * @param {Event} e The event object
17951 * @param {String} id The id of the dropped element
17952 * @method afterInvalidDrop
17954 this.afterValidDrop(target, e, id);
17959 getRepairXY : function(e, data){
17960 return this.el.getXY();
17964 onInvalidDrop : function(target, e, id){
17965 this.beforeInvalidDrop(target, e, id);
17966 if(this.cachedTarget){
17967 if(this.cachedTarget.isNotifyTarget){
17968 this.cachedTarget.notifyOut(this, e, this.dragData);
17970 this.cacheTarget = null;
17972 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
17974 if(this.afterInvalidDrop){
17976 * An empty function by default, but provided so that you can perform a custom action
17977 * after an invalid drop has occurred by providing an implementation.
17978 * @param {Event} e The event object
17979 * @param {String} id The id of the dropped element
17980 * @method afterInvalidDrop
17982 this.afterInvalidDrop(e, id);
17987 afterRepair : function(){
17989 this.el.highlight(this.hlColor || "c3daf9");
17991 this.dragging = false;
17995 * An empty function by default, but provided so that you can perform a custom action after an invalid
17996 * drop has occurred.
17997 * @param {Roo.dd.DragDrop} target The drop target
17998 * @param {Event} e The event object
17999 * @param {String} id The id of the dragged element
18000 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18002 beforeInvalidDrop : function(target, e, id){
18007 handleMouseDown : function(e){
18008 if(this.dragging) {
18011 var data = this.getDragData(e);
18012 if(data && this.onBeforeDrag(data, e) !== false){
18013 this.dragData = data;
18015 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18020 * An empty function by default, but provided so that you can perform a custom action before the initial
18021 * drag event begins and optionally cancel it.
18022 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18023 * @param {Event} e The event object
18024 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18026 onBeforeDrag : function(data, e){
18031 * An empty function by default, but provided so that you can perform a custom action once the initial
18032 * drag event has begun. The drag cannot be canceled from this function.
18033 * @param {Number} x The x position of the click on the dragged object
18034 * @param {Number} y The y position of the click on the dragged object
18036 onStartDrag : Roo.emptyFn,
18038 // private - YUI override
18039 startDrag : function(x, y){
18040 this.proxy.reset();
18041 this.dragging = true;
18042 this.proxy.update("");
18043 this.onInitDrag(x, y);
18048 onInitDrag : function(x, y){
18049 var clone = this.el.dom.cloneNode(true);
18050 clone.id = Roo.id(); // prevent duplicate ids
18051 this.proxy.update(clone);
18052 this.onStartDrag(x, y);
18057 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18058 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18060 getProxy : function(){
18065 * Hides the drag source's {@link Roo.dd.StatusProxy}
18067 hideProxy : function(){
18069 this.proxy.reset(true);
18070 this.dragging = false;
18074 triggerCacheRefresh : function(){
18075 Roo.dd.DDM.refreshCache(this.groups);
18078 // private - override to prevent hiding
18079 b4EndDrag: function(e) {
18082 // private - override to prevent moving
18083 endDrag : function(e){
18084 this.onEndDrag(this.dragData, e);
18088 onEndDrag : function(data, e){
18091 // private - pin to cursor
18092 autoOffset : function(x, y) {
18093 this.setDelta(-12, -20);
18097 * Ext JS Library 1.1.1
18098 * Copyright(c) 2006-2007, Ext JS, LLC.
18100 * Originally Released Under LGPL - original licence link has changed is not relivant.
18103 * <script type="text/javascript">
18108 * @class Roo.dd.DropTarget
18109 * @extends Roo.dd.DDTarget
18110 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18111 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18113 * @param {String/HTMLElement/Element} el The container element
18114 * @param {Object} config
18116 Roo.dd.DropTarget = function(el, config){
18117 this.el = Roo.get(el);
18119 Roo.apply(this, config);
18121 if(this.containerScroll){
18122 Roo.dd.ScrollManager.register(this.el);
18125 Roo.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18130 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18132 * @cfg {String} overClass
18133 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18136 * @cfg {String} dropAllowed
18137 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18139 dropAllowed : "x-dd-drop-ok",
18141 * @cfg {String} dropNotAllowed
18142 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18144 dropNotAllowed : "x-dd-drop-nodrop",
18150 isNotifyTarget : true,
18153 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18154 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18155 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18156 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18157 * @param {Event} e The event
18158 * @param {Object} data An object containing arbitrary data supplied by the drag source
18159 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18160 * underlying {@link Roo.dd.StatusProxy} can be updated
18162 notifyEnter : function(dd, e, data){
18163 if(this.overClass){
18164 this.el.addClass(this.overClass);
18166 return this.dropAllowed;
18170 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18171 * This method will be called on every mouse movement while the drag source is over the drop target.
18172 * This default implementation simply returns the dropAllowed config value.
18173 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18174 * @param {Event} e The event
18175 * @param {Object} data An object containing arbitrary data supplied by the drag source
18176 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18177 * underlying {@link Roo.dd.StatusProxy} can be updated
18179 notifyOver : function(dd, e, data){
18180 return this.dropAllowed;
18184 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18185 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18186 * overClass (if any) from the drop element.
18187 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18188 * @param {Event} e The event
18189 * @param {Object} data An object containing arbitrary data supplied by the drag source
18191 notifyOut : function(dd, e, data){
18192 if(this.overClass){
18193 this.el.removeClass(this.overClass);
18198 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18199 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18200 * implementation that does something to process the drop event and returns true so that the drag source's
18201 * repair action does not run.
18202 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18203 * @param {Event} e The event
18204 * @param {Object} data An object containing arbitrary data supplied by the drag source
18205 * @return {Boolean} True if the drop was valid, else false
18207 notifyDrop : function(dd, e, data){
18212 * Ext JS Library 1.1.1
18213 * Copyright(c) 2006-2007, Ext JS, LLC.
18215 * Originally Released Under LGPL - original licence link has changed is not relivant.
18218 * <script type="text/javascript">
18223 * @class Roo.dd.DragZone
18224 * @extends Roo.dd.DragSource
18225 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18226 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18228 * @param {String/HTMLElement/Element} el The container element
18229 * @param {Object} config
18231 Roo.dd.DragZone = function(el, config){
18232 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18233 if(this.containerScroll){
18234 Roo.dd.ScrollManager.register(this.el);
18238 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18240 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18241 * for auto scrolling during drag operations.
18244 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18245 * method after a failed drop (defaults to "c3daf9" - light blue)
18249 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18250 * for a valid target to drag based on the mouse down. Override this method
18251 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18252 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18253 * @param {EventObject} e The mouse down event
18254 * @return {Object} The dragData
18256 getDragData : function(e){
18257 return Roo.dd.Registry.getHandleFromEvent(e);
18261 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18262 * this.dragData.ddel
18263 * @param {Number} x The x position of the click on the dragged object
18264 * @param {Number} y The y position of the click on the dragged object
18265 * @return {Boolean} true to continue the drag, false to cancel
18267 onInitDrag : function(x, y){
18268 this.proxy.update(this.dragData.ddel.cloneNode(true));
18269 this.onStartDrag(x, y);
18274 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18276 afterRepair : function(){
18278 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18280 this.dragging = false;
18284 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18285 * the XY of this.dragData.ddel
18286 * @param {EventObject} e The mouse up event
18287 * @return {Array} The xy location (e.g. [100, 200])
18289 getRepairXY : function(e){
18290 return Roo.Element.fly(this.dragData.ddel).getXY();
18294 * Ext JS Library 1.1.1
18295 * Copyright(c) 2006-2007, Ext JS, LLC.
18297 * Originally Released Under LGPL - original licence link has changed is not relivant.
18300 * <script type="text/javascript">
18303 * @class Roo.dd.DropZone
18304 * @extends Roo.dd.DropTarget
18305 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18306 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18308 * @param {String/HTMLElement/Element} el The container element
18309 * @param {Object} config
18311 Roo.dd.DropZone = function(el, config){
18312 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18315 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18317 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18318 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18319 * provide your own custom lookup.
18320 * @param {Event} e The event
18321 * @return {Object} data The custom data
18323 getTargetFromEvent : function(e){
18324 return Roo.dd.Registry.getTargetFromEvent(e);
18328 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18329 * that it has registered. This method has no default implementation and should be overridden to provide
18330 * node-specific processing if necessary.
18331 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18332 * {@link #getTargetFromEvent} for this node)
18333 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18334 * @param {Event} e The event
18335 * @param {Object} data An object containing arbitrary data supplied by the drag source
18337 onNodeEnter : function(n, dd, e, data){
18342 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18343 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18344 * overridden to provide the proper feedback.
18345 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18346 * {@link #getTargetFromEvent} for this node)
18347 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18348 * @param {Event} e The event
18349 * @param {Object} data An object containing arbitrary data supplied by the drag source
18350 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18351 * underlying {@link Roo.dd.StatusProxy} can be updated
18353 onNodeOver : function(n, dd, e, data){
18354 return this.dropAllowed;
18358 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18359 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18360 * node-specific processing if necessary.
18361 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18362 * {@link #getTargetFromEvent} for this node)
18363 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18364 * @param {Event} e The event
18365 * @param {Object} data An object containing arbitrary data supplied by the drag source
18367 onNodeOut : function(n, dd, e, data){
18372 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18373 * the drop node. The default implementation returns false, so it should be overridden to provide the
18374 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18375 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18376 * {@link #getTargetFromEvent} for this node)
18377 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18378 * @param {Event} e The event
18379 * @param {Object} data An object containing arbitrary data supplied by the drag source
18380 * @return {Boolean} True if the drop was valid, else false
18382 onNodeDrop : function(n, dd, e, data){
18387 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18388 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18389 * it should be overridden to provide the proper feedback if necessary.
18390 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18391 * @param {Event} e The event
18392 * @param {Object} data An object containing arbitrary data supplied by the drag source
18393 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18394 * underlying {@link Roo.dd.StatusProxy} can be updated
18396 onContainerOver : function(dd, e, data){
18397 return this.dropNotAllowed;
18401 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18402 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18403 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18404 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18405 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18406 * @param {Event} e The event
18407 * @param {Object} data An object containing arbitrary data supplied by the drag source
18408 * @return {Boolean} True if the drop was valid, else false
18410 onContainerDrop : function(dd, e, data){
18415 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18416 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18417 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18418 * you should override this method and provide a custom implementation.
18419 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18420 * @param {Event} e The event
18421 * @param {Object} data An object containing arbitrary data supplied by the drag source
18422 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18423 * underlying {@link Roo.dd.StatusProxy} can be updated
18425 notifyEnter : function(dd, e, data){
18426 return this.dropNotAllowed;
18430 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18431 * This method will be called on every mouse movement while the drag source is over the drop zone.
18432 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18433 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18434 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18435 * registered node, it will call {@link #onContainerOver}.
18436 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18437 * @param {Event} e The event
18438 * @param {Object} data An object containing arbitrary data supplied by the drag source
18439 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18440 * underlying {@link Roo.dd.StatusProxy} can be updated
18442 notifyOver : function(dd, e, data){
18443 var n = this.getTargetFromEvent(e);
18444 if(!n){ // not over valid drop target
18445 if(this.lastOverNode){
18446 this.onNodeOut(this.lastOverNode, dd, e, data);
18447 this.lastOverNode = null;
18449 return this.onContainerOver(dd, e, data);
18451 if(this.lastOverNode != n){
18452 if(this.lastOverNode){
18453 this.onNodeOut(this.lastOverNode, dd, e, data);
18455 this.onNodeEnter(n, dd, e, data);
18456 this.lastOverNode = n;
18458 return this.onNodeOver(n, dd, e, data);
18462 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18463 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18464 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18465 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18466 * @param {Event} e The event
18467 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18469 notifyOut : function(dd, e, data){
18470 if(this.lastOverNode){
18471 this.onNodeOut(this.lastOverNode, dd, e, data);
18472 this.lastOverNode = null;
18477 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18478 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18479 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18480 * otherwise it will call {@link #onContainerDrop}.
18481 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18482 * @param {Event} e The event
18483 * @param {Object} data An object containing arbitrary data supplied by the drag source
18484 * @return {Boolean} True if the drop was valid, else false
18486 notifyDrop : function(dd, e, data){
18487 if(this.lastOverNode){
18488 this.onNodeOut(this.lastOverNode, dd, e, data);
18489 this.lastOverNode = null;
18491 var n = this.getTargetFromEvent(e);
18493 this.onNodeDrop(n, dd, e, data) :
18494 this.onContainerDrop(dd, e, data);
18498 triggerCacheRefresh : function(){
18499 Roo.dd.DDM.refreshCache(this.groups);
18503 * Ext JS Library 1.1.1
18504 * Copyright(c) 2006-2007, Ext JS, LLC.
18506 * Originally Released Under LGPL - original licence link has changed is not relivant.
18509 * <script type="text/javascript">
18514 * @class Roo.data.SortTypes
18516 * Defines the default sorting (casting?) comparison functions used when sorting data.
18518 Roo.data.SortTypes = {
18520 * Default sort that does nothing
18521 * @param {Mixed} s The value being converted
18522 * @return {Mixed} The comparison value
18524 none : function(s){
18529 * The regular expression used to strip tags
18533 stripTagsRE : /<\/?[^>]+>/gi,
18536 * Strips all HTML tags to sort on text only
18537 * @param {Mixed} s The value being converted
18538 * @return {String} The comparison value
18540 asText : function(s){
18541 return String(s).replace(this.stripTagsRE, "");
18545 * Strips all HTML tags to sort on text only - Case insensitive
18546 * @param {Mixed} s The value being converted
18547 * @return {String} The comparison value
18549 asUCText : function(s){
18550 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18554 * Case insensitive string
18555 * @param {Mixed} s The value being converted
18556 * @return {String} The comparison value
18558 asUCString : function(s) {
18559 return String(s).toUpperCase();
18564 * @param {Mixed} s The value being converted
18565 * @return {Number} The comparison value
18567 asDate : function(s) {
18571 if(s instanceof Date){
18572 return s.getTime();
18574 return Date.parse(String(s));
18579 * @param {Mixed} s The value being converted
18580 * @return {Float} The comparison value
18582 asFloat : function(s) {
18583 var val = parseFloat(String(s).replace(/,/g, ""));
18584 if(isNaN(val)) val = 0;
18590 * @param {Mixed} s The value being converted
18591 * @return {Number} The comparison value
18593 asInt : function(s) {
18594 var val = parseInt(String(s).replace(/,/g, ""));
18595 if(isNaN(val)) val = 0;
18600 * Ext JS Library 1.1.1
18601 * Copyright(c) 2006-2007, Ext JS, LLC.
18603 * Originally Released Under LGPL - original licence link has changed is not relivant.
18606 * <script type="text/javascript">
18610 * @class Roo.data.Record
18611 * Instances of this class encapsulate both record <em>definition</em> information, and record
18612 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18613 * to access Records cached in an {@link Roo.data.Store} object.<br>
18615 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18616 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18619 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18621 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18622 * {@link #create}. The parameters are the same.
18623 * @param {Array} data An associative Array of data values keyed by the field name.
18624 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18625 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18626 * not specified an integer id is generated.
18628 Roo.data.Record = function(data, id){
18629 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18634 * Generate a constructor for a specific record layout.
18635 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18636 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18637 * Each field definition object may contain the following properties: <ul>
18638 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
18639 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18640 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18641 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18642 * is being used, then this is a string containing the javascript expression to reference the data relative to
18643 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18644 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18645 * this may be omitted.</p></li>
18646 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18647 * <ul><li>auto (Default, implies no conversion)</li>
18652 * <li>date</li></ul></p></li>
18653 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18654 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18655 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18656 * by the Reader into an object that will be stored in the Record. It is passed the
18657 * following parameters:<ul>
18658 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18660 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18662 * <br>usage:<br><pre><code>
18663 var TopicRecord = Roo.data.Record.create(
18664 {name: 'title', mapping: 'topic_title'},
18665 {name: 'author', mapping: 'username'},
18666 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18667 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18668 {name: 'lastPoster', mapping: 'user2'},
18669 {name: 'excerpt', mapping: 'post_text'}
18672 var myNewRecord = new TopicRecord({
18673 title: 'Do my job please',
18676 lastPost: new Date(),
18677 lastPoster: 'Animal',
18678 excerpt: 'No way dude!'
18680 myStore.add(myNewRecord);
18685 Roo.data.Record.create = function(o){
18686 var f = function(){
18687 f.superclass.constructor.apply(this, arguments);
18689 Roo.extend(f, Roo.data.Record);
18690 var p = f.prototype;
18691 p.fields = new Roo.util.MixedCollection(false, function(field){
18694 for(var i = 0, len = o.length; i < len; i++){
18695 p.fields.add(new Roo.data.Field(o[i]));
18697 f.getField = function(name){
18698 return p.fields.get(name);
18703 Roo.data.Record.AUTO_ID = 1000;
18704 Roo.data.Record.EDIT = 'edit';
18705 Roo.data.Record.REJECT = 'reject';
18706 Roo.data.Record.COMMIT = 'commit';
18708 Roo.data.Record.prototype = {
18710 * Readonly flag - true if this record has been modified.
18719 join : function(store){
18720 this.store = store;
18724 * Set the named field to the specified value.
18725 * @param {String} name The name of the field to set.
18726 * @param {Object} value The value to set the field to.
18728 set : function(name, value){
18729 if(this.data[name] == value){
18733 if(!this.modified){
18734 this.modified = {};
18736 if(typeof this.modified[name] == 'undefined'){
18737 this.modified[name] = this.data[name];
18739 this.data[name] = value;
18741 this.store.afterEdit(this);
18746 * Get the value of the named field.
18747 * @param {String} name The name of the field to get the value of.
18748 * @return {Object} The value of the field.
18750 get : function(name){
18751 return this.data[name];
18755 beginEdit : function(){
18756 this.editing = true;
18757 this.modified = {};
18761 cancelEdit : function(){
18762 this.editing = false;
18763 delete this.modified;
18767 endEdit : function(){
18768 this.editing = false;
18769 if(this.dirty && this.store){
18770 this.store.afterEdit(this);
18775 * Usually called by the {@link Roo.data.Store} which owns the Record.
18776 * Rejects all changes made to the Record since either creation, or the last commit operation.
18777 * Modified fields are reverted to their original values.
18779 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18780 * of reject operations.
18782 reject : function(){
18783 var m = this.modified;
18785 if(typeof m[n] != "function"){
18786 this.data[n] = m[n];
18789 this.dirty = false;
18790 delete this.modified;
18791 this.editing = false;
18793 this.store.afterReject(this);
18798 * Usually called by the {@link Roo.data.Store} which owns the Record.
18799 * Commits all changes made to the Record since either creation, or the last commit operation.
18801 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18802 * of commit operations.
18804 commit : function(){
18805 this.dirty = false;
18806 delete this.modified;
18807 this.editing = false;
18809 this.store.afterCommit(this);
18814 hasError : function(){
18815 return this.error != null;
18819 clearError : function(){
18824 * Creates a copy of this record.
18825 * @param {String} id (optional) A new record id if you don't want to use this record's id
18828 copy : function(newId) {
18829 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
18833 * Ext JS Library 1.1.1
18834 * Copyright(c) 2006-2007, Ext JS, LLC.
18836 * Originally Released Under LGPL - original licence link has changed is not relivant.
18839 * <script type="text/javascript">
18845 * @class Roo.data.Store
18846 * @extends Roo.util.Observable
18847 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
18848 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
18850 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
18851 * has no knowledge of the format of the data returned by the Proxy.<br>
18853 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
18854 * instances from the data object. These records are cached and made available through accessor functions.
18856 * Creates a new Store.
18857 * @param {Object} config A config object containing the objects needed for the Store to access data,
18858 * and read the data into Records.
18860 Roo.data.Store = function(config){
18861 this.data = new Roo.util.MixedCollection(false);
18862 this.data.getKey = function(o){
18865 this.baseParams = {};
18867 this.paramNames = {
18874 if(config && config.data){
18875 this.inlineData = config.data;
18876 delete config.data;
18879 Roo.apply(this, config);
18881 if(this.reader){ // reader passed
18882 this.reader = Roo.factory(this.reader, Roo.data);
18883 this.reader.xmodule = this.xmodule || false;
18884 if(!this.recordType){
18885 this.recordType = this.reader.recordType;
18887 if(this.reader.onMetaChange){
18888 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
18892 if(this.recordType){
18893 this.fields = this.recordType.prototype.fields;
18895 this.modified = [];
18899 * @event datachanged
18900 * Fires when the data cache has changed, and a widget which is using this Store
18901 * as a Record cache should refresh its view.
18902 * @param {Store} this
18904 datachanged : true,
18906 * @event metachange
18907 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
18908 * @param {Store} this
18909 * @param {Object} meta The JSON metadata
18914 * Fires when Records have been added to the Store
18915 * @param {Store} this
18916 * @param {Roo.data.Record[]} records The array of Records added
18917 * @param {Number} index The index at which the record(s) were added
18922 * Fires when a Record has been removed from the Store
18923 * @param {Store} this
18924 * @param {Roo.data.Record} record The Record that was removed
18925 * @param {Number} index The index at which the record was removed
18930 * Fires when a Record has been updated
18931 * @param {Store} this
18932 * @param {Roo.data.Record} record The Record that was updated
18933 * @param {String} operation The update operation being performed. Value may be one of:
18935 Roo.data.Record.EDIT
18936 Roo.data.Record.REJECT
18937 Roo.data.Record.COMMIT
18943 * Fires when the data cache has been cleared.
18944 * @param {Store} this
18948 * @event beforeload
18949 * Fires before a request is made for a new data object. If the beforeload handler returns false
18950 * the load action will be canceled.
18951 * @param {Store} this
18952 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18957 * Fires after a new set of Records has been loaded.
18958 * @param {Store} this
18959 * @param {Roo.data.Record[]} records The Records that were loaded
18960 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18964 * @event loadexception
18965 * Fires if an exception occurs in the Proxy during loading.
18966 * Called with the signature of the Proxy's "loadexception" event.
18967 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
18970 * @param {Object} return from JsonData.reader() - success, totalRecords, records
18971 * @param {Object} load options
18972 * @param {Object} jsonData from your request (normally this contains the Exception)
18974 loadexception : true
18978 this.proxy = Roo.factory(this.proxy, Roo.data);
18979 this.proxy.xmodule = this.xmodule || false;
18980 this.relayEvents(this.proxy, ["loadexception"]);
18982 this.sortToggle = {};
18984 Roo.data.Store.superclass.constructor.call(this);
18986 if(this.inlineData){
18987 this.loadData(this.inlineData);
18988 delete this.inlineData;
18991 Roo.extend(Roo.data.Store, Roo.util.Observable, {
18993 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
18994 * without a remote query - used by combo/forms at present.
18998 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19001 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19004 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19005 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19008 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19009 * on any HTTP request
19012 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19015 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19016 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19018 remoteSort : false,
19021 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19022 * loaded or when a record is removed. (defaults to false).
19024 pruneModifiedRecords : false,
19027 lastOptions : null,
19030 * Add Records to the Store and fires the add event.
19031 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19033 add : function(records){
19034 records = [].concat(records);
19035 for(var i = 0, len = records.length; i < len; i++){
19036 records[i].join(this);
19038 var index = this.data.length;
19039 this.data.addAll(records);
19040 this.fireEvent("add", this, records, index);
19044 * Remove a Record from the Store and fires the remove event.
19045 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19047 remove : function(record){
19048 var index = this.data.indexOf(record);
19049 this.data.removeAt(index);
19050 if(this.pruneModifiedRecords){
19051 this.modified.remove(record);
19053 this.fireEvent("remove", this, record, index);
19057 * Remove all Records from the Store and fires the clear event.
19059 removeAll : function(){
19061 if(this.pruneModifiedRecords){
19062 this.modified = [];
19064 this.fireEvent("clear", this);
19068 * Inserts Records to the Store at the given index and fires the add event.
19069 * @param {Number} index The start index at which to insert the passed Records.
19070 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19072 insert : function(index, records){
19073 records = [].concat(records);
19074 for(var i = 0, len = records.length; i < len; i++){
19075 this.data.insert(index, records[i]);
19076 records[i].join(this);
19078 this.fireEvent("add", this, records, index);
19082 * Get the index within the cache of the passed Record.
19083 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19084 * @return {Number} The index of the passed Record. Returns -1 if not found.
19086 indexOf : function(record){
19087 return this.data.indexOf(record);
19091 * Get the index within the cache of the Record with the passed id.
19092 * @param {String} id The id of the Record to find.
19093 * @return {Number} The index of the Record. Returns -1 if not found.
19095 indexOfId : function(id){
19096 return this.data.indexOfKey(id);
19100 * Get the Record with the specified id.
19101 * @param {String} id The id of the Record to find.
19102 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19104 getById : function(id){
19105 return this.data.key(id);
19109 * Get the Record at the specified index.
19110 * @param {Number} index The index of the Record to find.
19111 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19113 getAt : function(index){
19114 return this.data.itemAt(index);
19118 * Returns a range of Records between specified indices.
19119 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19120 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19121 * @return {Roo.data.Record[]} An array of Records
19123 getRange : function(start, end){
19124 return this.data.getRange(start, end);
19128 storeOptions : function(o){
19129 o = Roo.apply({}, o);
19132 this.lastOptions = o;
19136 * Loads the Record cache from the configured Proxy using the configured Reader.
19138 * If using remote paging, then the first load call must specify the <em>start</em>
19139 * and <em>limit</em> properties in the options.params property to establish the initial
19140 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19142 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19143 * and this call will return before the new data has been loaded. Perform any post-processing
19144 * in a callback function, or in a "load" event handler.</strong>
19146 * @param {Object} options An object containing properties which control loading options:<ul>
19147 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19148 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19149 * passed the following arguments:<ul>
19150 * <li>r : Roo.data.Record[]</li>
19151 * <li>options: Options object from the load call</li>
19152 * <li>success: Boolean success indicator</li></ul></li>
19153 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19154 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19157 load : function(options){
19158 options = options || {};
19159 if(this.fireEvent("beforeload", this, options) !== false){
19160 this.storeOptions(options);
19161 var p = Roo.apply(options.params || {}, this.baseParams);
19162 if(this.sortInfo && this.remoteSort){
19163 var pn = this.paramNames;
19164 p[pn["sort"]] = this.sortInfo.field;
19165 p[pn["dir"]] = this.sortInfo.direction;
19167 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19172 * Reloads the Record cache from the configured Proxy using the configured Reader and
19173 * the options from the last load operation performed.
19174 * @param {Object} options (optional) An object containing properties which may override the options
19175 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19176 * the most recently used options are reused).
19178 reload : function(options){
19179 this.load(Roo.applyIf(options||{}, this.lastOptions));
19183 // Called as a callback by the Reader during a load operation.
19184 loadRecords : function(o, options, success){
19185 if(!o || success === false){
19186 if(success !== false){
19187 this.fireEvent("load", this, [], options);
19189 if(options.callback){
19190 options.callback.call(options.scope || this, [], options, false);
19194 // if data returned failure - throw an exception.
19195 if (o.success === false) {
19196 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19199 var r = o.records, t = o.totalRecords || r.length;
19200 if(!options || options.add !== true){
19201 if(this.pruneModifiedRecords){
19202 this.modified = [];
19204 for(var i = 0, len = r.length; i < len; i++){
19208 this.data = this.snapshot;
19209 delete this.snapshot;
19212 this.data.addAll(r);
19213 this.totalLength = t;
19215 this.fireEvent("datachanged", this);
19217 this.totalLength = Math.max(t, this.data.length+r.length);
19220 this.fireEvent("load", this, r, options);
19221 if(options.callback){
19222 options.callback.call(options.scope || this, r, options, true);
19227 * Loads data from a passed data block. A Reader which understands the format of the data
19228 * must have been configured in the constructor.
19229 * @param {Object} data The data block from which to read the Records. The format of the data expected
19230 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19231 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19233 loadData : function(o, append){
19234 var r = this.reader.readRecords(o);
19235 this.loadRecords(r, {add: append}, true);
19239 * Gets the number of cached records.
19241 * <em>If using paging, this may not be the total size of the dataset. If the data object
19242 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19243 * the data set size</em>
19245 getCount : function(){
19246 return this.data.length || 0;
19250 * Gets the total number of records in the dataset as returned by the server.
19252 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19253 * the dataset size</em>
19255 getTotalCount : function(){
19256 return this.totalLength || 0;
19260 * Returns the sort state of the Store as an object with two properties:
19262 field {String} The name of the field by which the Records are sorted
19263 direction {String} The sort order, "ASC" or "DESC"
19266 getSortState : function(){
19267 return this.sortInfo;
19271 applySort : function(){
19272 if(this.sortInfo && !this.remoteSort){
19273 var s = this.sortInfo, f = s.field;
19274 var st = this.fields.get(f).sortType;
19275 var fn = function(r1, r2){
19276 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19277 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19279 this.data.sort(s.direction, fn);
19280 if(this.snapshot && this.snapshot != this.data){
19281 this.snapshot.sort(s.direction, fn);
19287 * Sets the default sort column and order to be used by the next load operation.
19288 * @param {String} fieldName The name of the field to sort by.
19289 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19291 setDefaultSort : function(field, dir){
19292 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19296 * Sort the Records.
19297 * If remote sorting is used, the sort is performed on the server, and the cache is
19298 * reloaded. If local sorting is used, the cache is sorted internally.
19299 * @param {String} fieldName The name of the field to sort by.
19300 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19302 sort : function(fieldName, dir){
19303 var f = this.fields.get(fieldName);
19305 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19306 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19311 this.sortToggle[f.name] = dir;
19312 this.sortInfo = {field: f.name, direction: dir};
19313 if(!this.remoteSort){
19315 this.fireEvent("datachanged", this);
19317 this.load(this.lastOptions);
19322 * Calls the specified function for each of the Records in the cache.
19323 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19324 * Returning <em>false</em> aborts and exits the iteration.
19325 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19327 each : function(fn, scope){
19328 this.data.each(fn, scope);
19332 * Gets all records modified since the last commit. Modified records are persisted across load operations
19333 * (e.g., during paging).
19334 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19336 getModifiedRecords : function(){
19337 return this.modified;
19341 createFilterFn : function(property, value, anyMatch){
19342 if(!value.exec){ // not a regex
19343 value = String(value);
19344 if(value.length == 0){
19347 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19349 return function(r){
19350 return value.test(r.data[property]);
19355 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19356 * @param {String} property A field on your records
19357 * @param {Number} start The record index to start at (defaults to 0)
19358 * @param {Number} end The last record index to include (defaults to length - 1)
19359 * @return {Number} The sum
19361 sum : function(property, start, end){
19362 var rs = this.data.items, v = 0;
19363 start = start || 0;
19364 end = (end || end === 0) ? end : rs.length-1;
19366 for(var i = start; i <= end; i++){
19367 v += (rs[i].data[property] || 0);
19373 * Filter the records by a specified property.
19374 * @param {String} field A field on your records
19375 * @param {String/RegExp} value Either a string that the field
19376 * should start with or a RegExp to test against the field
19377 * @param {Boolean} anyMatch True to match any part not just the beginning
19379 filter : function(property, value, anyMatch){
19380 var fn = this.createFilterFn(property, value, anyMatch);
19381 return fn ? this.filterBy(fn) : this.clearFilter();
19385 * Filter by a function. The specified function will be called with each
19386 * record in this data source. If the function returns true the record is included,
19387 * otherwise it is filtered.
19388 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19389 * @param {Object} scope (optional) The scope of the function (defaults to this)
19391 filterBy : function(fn, scope){
19392 this.snapshot = this.snapshot || this.data;
19393 this.data = this.queryBy(fn, scope||this);
19394 this.fireEvent("datachanged", this);
19398 * Query the records by a specified property.
19399 * @param {String} field A field on your records
19400 * @param {String/RegExp} value Either a string that the field
19401 * should start with or a RegExp to test against the field
19402 * @param {Boolean} anyMatch True to match any part not just the beginning
19403 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19405 query : function(property, value, anyMatch){
19406 var fn = this.createFilterFn(property, value, anyMatch);
19407 return fn ? this.queryBy(fn) : this.data.clone();
19411 * Query by a function. The specified function will be called with each
19412 * record in this data source. If the function returns true the record is included
19414 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19415 * @param {Object} scope (optional) The scope of the function (defaults to this)
19416 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19418 queryBy : function(fn, scope){
19419 var data = this.snapshot || this.data;
19420 return data.filterBy(fn, scope||this);
19424 * Collects unique values for a particular dataIndex from this store.
19425 * @param {String} dataIndex The property to collect
19426 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19427 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19428 * @return {Array} An array of the unique values
19430 collect : function(dataIndex, allowNull, bypassFilter){
19431 var d = (bypassFilter === true && this.snapshot) ?
19432 this.snapshot.items : this.data.items;
19433 var v, sv, r = [], l = {};
19434 for(var i = 0, len = d.length; i < len; i++){
19435 v = d[i].data[dataIndex];
19437 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19446 * Revert to a view of the Record cache with no filtering applied.
19447 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19449 clearFilter : function(suppressEvent){
19450 if(this.snapshot && this.snapshot != this.data){
19451 this.data = this.snapshot;
19452 delete this.snapshot;
19453 if(suppressEvent !== true){
19454 this.fireEvent("datachanged", this);
19460 afterEdit : function(record){
19461 if(this.modified.indexOf(record) == -1){
19462 this.modified.push(record);
19464 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19468 afterReject : function(record){
19469 this.modified.remove(record);
19470 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19474 afterCommit : function(record){
19475 this.modified.remove(record);
19476 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19480 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19481 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19483 commitChanges : function(){
19484 var m = this.modified.slice(0);
19485 this.modified = [];
19486 for(var i = 0, len = m.length; i < len; i++){
19492 * Cancel outstanding changes on all changed records.
19494 rejectChanges : function(){
19495 var m = this.modified.slice(0);
19496 this.modified = [];
19497 for(var i = 0, len = m.length; i < len; i++){
19502 onMetaChange : function(meta, rtype, o){
19503 this.recordType = rtype;
19504 this.fields = rtype.prototype.fields;
19505 delete this.snapshot;
19506 this.sortInfo = meta.sortInfo;
19507 this.modified = [];
19508 this.fireEvent('metachange', this, this.reader.meta);
19512 * Ext JS Library 1.1.1
19513 * Copyright(c) 2006-2007, Ext JS, LLC.
19515 * Originally Released Under LGPL - original licence link has changed is not relivant.
19518 * <script type="text/javascript">
19522 * @class Roo.data.SimpleStore
19523 * @extends Roo.data.Store
19524 * Small helper class to make creating Stores from Array data easier.
19525 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19526 * @cfg {Array} fields An array of field definition objects, or field name strings.
19527 * @cfg {Array} data The multi-dimensional array of data
19529 * @param {Object} config
19531 Roo.data.SimpleStore = function(config){
19532 Roo.data.SimpleStore.superclass.constructor.call(this, {
19534 reader: new Roo.data.ArrayReader({
19537 Roo.data.Record.create(config.fields)
19539 proxy : new Roo.data.MemoryProxy(config.data)
19543 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19545 * Ext JS Library 1.1.1
19546 * Copyright(c) 2006-2007, Ext JS, LLC.
19548 * Originally Released Under LGPL - original licence link has changed is not relivant.
19551 * <script type="text/javascript">
19556 * @extends Roo.data.Store
19557 * @class Roo.data.JsonStore
19558 * Small helper class to make creating Stores for JSON data easier. <br/>
19560 var store = new Roo.data.JsonStore({
19561 url: 'get-images.php',
19563 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19566 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19567 * JsonReader and HttpProxy (unless inline data is provided).</b>
19568 * @cfg {Array} fields An array of field definition objects, or field name strings.
19570 * @param {Object} config
19572 Roo.data.JsonStore = function(c){
19573 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19574 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19575 reader: new Roo.data.JsonReader(c, c.fields)
19578 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19580 * Ext JS Library 1.1.1
19581 * Copyright(c) 2006-2007, Ext JS, LLC.
19583 * Originally Released Under LGPL - original licence link has changed is not relivant.
19586 * <script type="text/javascript">
19590 Roo.data.Field = function(config){
19591 if(typeof config == "string"){
19592 config = {name: config};
19594 Roo.apply(this, config);
19597 this.type = "auto";
19600 var st = Roo.data.SortTypes;
19601 // named sortTypes are supported, here we look them up
19602 if(typeof this.sortType == "string"){
19603 this.sortType = st[this.sortType];
19606 // set default sortType for strings and dates
19607 if(!this.sortType){
19610 this.sortType = st.asUCString;
19613 this.sortType = st.asDate;
19616 this.sortType = st.none;
19621 var stripRe = /[\$,%]/g;
19623 // prebuilt conversion function for this field, instead of
19624 // switching every time we're reading a value
19626 var cv, dateFormat = this.dateFormat;
19631 cv = function(v){ return v; };
19634 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19638 return v !== undefined && v !== null && v !== '' ?
19639 parseInt(String(v).replace(stripRe, ""), 10) : '';
19644 return v !== undefined && v !== null && v !== '' ?
19645 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19650 cv = function(v){ return v === true || v === "true" || v == 1; };
19657 if(v instanceof Date){
19661 if(dateFormat == "timestamp"){
19662 return new Date(v*1000);
19664 return Date.parseDate(v, dateFormat);
19666 var parsed = Date.parse(v);
19667 return parsed ? new Date(parsed) : null;
19676 Roo.data.Field.prototype = {
19684 * Ext JS Library 1.1.1
19685 * Copyright(c) 2006-2007, Ext JS, LLC.
19687 * Originally Released Under LGPL - original licence link has changed is not relivant.
19690 * <script type="text/javascript">
19693 // Base class for reading structured data from a data source. This class is intended to be
19694 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19697 * @class Roo.data.DataReader
19698 * Base class for reading structured data from a data source. This class is intended to be
19699 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19702 Roo.data.DataReader = function(meta, recordType){
19706 this.recordType = recordType instanceof Array ?
19707 Roo.data.Record.create(recordType) : recordType;
19710 Roo.data.DataReader.prototype = {
19712 * Create an empty record
19713 * @param {Object} data (optional) - overlay some values
19714 * @return {Roo.data.Record} record created.
19716 newRow : function(d) {
19718 this.recordType.prototype.fields.each(function(c) {
19720 case 'int' : da[c.name] = 0; break;
19721 case 'date' : da[c.name] = new Date(); break;
19722 case 'float' : da[c.name] = 0.0; break;
19723 case 'boolean' : da[c.name] = false; break;
19724 default : da[c.name] = ""; break;
19728 return new this.recordType(Roo.apply(da, d));
19733 * Ext JS Library 1.1.1
19734 * Copyright(c) 2006-2007, Ext JS, LLC.
19736 * Originally Released Under LGPL - original licence link has changed is not relivant.
19739 * <script type="text/javascript">
19743 * @class Roo.data.DataProxy
19744 * @extends Roo.data.Observable
19745 * This class is an abstract base class for implementations which provide retrieval of
19746 * unformatted data objects.<br>
19748 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19749 * (of the appropriate type which knows how to parse the data object) to provide a block of
19750 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19752 * Custom implementations must implement the load method as described in
19753 * {@link Roo.data.HttpProxy#load}.
19755 Roo.data.DataProxy = function(){
19758 * @event beforeload
19759 * Fires before a network request is made to retrieve a data object.
19760 * @param {Object} This DataProxy object.
19761 * @param {Object} params The params parameter to the load function.
19766 * Fires before the load method's callback is called.
19767 * @param {Object} This DataProxy object.
19768 * @param {Object} o The data object.
19769 * @param {Object} arg The callback argument object passed to the load function.
19773 * @event loadexception
19774 * Fires if an Exception occurs during data retrieval.
19775 * @param {Object} This DataProxy object.
19776 * @param {Object} o The data object.
19777 * @param {Object} arg The callback argument object passed to the load function.
19778 * @param {Object} e The Exception.
19780 loadexception : true
19782 Roo.data.DataProxy.superclass.constructor.call(this);
19785 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
19788 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
19792 * Ext JS Library 1.1.1
19793 * Copyright(c) 2006-2007, Ext JS, LLC.
19795 * Originally Released Under LGPL - original licence link has changed is not relivant.
19798 * <script type="text/javascript">
19801 * @class Roo.data.MemoryProxy
19802 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
19803 * to the Reader when its load method is called.
19805 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
19807 Roo.data.MemoryProxy = function(data){
19811 Roo.data.MemoryProxy.superclass.constructor.call(this);
19815 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
19817 * Load data from the requested source (in this case an in-memory
19818 * data object passed to the constructor), read the data object into
19819 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
19820 * process that block using the passed callback.
19821 * @param {Object} params This parameter is not used by the MemoryProxy class.
19822 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19823 * object into a block of Roo.data.Records.
19824 * @param {Function} callback The function into which to pass the block of Roo.data.records.
19825 * The function must be passed <ul>
19826 * <li>The Record block object</li>
19827 * <li>The "arg" argument from the load function</li>
19828 * <li>A boolean success indicator</li>
19830 * @param {Object} scope The scope in which to call the callback
19831 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19833 load : function(params, reader, callback, scope, arg){
19834 params = params || {};
19837 result = reader.readRecords(this.data);
19839 this.fireEvent("loadexception", this, arg, null, e);
19840 callback.call(scope, null, arg, false);
19843 callback.call(scope, result, arg, true);
19847 update : function(params, records){
19852 * Ext JS Library 1.1.1
19853 * Copyright(c) 2006-2007, Ext JS, LLC.
19855 * Originally Released Under LGPL - original licence link has changed is not relivant.
19858 * <script type="text/javascript">
19861 * @class Roo.data.HttpProxy
19862 * @extends Roo.data.DataProxy
19863 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
19864 * configured to reference a certain URL.<br><br>
19866 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
19867 * from which the running page was served.<br><br>
19869 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
19871 * Be aware that to enable the browser to parse an XML document, the server must set
19872 * the Content-Type header in the HTTP response to "text/xml".
19874 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
19875 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
19876 * will be used to make the request.
19878 Roo.data.HttpProxy = function(conn){
19879 Roo.data.HttpProxy.superclass.constructor.call(this);
19880 // is conn a conn config or a real conn?
19882 this.useAjax = !conn || !conn.events;
19886 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
19887 // thse are take from connection...
19890 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
19893 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
19894 * extra parameters to each request made by this object. (defaults to undefined)
19897 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
19898 * to each request made by this object. (defaults to undefined)
19901 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
19904 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
19907 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
19913 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
19917 * Return the {@link Roo.data.Connection} object being used by this Proxy.
19918 * @return {Connection} The Connection object. This object may be used to subscribe to events on
19919 * a finer-grained basis than the DataProxy events.
19921 getConnection : function(){
19922 return this.useAjax ? Roo.Ajax : this.conn;
19926 * Load data from the configured {@link Roo.data.Connection}, read the data object into
19927 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
19928 * process that block using the passed callback.
19929 * @param {Object} params An object containing properties which are to be used as HTTP parameters
19930 * for the request to the remote server.
19931 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19932 * object into a block of Roo.data.Records.
19933 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
19934 * The function must be passed <ul>
19935 * <li>The Record block object</li>
19936 * <li>The "arg" argument from the load function</li>
19937 * <li>A boolean success indicator</li>
19939 * @param {Object} scope The scope in which to call the callback
19940 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19942 load : function(params, reader, callback, scope, arg){
19943 if(this.fireEvent("beforeload", this, params) !== false){
19945 params : params || {},
19947 callback : callback,
19952 callback : this.loadResponse,
19956 Roo.applyIf(o, this.conn);
19957 if(this.activeRequest){
19958 Roo.Ajax.abort(this.activeRequest);
19960 this.activeRequest = Roo.Ajax.request(o);
19962 this.conn.request(o);
19965 callback.call(scope||this, null, arg, false);
19970 loadResponse : function(o, success, response){
19971 delete this.activeRequest;
19973 this.fireEvent("loadexception", this, o, response);
19974 o.request.callback.call(o.request.scope, null, o.request.arg, false);
19979 result = o.reader.read(response);
19981 this.fireEvent("loadexception", this, o, response, e);
19982 o.request.callback.call(o.request.scope, null, o.request.arg, false);
19986 this.fireEvent("load", this, o, o.request.arg);
19987 o.request.callback.call(o.request.scope, result, o.request.arg, true);
19991 update : function(dataSet){
19996 updateResponse : function(dataSet){
20001 * Ext JS Library 1.1.1
20002 * Copyright(c) 2006-2007, Ext JS, LLC.
20004 * Originally Released Under LGPL - original licence link has changed is not relivant.
20007 * <script type="text/javascript">
20011 * @class Roo.data.ScriptTagProxy
20012 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20013 * other than the originating domain of the running page.<br><br>
20015 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
20016 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20018 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20019 * source code that is used as the source inside a <script> tag.<br><br>
20021 * In order for the browser to process the returned data, the server must wrap the data object
20022 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20023 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20024 * depending on whether the callback name was passed:
20027 boolean scriptTag = false;
20028 String cb = request.getParameter("callback");
20031 response.setContentType("text/javascript");
20033 response.setContentType("application/x-json");
20035 Writer out = response.getWriter();
20037 out.write(cb + "(");
20039 out.print(dataBlock.toJsonString());
20046 * @param {Object} config A configuration object.
20048 Roo.data.ScriptTagProxy = function(config){
20049 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20050 Roo.apply(this, config);
20051 this.head = document.getElementsByTagName("head")[0];
20054 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20056 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20058 * @cfg {String} url The URL from which to request the data object.
20061 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20065 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20066 * the server the name of the callback function set up by the load call to process the returned data object.
20067 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20068 * javascript output which calls this named function passing the data object as its only parameter.
20070 callbackParam : "callback",
20072 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20073 * name to the request.
20078 * Load data from the configured URL, read the data object into
20079 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20080 * process that block using the passed callback.
20081 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20082 * for the request to the remote server.
20083 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20084 * object into a block of Roo.data.Records.
20085 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20086 * The function must be passed <ul>
20087 * <li>The Record block object</li>
20088 * <li>The "arg" argument from the load function</li>
20089 * <li>A boolean success indicator</li>
20091 * @param {Object} scope The scope in which to call the callback
20092 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20094 load : function(params, reader, callback, scope, arg){
20095 if(this.fireEvent("beforeload", this, params) !== false){
20097 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20099 var url = this.url;
20100 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20102 url += "&_dc=" + (new Date().getTime());
20104 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20107 cb : "stcCallback"+transId,
20108 scriptId : "stcScript"+transId,
20112 callback : callback,
20118 window[trans.cb] = function(o){
20119 conn.handleResponse(o, trans);
20122 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20124 if(this.autoAbort !== false){
20128 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20130 var script = document.createElement("script");
20131 script.setAttribute("src", url);
20132 script.setAttribute("type", "text/javascript");
20133 script.setAttribute("id", trans.scriptId);
20134 this.head.appendChild(script);
20136 this.trans = trans;
20138 callback.call(scope||this, null, arg, false);
20143 isLoading : function(){
20144 return this.trans ? true : false;
20148 * Abort the current server request.
20150 abort : function(){
20151 if(this.isLoading()){
20152 this.destroyTrans(this.trans);
20157 destroyTrans : function(trans, isLoaded){
20158 this.head.removeChild(document.getElementById(trans.scriptId));
20159 clearTimeout(trans.timeoutId);
20161 window[trans.cb] = undefined;
20163 delete window[trans.cb];
20166 // if hasn't been loaded, wait for load to remove it to prevent script error
20167 window[trans.cb] = function(){
20168 window[trans.cb] = undefined;
20170 delete window[trans.cb];
20177 handleResponse : function(o, trans){
20178 this.trans = false;
20179 this.destroyTrans(trans, true);
20182 result = trans.reader.readRecords(o);
20184 this.fireEvent("loadexception", this, o, trans.arg, e);
20185 trans.callback.call(trans.scope||window, null, trans.arg, false);
20188 this.fireEvent("load", this, o, trans.arg);
20189 trans.callback.call(trans.scope||window, result, trans.arg, true);
20193 handleFailure : function(trans){
20194 this.trans = false;
20195 this.destroyTrans(trans, false);
20196 this.fireEvent("loadexception", this, null, trans.arg);
20197 trans.callback.call(trans.scope||window, null, trans.arg, false);
20201 * Ext JS Library 1.1.1
20202 * Copyright(c) 2006-2007, Ext JS, LLC.
20204 * Originally Released Under LGPL - original licence link has changed is not relivant.
20207 * <script type="text/javascript">
20211 * @class Roo.data.JsonReader
20212 * @extends Roo.data.DataReader
20213 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20214 * based on mappings in a provided Roo.data.Record constructor.
20218 var RecordDef = Roo.data.Record.create([
20219 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20220 {name: 'occupation'} // This field will use "occupation" as the mapping.
20222 var myReader = new Roo.data.JsonReader({
20223 totalProperty: "results", // The property which contains the total dataset size (optional)
20224 root: "rows", // The property which contains an Array of row objects
20225 id: "id" // The property within each row object that provides an ID for the record (optional)
20229 * This would consume a JSON file like this:
20231 { 'results': 2, 'rows': [
20232 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20233 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20236 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20237 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20238 * paged from the remote server.
20239 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20240 * @cfg {String} root name of the property which contains the Array of row objects.
20241 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20243 * Create a new JsonReader
20244 * @param {Object} meta Metadata configuration options
20245 * @param {Object} recordType Either an Array of field definition objects,
20246 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20248 Roo.data.JsonReader = function(meta, recordType){
20251 // set some defaults:
20252 Roo.applyIf(meta, {
20253 totalProperty: 'total',
20254 successProperty : 'success',
20259 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20261 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20263 * This method is only used by a DataProxy which has retrieved data from a remote server.
20264 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20265 * @return {Object} data A data block which is used by an Roo.data.Store object as
20266 * a cache of Roo.data.Records.
20268 read : function(response){
20269 var json = response.responseText;
20271 var o = eval("("+json+")");
20273 throw {message: "JsonReader.read: Json object not found"};
20278 this.meta = o.metaData;
20279 this.recordType = Roo.data.Record.create(o.metaData.fields);
20280 this.onMetaChange(this.meta, this.recordType, o);
20282 return this.readRecords(o);
20285 // private function a store will implement
20286 onMetaChange : function(meta, recordType, o){
20293 simpleAccess: function(obj, subsc) {
20300 getJsonAccessor: function(){
20302 return function(expr) {
20304 return(re.test(expr))
20305 ? new Function("obj", "return obj." + expr)
20310 return Roo.emptyFn;
20315 * Create a data block containing Roo.data.Records from an XML document.
20316 * @param {Object} o An object which contains an Array of row objects in the property specified
20317 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20318 * which contains the total size of the dataset.
20319 * @return {Object} data A data block which is used by an Roo.data.Store object as
20320 * a cache of Roo.data.Records.
20322 readRecords : function(o){
20324 * After any data loads, the raw JSON data is available for further custom processing.
20328 var s = this.meta, Record = this.recordType,
20329 f = Record.prototype.fields, fi = f.items, fl = f.length;
20331 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20333 if(s.totalProperty) {
20334 this.getTotal = this.getJsonAccessor(s.totalProperty);
20336 if(s.successProperty) {
20337 this.getSuccess = this.getJsonAccessor(s.successProperty);
20339 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20341 var g = this.getJsonAccessor(s.id);
20342 this.getId = function(rec) {
20344 return (r === undefined || r === "") ? null : r;
20347 this.getId = function(){return null;};
20350 for(var i = 0; i < fl; i++){
20352 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20353 this.ef[i] = this.getJsonAccessor(map);
20357 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20358 if(s.totalProperty){
20359 var v = parseInt(this.getTotal(o), 10);
20364 if(s.successProperty){
20365 var v = this.getSuccess(o);
20366 if(v === false || v === 'false'){
20371 for(var i = 0; i < c; i++){
20374 var id = this.getId(n);
20375 for(var j = 0; j < fl; j++){
20377 var v = this.ef[j](n);
20378 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20380 var record = new Record(values, id);
20382 records[i] = record;
20387 totalRecords : totalRecords
20392 * Ext JS Library 1.1.1
20393 * Copyright(c) 2006-2007, Ext JS, LLC.
20395 * Originally Released Under LGPL - original licence link has changed is not relivant.
20398 * <script type="text/javascript">
20402 * @class Roo.data.XmlReader
20403 * @extends Roo.data.DataReader
20404 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20405 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20407 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20408 * header in the HTTP response must be set to "text/xml".</em>
20412 var RecordDef = Roo.data.Record.create([
20413 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20414 {name: 'occupation'} // This field will use "occupation" as the mapping.
20416 var myReader = new Roo.data.XmlReader({
20417 totalRecords: "results", // The element which contains the total dataset size (optional)
20418 record: "row", // The repeated element which contains row information
20419 id: "id" // The element within the row that provides an ID for the record (optional)
20423 * This would consume an XML file like this:
20427 <results>2</results>
20430 <name>Bill</name>
20431 <occupation>Gardener</occupation>
20435 <name>Ben</name>
20436 <occupation>Horticulturalist</occupation>
20440 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20441 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20442 * paged from the remote server.
20443 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20444 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20445 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20446 * a record identifier value.
20448 * Create a new XmlReader
20449 * @param {Object} meta Metadata configuration options
20450 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20451 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20452 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20454 Roo.data.XmlReader = function(meta, recordType){
20456 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20458 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20460 * This method is only used by a DataProxy which has retrieved data from a remote server.
20461 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20462 * to contain a method called 'responseXML' that returns an XML document object.
20463 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20464 * a cache of Roo.data.Records.
20466 read : function(response){
20467 var doc = response.responseXML;
20469 throw {message: "XmlReader.read: XML Document not available"};
20471 return this.readRecords(doc);
20475 * Create a data block containing Roo.data.Records from an XML document.
20476 * @param {Object} doc A parsed XML document.
20477 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20478 * a cache of Roo.data.Records.
20480 readRecords : function(doc){
20482 * After any data loads/reads, the raw XML Document is available for further custom processing.
20483 * @type XMLDocument
20485 this.xmlData = doc;
20486 var root = doc.documentElement || doc;
20487 var q = Roo.DomQuery;
20488 var recordType = this.recordType, fields = recordType.prototype.fields;
20489 var sid = this.meta.id;
20490 var totalRecords = 0, success = true;
20491 if(this.meta.totalRecords){
20492 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20495 if(this.meta.success){
20496 var sv = q.selectValue(this.meta.success, root, true);
20497 success = sv !== false && sv !== 'false';
20500 var ns = q.select(this.meta.record, root);
20501 for(var i = 0, len = ns.length; i < len; i++) {
20504 var id = sid ? q.selectValue(sid, n) : undefined;
20505 for(var j = 0, jlen = fields.length; j < jlen; j++){
20506 var f = fields.items[j];
20507 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20509 values[f.name] = v;
20511 var record = new recordType(values, id);
20513 records[records.length] = record;
20519 totalRecords : totalRecords || records.length
20524 * Ext JS Library 1.1.1
20525 * Copyright(c) 2006-2007, Ext JS, LLC.
20527 * Originally Released Under LGPL - original licence link has changed is not relivant.
20530 * <script type="text/javascript">
20534 * @class Roo.data.ArrayReader
20535 * @extends Roo.data.DataReader
20536 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20537 * Each element of that Array represents a row of data fields. The
20538 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20539 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20543 var RecordDef = Roo.data.Record.create([
20544 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20545 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20547 var myReader = new Roo.data.ArrayReader({
20548 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20552 * This would consume an Array like this:
20554 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20556 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20558 * Create a new JsonReader
20559 * @param {Object} meta Metadata configuration options.
20560 * @param {Object} recordType Either an Array of field definition objects
20561 * as specified to {@link Roo.data.Record#create},
20562 * or an {@link Roo.data.Record} object
20563 * created using {@link Roo.data.Record#create}.
20565 Roo.data.ArrayReader = function(meta, recordType){
20566 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20569 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20571 * Create a data block containing Roo.data.Records from an XML document.
20572 * @param {Object} o An Array of row objects which represents the dataset.
20573 * @return {Object} data A data block which is used by an Roo.data.Store object as
20574 * a cache of Roo.data.Records.
20576 readRecords : function(o){
20577 var sid = this.meta ? this.meta.id : null;
20578 var recordType = this.recordType, fields = recordType.prototype.fields;
20581 for(var i = 0; i < root.length; i++){
20584 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20585 for(var j = 0, jlen = fields.length; j < jlen; j++){
20586 var f = fields.items[j];
20587 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20588 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20590 values[f.name] = v;
20592 var record = new recordType(values, id);
20594 records[records.length] = record;
20598 totalRecords : records.length
20603 * Ext JS Library 1.1.1
20604 * Copyright(c) 2006-2007, Ext JS, LLC.
20606 * Originally Released Under LGPL - original licence link has changed is not relivant.
20609 * <script type="text/javascript">
20614 * @class Roo.data.Tree
20615 * @extends Roo.util.Observable
20616 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20617 * in the tree have most standard DOM functionality.
20619 * @param {Node} root (optional) The root node
20621 Roo.data.Tree = function(root){
20622 this.nodeHash = {};
20624 * The root node for this tree
20629 this.setRootNode(root);
20634 * Fires when a new child node is appended to a node in this tree.
20635 * @param {Tree} tree The owner tree
20636 * @param {Node} parent The parent node
20637 * @param {Node} node The newly appended node
20638 * @param {Number} index The index of the newly appended node
20643 * Fires when a child node is removed from a node in this tree.
20644 * @param {Tree} tree The owner tree
20645 * @param {Node} parent The parent node
20646 * @param {Node} node The child node removed
20651 * Fires when a node is moved to a new location in the tree
20652 * @param {Tree} tree The owner tree
20653 * @param {Node} node The node moved
20654 * @param {Node} oldParent The old parent of this node
20655 * @param {Node} newParent The new parent of this node
20656 * @param {Number} index The index it was moved to
20661 * Fires when a new child node is inserted in a node in this tree.
20662 * @param {Tree} tree The owner tree
20663 * @param {Node} parent The parent node
20664 * @param {Node} node The child node inserted
20665 * @param {Node} refNode The child node the node was inserted before
20669 * @event beforeappend
20670 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20671 * @param {Tree} tree The owner tree
20672 * @param {Node} parent The parent node
20673 * @param {Node} node The child node to be appended
20675 "beforeappend" : true,
20677 * @event beforeremove
20678 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20679 * @param {Tree} tree The owner tree
20680 * @param {Node} parent The parent node
20681 * @param {Node} node The child node to be removed
20683 "beforeremove" : true,
20685 * @event beforemove
20686 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20687 * @param {Tree} tree The owner tree
20688 * @param {Node} node The node being moved
20689 * @param {Node} oldParent The parent of the node
20690 * @param {Node} newParent The new parent the node is moving to
20691 * @param {Number} index The index it is being moved to
20693 "beforemove" : true,
20695 * @event beforeinsert
20696 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20697 * @param {Tree} tree The owner tree
20698 * @param {Node} parent The parent node
20699 * @param {Node} node The child node to be inserted
20700 * @param {Node} refNode The child node the node is being inserted before
20702 "beforeinsert" : true
20705 Roo.data.Tree.superclass.constructor.call(this);
20708 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20709 pathSeparator: "/",
20711 proxyNodeEvent : function(){
20712 return this.fireEvent.apply(this, arguments);
20716 * Returns the root node for this tree.
20719 getRootNode : function(){
20724 * Sets the root node for this tree.
20725 * @param {Node} node
20728 setRootNode : function(node){
20730 node.ownerTree = this;
20731 node.isRoot = true;
20732 this.registerNode(node);
20737 * Gets a node in this tree by its id.
20738 * @param {String} id
20741 getNodeById : function(id){
20742 return this.nodeHash[id];
20745 registerNode : function(node){
20746 this.nodeHash[node.id] = node;
20749 unregisterNode : function(node){
20750 delete this.nodeHash[node.id];
20753 toString : function(){
20754 return "[Tree"+(this.id?" "+this.id:"")+"]";
20759 * @class Roo.data.Node
20760 * @extends Roo.util.Observable
20761 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
20762 * @cfg {String} id The id for this node. If one is not specified, one is generated.
20764 * @param {Object} attributes The attributes/config for the node
20766 Roo.data.Node = function(attributes){
20768 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
20771 this.attributes = attributes || {};
20772 this.leaf = this.attributes.leaf;
20774 * The node id. @type String
20776 this.id = this.attributes.id;
20778 this.id = Roo.id(null, "ynode-");
20779 this.attributes.id = this.id;
20782 * All child nodes of this node. @type Array
20784 this.childNodes = [];
20785 if(!this.childNodes.indexOf){ // indexOf is a must
20786 this.childNodes.indexOf = function(o){
20787 for(var i = 0, len = this.length; i < len; i++){
20788 if(this[i] == o) return i;
20794 * The parent node for this node. @type Node
20796 this.parentNode = null;
20798 * The first direct child node of this node, or null if this node has no child nodes. @type Node
20800 this.firstChild = null;
20802 * The last direct child node of this node, or null if this node has no child nodes. @type Node
20804 this.lastChild = null;
20806 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
20808 this.previousSibling = null;
20810 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
20812 this.nextSibling = null;
20817 * Fires when a new child node is appended
20818 * @param {Tree} tree The owner tree
20819 * @param {Node} this This node
20820 * @param {Node} node The newly appended node
20821 * @param {Number} index The index of the newly appended node
20826 * Fires when a child node is removed
20827 * @param {Tree} tree The owner tree
20828 * @param {Node} this This node
20829 * @param {Node} node The removed node
20834 * Fires when this node is moved to a new location in the tree
20835 * @param {Tree} tree The owner tree
20836 * @param {Node} this This node
20837 * @param {Node} oldParent The old parent of this node
20838 * @param {Node} newParent The new parent of this node
20839 * @param {Number} index The index it was moved to
20844 * Fires when a new child node is inserted.
20845 * @param {Tree} tree The owner tree
20846 * @param {Node} this This node
20847 * @param {Node} node The child node inserted
20848 * @param {Node} refNode The child node the node was inserted before
20852 * @event beforeappend
20853 * Fires before a new child is appended, return false to cancel the append.
20854 * @param {Tree} tree The owner tree
20855 * @param {Node} this This node
20856 * @param {Node} node The child node to be appended
20858 "beforeappend" : true,
20860 * @event beforeremove
20861 * Fires before a child is removed, return false to cancel the remove.
20862 * @param {Tree} tree The owner tree
20863 * @param {Node} this This node
20864 * @param {Node} node The child node to be removed
20866 "beforeremove" : true,
20868 * @event beforemove
20869 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
20870 * @param {Tree} tree The owner tree
20871 * @param {Node} this This node
20872 * @param {Node} oldParent The parent of this node
20873 * @param {Node} newParent The new parent this node is moving to
20874 * @param {Number} index The index it is being moved to
20876 "beforemove" : true,
20878 * @event beforeinsert
20879 * Fires before a new child is inserted, return false to cancel the insert.
20880 * @param {Tree} tree The owner tree
20881 * @param {Node} this This node
20882 * @param {Node} node The child node to be inserted
20883 * @param {Node} refNode The child node the node is being inserted before
20885 "beforeinsert" : true
20887 this.listeners = this.attributes.listeners;
20888 Roo.data.Node.superclass.constructor.call(this);
20891 Roo.extend(Roo.data.Node, Roo.util.Observable, {
20892 fireEvent : function(evtName){
20893 // first do standard event for this node
20894 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
20897 // then bubble it up to the tree if the event wasn't cancelled
20898 var ot = this.getOwnerTree();
20900 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
20908 * Returns true if this node is a leaf
20909 * @return {Boolean}
20911 isLeaf : function(){
20912 return this.leaf === true;
20916 setFirstChild : function(node){
20917 this.firstChild = node;
20921 setLastChild : function(node){
20922 this.lastChild = node;
20927 * Returns true if this node is the last child of its parent
20928 * @return {Boolean}
20930 isLast : function(){
20931 return (!this.parentNode ? true : this.parentNode.lastChild == this);
20935 * Returns true if this node is the first child of its parent
20936 * @return {Boolean}
20938 isFirst : function(){
20939 return (!this.parentNode ? true : this.parentNode.firstChild == this);
20942 hasChildNodes : function(){
20943 return !this.isLeaf() && this.childNodes.length > 0;
20947 * Insert node(s) as the last child node of this node.
20948 * @param {Node/Array} node The node or Array of nodes to append
20949 * @return {Node} The appended node if single append, or null if an array was passed
20951 appendChild : function(node){
20953 if(node instanceof Array){
20955 }else if(arguments.length > 1){
20958 // if passed an array or multiple args do them one by one
20960 for(var i = 0, len = multi.length; i < len; i++) {
20961 this.appendChild(multi[i]);
20964 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
20967 var index = this.childNodes.length;
20968 var oldParent = node.parentNode;
20969 // it's a move, make sure we move it cleanly
20971 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
20974 oldParent.removeChild(node);
20976 index = this.childNodes.length;
20978 this.setFirstChild(node);
20980 this.childNodes.push(node);
20981 node.parentNode = this;
20982 var ps = this.childNodes[index-1];
20984 node.previousSibling = ps;
20985 ps.nextSibling = node;
20987 node.previousSibling = null;
20989 node.nextSibling = null;
20990 this.setLastChild(node);
20991 node.setOwnerTree(this.getOwnerTree());
20992 this.fireEvent("append", this.ownerTree, this, node, index);
20994 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21001 * Removes a child node from this node.
21002 * @param {Node} node The node to remove
21003 * @return {Node} The removed node
21005 removeChild : function(node){
21006 var index = this.childNodes.indexOf(node);
21010 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21014 // remove it from childNodes collection
21015 this.childNodes.splice(index, 1);
21018 if(node.previousSibling){
21019 node.previousSibling.nextSibling = node.nextSibling;
21021 if(node.nextSibling){
21022 node.nextSibling.previousSibling = node.previousSibling;
21025 // update child refs
21026 if(this.firstChild == node){
21027 this.setFirstChild(node.nextSibling);
21029 if(this.lastChild == node){
21030 this.setLastChild(node.previousSibling);
21033 node.setOwnerTree(null);
21034 // clear any references from the node
21035 node.parentNode = null;
21036 node.previousSibling = null;
21037 node.nextSibling = null;
21038 this.fireEvent("remove", this.ownerTree, this, node);
21043 * Inserts the first node before the second node in this nodes childNodes collection.
21044 * @param {Node} node The node to insert
21045 * @param {Node} refNode The node to insert before (if null the node is appended)
21046 * @return {Node} The inserted node
21048 insertBefore : function(node, refNode){
21049 if(!refNode){ // like standard Dom, refNode can be null for append
21050 return this.appendChild(node);
21053 if(node == refNode){
21057 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21060 var index = this.childNodes.indexOf(refNode);
21061 var oldParent = node.parentNode;
21062 var refIndex = index;
21064 // when moving internally, indexes will change after remove
21065 if(oldParent == this && this.childNodes.indexOf(node) < index){
21069 // it's a move, make sure we move it cleanly
21071 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21074 oldParent.removeChild(node);
21077 this.setFirstChild(node);
21079 this.childNodes.splice(refIndex, 0, node);
21080 node.parentNode = this;
21081 var ps = this.childNodes[refIndex-1];
21083 node.previousSibling = ps;
21084 ps.nextSibling = node;
21086 node.previousSibling = null;
21088 node.nextSibling = refNode;
21089 refNode.previousSibling = node;
21090 node.setOwnerTree(this.getOwnerTree());
21091 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21093 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21099 * Returns the child node at the specified index.
21100 * @param {Number} index
21103 item : function(index){
21104 return this.childNodes[index];
21108 * Replaces one child node in this node with another.
21109 * @param {Node} newChild The replacement node
21110 * @param {Node} oldChild The node to replace
21111 * @return {Node} The replaced node
21113 replaceChild : function(newChild, oldChild){
21114 this.insertBefore(newChild, oldChild);
21115 this.removeChild(oldChild);
21120 * Returns the index of a child node
21121 * @param {Node} node
21122 * @return {Number} The index of the node or -1 if it was not found
21124 indexOf : function(child){
21125 return this.childNodes.indexOf(child);
21129 * Returns the tree this node is in.
21132 getOwnerTree : function(){
21133 // if it doesn't have one, look for one
21134 if(!this.ownerTree){
21138 this.ownerTree = p.ownerTree;
21144 return this.ownerTree;
21148 * Returns depth of this node (the root node has a depth of 0)
21151 getDepth : function(){
21154 while(p.parentNode){
21162 setOwnerTree : function(tree){
21163 // if it's move, we need to update everyone
21164 if(tree != this.ownerTree){
21165 if(this.ownerTree){
21166 this.ownerTree.unregisterNode(this);
21168 this.ownerTree = tree;
21169 var cs = this.childNodes;
21170 for(var i = 0, len = cs.length; i < len; i++) {
21171 cs[i].setOwnerTree(tree);
21174 tree.registerNode(this);
21180 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21181 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21182 * @return {String} The path
21184 getPath : function(attr){
21185 attr = attr || "id";
21186 var p = this.parentNode;
21187 var b = [this.attributes[attr]];
21189 b.unshift(p.attributes[attr]);
21192 var sep = this.getOwnerTree().pathSeparator;
21193 return sep + b.join(sep);
21197 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21198 * function call will be the scope provided or the current node. The arguments to the function
21199 * will be the args provided or the current node. If the function returns false at any point,
21200 * the bubble is stopped.
21201 * @param {Function} fn The function to call
21202 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21203 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21205 bubble : function(fn, scope, args){
21208 if(fn.call(scope || p, args || p) === false){
21216 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21217 * function call will be the scope provided or the current node. The arguments to the function
21218 * will be the args provided or the current node. If the function returns false at any point,
21219 * the cascade is stopped on that branch.
21220 * @param {Function} fn The function to call
21221 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21222 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21224 cascade : function(fn, scope, args){
21225 if(fn.call(scope || this, args || this) !== false){
21226 var cs = this.childNodes;
21227 for(var i = 0, len = cs.length; i < len; i++) {
21228 cs[i].cascade(fn, scope, args);
21234 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21235 * function call will be the scope provided or the current node. The arguments to the function
21236 * will be the args provided or the current node. If the function returns false at any point,
21237 * the iteration stops.
21238 * @param {Function} fn The function to call
21239 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21240 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21242 eachChild : function(fn, scope, args){
21243 var cs = this.childNodes;
21244 for(var i = 0, len = cs.length; i < len; i++) {
21245 if(fn.call(scope || this, args || cs[i]) === false){
21252 * Finds the first child that has the attribute with the specified value.
21253 * @param {String} attribute The attribute name
21254 * @param {Mixed} value The value to search for
21255 * @return {Node} The found child or null if none was found
21257 findChild : function(attribute, value){
21258 var cs = this.childNodes;
21259 for(var i = 0, len = cs.length; i < len; i++) {
21260 if(cs[i].attributes[attribute] == value){
21268 * Finds the first child by a custom function. The child matches if the function passed
21270 * @param {Function} fn
21271 * @param {Object} scope (optional)
21272 * @return {Node} The found child or null if none was found
21274 findChildBy : function(fn, scope){
21275 var cs = this.childNodes;
21276 for(var i = 0, len = cs.length; i < len; i++) {
21277 if(fn.call(scope||cs[i], cs[i]) === true){
21285 * Sorts this nodes children using the supplied sort function
21286 * @param {Function} fn
21287 * @param {Object} scope (optional)
21289 sort : function(fn, scope){
21290 var cs = this.childNodes;
21291 var len = cs.length;
21293 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21295 for(var i = 0; i < len; i++){
21297 n.previousSibling = cs[i-1];
21298 n.nextSibling = cs[i+1];
21300 this.setFirstChild(n);
21303 this.setLastChild(n);
21310 * Returns true if this node is an ancestor (at any point) of the passed node.
21311 * @param {Node} node
21312 * @return {Boolean}
21314 contains : function(node){
21315 return node.isAncestor(this);
21319 * Returns true if the passed node is an ancestor (at any point) of this node.
21320 * @param {Node} node
21321 * @return {Boolean}
21323 isAncestor : function(node){
21324 var p = this.parentNode;
21334 toString : function(){
21335 return "[Node"+(this.id?" "+this.id:"")+"]";
21339 * Ext JS Library 1.1.1
21340 * Copyright(c) 2006-2007, Ext JS, LLC.
21342 * Originally Released Under LGPL - original licence link has changed is not relivant.
21345 * <script type="text/javascript">
21350 * @class Roo.ComponentMgr
21351 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21354 Roo.ComponentMgr = function(){
21355 var all = new Roo.util.MixedCollection();
21359 * Registers a component.
21360 * @param {Roo.Component} c The component
21362 register : function(c){
21367 * Unregisters a component.
21368 * @param {Roo.Component} c The component
21370 unregister : function(c){
21375 * Returns a component by id
21376 * @param {String} id The component id
21378 get : function(id){
21379 return all.get(id);
21383 * Registers a function that will be called when a specified component is added to ComponentMgr
21384 * @param {String} id The component id
21385 * @param {Funtction} fn The callback function
21386 * @param {Object} scope The scope of the callback
21388 onAvailable : function(id, fn, scope){
21389 all.on("add", function(index, o){
21391 fn.call(scope || o, o);
21392 all.un("add", fn, scope);
21399 * Ext JS Library 1.1.1
21400 * Copyright(c) 2006-2007, Ext JS, LLC.
21402 * Originally Released Under LGPL - original licence link has changed is not relivant.
21405 * <script type="text/javascript">
21409 * @class Roo.Component
21410 * @extends Roo.util.Observable
21411 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21412 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21413 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21414 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21415 * All visual components (widgets) that require rendering into a layout should subclass Component.
21417 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21418 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
21419 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21421 Roo.Component = function(config){
21422 config = config || {};
21423 if(config.tagName || config.dom || typeof config == "string"){ // element object
21424 config = {el: config, id: config.id || config};
21426 this.initialConfig = config;
21428 Roo.apply(this, config);
21432 * Fires after the component is disabled.
21433 * @param {Roo.Component} this
21438 * Fires after the component is enabled.
21439 * @param {Roo.Component} this
21443 * @event beforeshow
21444 * Fires before the component is shown. Return false to stop the show.
21445 * @param {Roo.Component} this
21450 * Fires after the component is shown.
21451 * @param {Roo.Component} this
21455 * @event beforehide
21456 * Fires before the component is hidden. Return false to stop the hide.
21457 * @param {Roo.Component} this
21462 * Fires after the component is hidden.
21463 * @param {Roo.Component} this
21467 * @event beforerender
21468 * Fires before the component is rendered. Return false to stop the render.
21469 * @param {Roo.Component} this
21471 beforerender : true,
21474 * Fires after the component is rendered.
21475 * @param {Roo.Component} this
21479 * @event beforedestroy
21480 * Fires before the component is destroyed. Return false to stop the destroy.
21481 * @param {Roo.Component} this
21483 beforedestroy : true,
21486 * Fires after the component is destroyed.
21487 * @param {Roo.Component} this
21492 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21494 Roo.ComponentMgr.register(this);
21495 Roo.Component.superclass.constructor.call(this);
21496 this.initComponent();
21497 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21498 this.render(this.renderTo);
21499 delete this.renderTo;
21504 Roo.Component.AUTO_ID = 1000;
21506 Roo.extend(Roo.Component, Roo.util.Observable, {
21508 * @property {Boolean} hidden
21509 * true if this component is hidden. Read-only.
21513 * true if this component is disabled. Read-only.
21517 * true if this component has been rendered. Read-only.
21521 /** @cfg {String} disableClass
21522 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21524 disabledClass : "x-item-disabled",
21525 /** @cfg {Boolean} allowDomMove
21526 * Whether the component can move the Dom node when rendering (defaults to true).
21528 allowDomMove : true,
21529 /** @cfg {String} hideMode
21530 * How this component should hidden. Supported values are
21531 * "visibility" (css visibility), "offsets" (negative offset position) and
21532 * "display" (css display) - defaults to "display".
21534 hideMode: 'display',
21537 ctype : "Roo.Component",
21539 /** @cfg {String} actionMode
21540 * which property holds the element that used for hide() / show() / disable() / enable()
21546 getActionEl : function(){
21547 return this[this.actionMode];
21550 initComponent : Roo.emptyFn,
21552 * If this is a lazy rendering component, render it to its container element.
21553 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
21555 render : function(container, position){
21556 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21557 if(!container && this.el){
21558 this.el = Roo.get(this.el);
21559 container = this.el.dom.parentNode;
21560 this.allowDomMove = false;
21562 this.container = Roo.get(container);
21563 this.rendered = true;
21564 if(position !== undefined){
21565 if(typeof position == 'number'){
21566 position = this.container.dom.childNodes[position];
21568 position = Roo.getDom(position);
21571 this.onRender(this.container, position || null);
21573 this.el.addClass(this.cls);
21577 this.el.applyStyles(this.style);
21580 this.fireEvent("render", this);
21581 this.afterRender(this.container);
21593 // default function is not really useful
21594 onRender : function(ct, position){
21596 this.el = Roo.get(this.el);
21597 if(this.allowDomMove !== false){
21598 ct.dom.insertBefore(this.el.dom, position);
21604 getAutoCreate : function(){
21605 var cfg = typeof this.autoCreate == "object" ?
21606 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21607 if(this.id && !cfg.id){
21614 afterRender : Roo.emptyFn,
21617 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21618 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21620 destroy : function(){
21621 if(this.fireEvent("beforedestroy", this) !== false){
21622 this.purgeListeners();
21623 this.beforeDestroy();
21625 this.el.removeAllListeners();
21627 if(this.actionMode == "container"){
21628 this.container.remove();
21632 Roo.ComponentMgr.unregister(this);
21633 this.fireEvent("destroy", this);
21638 beforeDestroy : function(){
21643 onDestroy : function(){
21648 * Returns the underlying {@link Roo.Element}.
21649 * @return {Roo.Element} The element
21651 getEl : function(){
21656 * Returns the id of this component.
21659 getId : function(){
21664 * Try to focus this component.
21665 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21666 * @return {Roo.Component} this
21668 focus : function(selectText){
21671 if(selectText === true){
21672 this.el.dom.select();
21687 * Disable this component.
21688 * @return {Roo.Component} this
21690 disable : function(){
21694 this.disabled = true;
21695 this.fireEvent("disable", this);
21700 onDisable : function(){
21701 this.getActionEl().addClass(this.disabledClass);
21702 this.el.dom.disabled = true;
21706 * Enable this component.
21707 * @return {Roo.Component} this
21709 enable : function(){
21713 this.disabled = false;
21714 this.fireEvent("enable", this);
21719 onEnable : function(){
21720 this.getActionEl().removeClass(this.disabledClass);
21721 this.el.dom.disabled = false;
21725 * Convenience function for setting disabled/enabled by boolean.
21726 * @param {Boolean} disabled
21728 setDisabled : function(disabled){
21729 this[disabled ? "disable" : "enable"]();
21733 * Show this component.
21734 * @return {Roo.Component} this
21737 if(this.fireEvent("beforeshow", this) !== false){
21738 this.hidden = false;
21742 this.fireEvent("show", this);
21748 onShow : function(){
21749 var ae = this.getActionEl();
21750 if(this.hideMode == 'visibility'){
21751 ae.dom.style.visibility = "visible";
21752 }else if(this.hideMode == 'offsets'){
21753 ae.removeClass('x-hidden');
21755 ae.dom.style.display = "";
21760 * Hide this component.
21761 * @return {Roo.Component} this
21764 if(this.fireEvent("beforehide", this) !== false){
21765 this.hidden = true;
21769 this.fireEvent("hide", this);
21775 onHide : function(){
21776 var ae = this.getActionEl();
21777 if(this.hideMode == 'visibility'){
21778 ae.dom.style.visibility = "hidden";
21779 }else if(this.hideMode == 'offsets'){
21780 ae.addClass('x-hidden');
21782 ae.dom.style.display = "none";
21787 * Convenience function to hide or show this component by boolean.
21788 * @param {Boolean} visible True to show, false to hide
21789 * @return {Roo.Component} this
21791 setVisible: function(visible){
21801 * Returns true if this component is visible.
21803 isVisible : function(){
21804 return this.getActionEl().isVisible();
21807 cloneConfig : function(overrides){
21808 overrides = overrides || {};
21809 var id = overrides.id || Roo.id();
21810 var cfg = Roo.applyIf(overrides, this.initialConfig);
21811 cfg.id = id; // prevent dup id
21812 return new this.constructor(cfg);
21816 * Ext JS Library 1.1.1
21817 * Copyright(c) 2006-2007, Ext JS, LLC.
21819 * Originally Released Under LGPL - original licence link has changed is not relivant.
21822 * <script type="text/javascript">
21827 * @extends Roo.Element
21828 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
21829 * automatic maintaining of shadow/shim positions.
21830 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
21831 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
21832 * you can pass a string with a CSS class name. False turns off the shadow.
21833 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
21834 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
21835 * @cfg {String} cls CSS class to add to the element
21836 * @cfg {Number} zindex Starting z-index (defaults to 11000)
21837 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
21839 * @param {Object} config An object with config options.
21840 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
21843 Roo.Layer = function(config, existingEl){
21844 config = config || {};
21845 var dh = Roo.DomHelper;
21846 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
21848 this.dom = Roo.getDom(existingEl);
21851 var o = config.dh || {tag: "div", cls: "x-layer"};
21852 this.dom = dh.append(pel, o);
21855 this.addClass(config.cls);
21857 this.constrain = config.constrain !== false;
21858 this.visibilityMode = Roo.Element.VISIBILITY;
21860 this.id = this.dom.id = config.id;
21862 this.id = Roo.id(this.dom);
21864 this.zindex = config.zindex || this.getZIndex();
21865 this.position("absolute", this.zindex);
21867 this.shadowOffset = config.shadowOffset || 4;
21868 this.shadow = new Roo.Shadow({
21869 offset : this.shadowOffset,
21870 mode : config.shadow
21873 this.shadowOffset = 0;
21875 this.useShim = config.shim !== false && Roo.useShims;
21876 this.useDisplay = config.useDisplay;
21880 var supr = Roo.Element.prototype;
21882 // shims are shared among layer to keep from having 100 iframes
21885 Roo.extend(Roo.Layer, Roo.Element, {
21887 getZIndex : function(){
21888 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
21891 getShim : function(){
21898 var shim = shims.shift();
21900 shim = this.createShim();
21901 shim.enableDisplayMode('block');
21902 shim.dom.style.display = 'none';
21903 shim.dom.style.visibility = 'visible';
21905 var pn = this.dom.parentNode;
21906 if(shim.dom.parentNode != pn){
21907 pn.insertBefore(shim.dom, this.dom);
21909 shim.setStyle('z-index', this.getZIndex()-2);
21914 hideShim : function(){
21916 this.shim.setDisplayed(false);
21917 shims.push(this.shim);
21922 disableShadow : function(){
21924 this.shadowDisabled = true;
21925 this.shadow.hide();
21926 this.lastShadowOffset = this.shadowOffset;
21927 this.shadowOffset = 0;
21931 enableShadow : function(show){
21933 this.shadowDisabled = false;
21934 this.shadowOffset = this.lastShadowOffset;
21935 delete this.lastShadowOffset;
21943 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
21944 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
21945 sync : function(doShow){
21946 var sw = this.shadow;
21947 if(!this.updating && this.isVisible() && (sw || this.useShim)){
21948 var sh = this.getShim();
21950 var w = this.getWidth(),
21951 h = this.getHeight();
21953 var l = this.getLeft(true),
21954 t = this.getTop(true);
21956 if(sw && !this.shadowDisabled){
21957 if(doShow && !sw.isVisible()){
21960 sw.realign(l, t, w, h);
21966 // fit the shim behind the shadow, so it is shimmed too
21967 var a = sw.adjusts, s = sh.dom.style;
21968 s.left = (Math.min(l, l+a.l))+"px";
21969 s.top = (Math.min(t, t+a.t))+"px";
21970 s.width = (w+a.w)+"px";
21971 s.height = (h+a.h)+"px";
21978 sh.setLeftTop(l, t);
21985 destroy : function(){
21988 this.shadow.hide();
21990 this.removeAllListeners();
21991 var pn = this.dom.parentNode;
21993 pn.removeChild(this.dom);
21995 Roo.Element.uncache(this.id);
21998 remove : function(){
22003 beginUpdate : function(){
22004 this.updating = true;
22008 endUpdate : function(){
22009 this.updating = false;
22014 hideUnders : function(negOffset){
22016 this.shadow.hide();
22022 constrainXY : function(){
22023 if(this.constrain){
22024 var vw = Roo.lib.Dom.getViewWidth(),
22025 vh = Roo.lib.Dom.getViewHeight();
22026 var s = Roo.get(document).getScroll();
22028 var xy = this.getXY();
22029 var x = xy[0], y = xy[1];
22030 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22031 // only move it if it needs it
22033 // first validate right/bottom
22034 if((x + w) > vw+s.left){
22035 x = vw - w - this.shadowOffset;
22038 if((y + h) > vh+s.top){
22039 y = vh - h - this.shadowOffset;
22042 // then make sure top/left isn't negative
22053 var ay = this.avoidY;
22054 if(y <= ay && (y+h) >= ay){
22060 supr.setXY.call(this, xy);
22066 isVisible : function(){
22067 return this.visible;
22071 showAction : function(){
22072 this.visible = true; // track visibility to prevent getStyle calls
22073 if(this.useDisplay === true){
22074 this.setDisplayed("");
22075 }else if(this.lastXY){
22076 supr.setXY.call(this, this.lastXY);
22077 }else if(this.lastLT){
22078 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22083 hideAction : function(){
22084 this.visible = false;
22085 if(this.useDisplay === true){
22086 this.setDisplayed(false);
22088 this.setLeftTop(-10000,-10000);
22092 // overridden Element method
22093 setVisible : function(v, a, d, c, e){
22098 var cb = function(){
22103 }.createDelegate(this);
22104 supr.setVisible.call(this, true, true, d, cb, e);
22107 this.hideUnders(true);
22116 }.createDelegate(this);
22118 supr.setVisible.call(this, v, a, d, cb, e);
22127 storeXY : function(xy){
22128 delete this.lastLT;
22132 storeLeftTop : function(left, top){
22133 delete this.lastXY;
22134 this.lastLT = [left, top];
22138 beforeFx : function(){
22139 this.beforeAction();
22140 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22144 afterFx : function(){
22145 Roo.Layer.superclass.afterFx.apply(this, arguments);
22146 this.sync(this.isVisible());
22150 beforeAction : function(){
22151 if(!this.updating && this.shadow){
22152 this.shadow.hide();
22156 // overridden Element method
22157 setLeft : function(left){
22158 this.storeLeftTop(left, this.getTop(true));
22159 supr.setLeft.apply(this, arguments);
22163 setTop : function(top){
22164 this.storeLeftTop(this.getLeft(true), top);
22165 supr.setTop.apply(this, arguments);
22169 setLeftTop : function(left, top){
22170 this.storeLeftTop(left, top);
22171 supr.setLeftTop.apply(this, arguments);
22175 setXY : function(xy, a, d, c, e){
22177 this.beforeAction();
22179 var cb = this.createCB(c);
22180 supr.setXY.call(this, xy, a, d, cb, e);
22187 createCB : function(c){
22198 // overridden Element method
22199 setX : function(x, a, d, c, e){
22200 this.setXY([x, this.getY()], a, d, c, e);
22203 // overridden Element method
22204 setY : function(y, a, d, c, e){
22205 this.setXY([this.getX(), y], a, d, c, e);
22208 // overridden Element method
22209 setSize : function(w, h, a, d, c, e){
22210 this.beforeAction();
22211 var cb = this.createCB(c);
22212 supr.setSize.call(this, w, h, a, d, cb, e);
22218 // overridden Element method
22219 setWidth : function(w, a, d, c, e){
22220 this.beforeAction();
22221 var cb = this.createCB(c);
22222 supr.setWidth.call(this, w, a, d, cb, e);
22228 // overridden Element method
22229 setHeight : function(h, a, d, c, e){
22230 this.beforeAction();
22231 var cb = this.createCB(c);
22232 supr.setHeight.call(this, h, a, d, cb, e);
22238 // overridden Element method
22239 setBounds : function(x, y, w, h, a, d, c, e){
22240 this.beforeAction();
22241 var cb = this.createCB(c);
22243 this.storeXY([x, y]);
22244 supr.setXY.call(this, [x, y]);
22245 supr.setSize.call(this, w, h, a, d, cb, e);
22248 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22254 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22255 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22256 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22257 * @param {Number} zindex The new z-index to set
22258 * @return {this} The Layer
22260 setZIndex : function(zindex){
22261 this.zindex = zindex;
22262 this.setStyle("z-index", zindex + 2);
22264 this.shadow.setZIndex(zindex + 1);
22267 this.shim.setStyle("z-index", zindex);
22273 * Ext JS Library 1.1.1
22274 * Copyright(c) 2006-2007, Ext JS, LLC.
22276 * Originally Released Under LGPL - original licence link has changed is not relivant.
22279 * <script type="text/javascript">
22284 * @class Roo.Shadow
22285 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22286 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22287 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22289 * Create a new Shadow
22290 * @param {Object} config The config object
22292 Roo.Shadow = function(config){
22293 Roo.apply(this, config);
22294 if(typeof this.mode != "string"){
22295 this.mode = this.defaultMode;
22297 var o = this.offset, a = {h: 0};
22298 var rad = Math.floor(this.offset/2);
22299 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22305 a.l -= this.offset + rad;
22306 a.t -= this.offset + rad;
22317 a.l -= (this.offset - rad);
22318 a.t -= this.offset + rad;
22320 a.w -= (this.offset - rad)*2;
22331 a.l -= (this.offset - rad);
22332 a.t -= (this.offset - rad);
22334 a.w -= (this.offset + rad + 1);
22335 a.h -= (this.offset + rad);
22344 Roo.Shadow.prototype = {
22346 * @cfg {String} mode
22347 * The shadow display mode. Supports the following options:<br />
22348 * sides: Shadow displays on both sides and bottom only<br />
22349 * frame: Shadow displays equally on all four sides<br />
22350 * drop: Traditional bottom-right drop shadow (default)
22353 * @cfg {String} offset
22354 * The number of pixels to offset the shadow from the element (defaults to 4)
22359 defaultMode: "drop",
22362 * Displays the shadow under the target element
22363 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22365 show : function(target){
22366 target = Roo.get(target);
22368 this.el = Roo.Shadow.Pool.pull();
22369 if(this.el.dom.nextSibling != target.dom){
22370 this.el.insertBefore(target);
22373 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22375 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22378 target.getLeft(true),
22379 target.getTop(true),
22383 this.el.dom.style.display = "block";
22387 * Returns true if the shadow is visible, else false
22389 isVisible : function(){
22390 return this.el ? true : false;
22394 * Direct alignment when values are already available. Show must be called at least once before
22395 * calling this method to ensure it is initialized.
22396 * @param {Number} left The target element left position
22397 * @param {Number} top The target element top position
22398 * @param {Number} width The target element width
22399 * @param {Number} height The target element height
22401 realign : function(l, t, w, h){
22405 var a = this.adjusts, d = this.el.dom, s = d.style;
22407 s.left = (l+a.l)+"px";
22408 s.top = (t+a.t)+"px";
22409 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22410 if(s.width != sws || s.height != shs){
22414 var cn = d.childNodes;
22415 var sww = Math.max(0, (sw-12))+"px";
22416 cn[0].childNodes[1].style.width = sww;
22417 cn[1].childNodes[1].style.width = sww;
22418 cn[2].childNodes[1].style.width = sww;
22419 cn[1].style.height = Math.max(0, (sh-12))+"px";
22425 * Hides this shadow
22429 this.el.dom.style.display = "none";
22430 Roo.Shadow.Pool.push(this.el);
22436 * Adjust the z-index of this shadow
22437 * @param {Number} zindex The new z-index
22439 setZIndex : function(z){
22442 this.el.setStyle("z-index", z);
22447 // Private utility class that manages the internal Shadow cache
22448 Roo.Shadow.Pool = function(){
22450 var markup = Roo.isIE ?
22451 '<div class="x-ie-shadow"></div>' :
22452 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
22455 var sh = p.shift();
22457 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22458 sh.autoBoxAdjust = false;
22463 push : function(sh){
22469 * Ext JS Library 1.1.1
22470 * Copyright(c) 2006-2007, Ext JS, LLC.
22472 * Originally Released Under LGPL - original licence link has changed is not relivant.
22475 * <script type="text/javascript">
22479 * @class Roo.BoxComponent
22480 * @extends Roo.Component
22481 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22482 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22483 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22484 * layout containers.
22486 * @param {Roo.Element/String/Object} config The configuration options.
22488 Roo.BoxComponent = function(config){
22489 Roo.Component.call(this, config);
22493 * Fires after the component is resized.
22494 * @param {Roo.Component} this
22495 * @param {Number} adjWidth The box-adjusted width that was set
22496 * @param {Number} adjHeight The box-adjusted height that was set
22497 * @param {Number} rawWidth The width that was originally specified
22498 * @param {Number} rawHeight The height that was originally specified
22503 * Fires after the component is moved.
22504 * @param {Roo.Component} this
22505 * @param {Number} x The new x position
22506 * @param {Number} y The new y position
22512 Roo.extend(Roo.BoxComponent, Roo.Component, {
22513 // private, set in afterRender to signify that the component has been rendered
22515 // private, used to defer height settings to subclasses
22516 deferHeight: false,
22517 /** @cfg {Number} width
22518 * width (optional) size of component
22520 /** @cfg {Number} height
22521 * height (optional) size of component
22525 * Sets the width and height of the component. This method fires the resize event. This method can accept
22526 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22527 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22528 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22529 * @return {Roo.BoxComponent} this
22531 setSize : function(w, h){
22532 // support for standard size objects
22533 if(typeof w == 'object'){
22538 if(!this.boxReady){
22544 // prevent recalcs when not needed
22545 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22548 this.lastSize = {width: w, height: h};
22550 var adj = this.adjustSize(w, h);
22551 var aw = adj.width, ah = adj.height;
22552 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22553 var rz = this.getResizeEl();
22554 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22555 rz.setSize(aw, ah);
22556 }else if(!this.deferHeight && ah !== undefined){
22558 }else if(aw !== undefined){
22561 this.onResize(aw, ah, w, h);
22562 this.fireEvent('resize', this, aw, ah, w, h);
22568 * Gets the current size of the component's underlying element.
22569 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22571 getSize : function(){
22572 return this.el.getSize();
22576 * Gets the current XY position of the component's underlying element.
22577 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22578 * @return {Array} The XY position of the element (e.g., [100, 200])
22580 getPosition : function(local){
22581 if(local === true){
22582 return [this.el.getLeft(true), this.el.getTop(true)];
22584 return this.xy || this.el.getXY();
22588 * Gets the current box measurements of the component's underlying element.
22589 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22590 * @returns {Object} box An object in the format {x, y, width, height}
22592 getBox : function(local){
22593 var s = this.el.getSize();
22595 s.x = this.el.getLeft(true);
22596 s.y = this.el.getTop(true);
22598 var xy = this.xy || this.el.getXY();
22606 * Sets the current box measurements of the component's underlying element.
22607 * @param {Object} box An object in the format {x, y, width, height}
22608 * @returns {Roo.BoxComponent} this
22610 updateBox : function(box){
22611 this.setSize(box.width, box.height);
22612 this.setPagePosition(box.x, box.y);
22617 getResizeEl : function(){
22618 return this.resizeEl || this.el;
22622 getPositionEl : function(){
22623 return this.positionEl || this.el;
22627 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22628 * This method fires the move event.
22629 * @param {Number} left The new left
22630 * @param {Number} top The new top
22631 * @returns {Roo.BoxComponent} this
22633 setPosition : function(x, y){
22636 if(!this.boxReady){
22639 var adj = this.adjustPosition(x, y);
22640 var ax = adj.x, ay = adj.y;
22642 var el = this.getPositionEl();
22643 if(ax !== undefined || ay !== undefined){
22644 if(ax !== undefined && ay !== undefined){
22645 el.setLeftTop(ax, ay);
22646 }else if(ax !== undefined){
22648 }else if(ay !== undefined){
22651 this.onPosition(ax, ay);
22652 this.fireEvent('move', this, ax, ay);
22658 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22659 * This method fires the move event.
22660 * @param {Number} x The new x position
22661 * @param {Number} y The new y position
22662 * @returns {Roo.BoxComponent} this
22664 setPagePosition : function(x, y){
22667 if(!this.boxReady){
22670 if(x === undefined || y === undefined){ // cannot translate undefined points
22673 var p = this.el.translatePoints(x, y);
22674 this.setPosition(p.left, p.top);
22679 onRender : function(ct, position){
22680 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22682 this.resizeEl = Roo.get(this.resizeEl);
22684 if(this.positionEl){
22685 this.positionEl = Roo.get(this.positionEl);
22690 afterRender : function(){
22691 Roo.BoxComponent.superclass.afterRender.call(this);
22692 this.boxReady = true;
22693 this.setSize(this.width, this.height);
22694 if(this.x || this.y){
22695 this.setPosition(this.x, this.y);
22697 if(this.pageX || this.pageY){
22698 this.setPagePosition(this.pageX, this.pageY);
22703 * Force the component's size to recalculate based on the underlying element's current height and width.
22704 * @returns {Roo.BoxComponent} this
22706 syncSize : function(){
22707 delete this.lastSize;
22708 this.setSize(this.el.getWidth(), this.el.getHeight());
22713 * Called after the component is resized, this method is empty by default but can be implemented by any
22714 * subclass that needs to perform custom logic after a resize occurs.
22715 * @param {Number} adjWidth The box-adjusted width that was set
22716 * @param {Number} adjHeight The box-adjusted height that was set
22717 * @param {Number} rawWidth The width that was originally specified
22718 * @param {Number} rawHeight The height that was originally specified
22720 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22725 * Called after the component is moved, this method is empty by default but can be implemented by any
22726 * subclass that needs to perform custom logic after a move occurs.
22727 * @param {Number} x The new x position
22728 * @param {Number} y The new y position
22730 onPosition : function(x, y){
22735 adjustSize : function(w, h){
22736 if(this.autoWidth){
22739 if(this.autoHeight){
22742 return {width : w, height: h};
22746 adjustPosition : function(x, y){
22747 return {x : x, y: y};
22751 * Ext JS Library 1.1.1
22752 * Copyright(c) 2006-2007, Ext JS, LLC.
22754 * Originally Released Under LGPL - original licence link has changed is not relivant.
22757 * <script type="text/javascript">
22762 * @class Roo.SplitBar
22763 * @extends Roo.util.Observable
22764 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
22768 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
22769 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
22770 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
22771 split.minSize = 100;
22772 split.maxSize = 600;
22773 split.animate = true;
22774 split.on('moved', splitterMoved);
22777 * Create a new SplitBar
22778 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
22779 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
22780 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22781 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
22782 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
22783 position of the SplitBar).
22785 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
22788 this.el = Roo.get(dragElement, true);
22789 this.el.dom.unselectable = "on";
22791 this.resizingEl = Roo.get(resizingElement, true);
22795 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22796 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
22799 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
22802 * The minimum size of the resizing element. (Defaults to 0)
22808 * The maximum size of the resizing element. (Defaults to 2000)
22811 this.maxSize = 2000;
22814 * Whether to animate the transition to the new size
22817 this.animate = false;
22820 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
22823 this.useShim = false;
22828 if(!existingProxy){
22830 this.proxy = Roo.SplitBar.createProxy(this.orientation);
22832 this.proxy = Roo.get(existingProxy).dom;
22835 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
22838 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
22841 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
22844 this.dragSpecs = {};
22847 * @private The adapter to use to positon and resize elements
22849 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
22850 this.adapter.init(this);
22852 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22854 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
22855 this.el.addClass("x-splitbar-h");
22858 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
22859 this.el.addClass("x-splitbar-v");
22865 * Fires when the splitter is moved (alias for {@link #event-moved})
22866 * @param {Roo.SplitBar} this
22867 * @param {Number} newSize the new width or height
22872 * Fires when the splitter is moved
22873 * @param {Roo.SplitBar} this
22874 * @param {Number} newSize the new width or height
22878 * @event beforeresize
22879 * Fires before the splitter is dragged
22880 * @param {Roo.SplitBar} this
22882 "beforeresize" : true,
22884 "beforeapply" : true
22887 Roo.util.Observable.call(this);
22890 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
22891 onStartProxyDrag : function(x, y){
22892 this.fireEvent("beforeresize", this);
22894 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
22896 o.enableDisplayMode("block");
22897 // all splitbars share the same overlay
22898 Roo.SplitBar.prototype.overlay = o;
22900 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
22901 this.overlay.show();
22902 Roo.get(this.proxy).setDisplayed("block");
22903 var size = this.adapter.getElementSize(this);
22904 this.activeMinSize = this.getMinimumSize();;
22905 this.activeMaxSize = this.getMaximumSize();;
22906 var c1 = size - this.activeMinSize;
22907 var c2 = Math.max(this.activeMaxSize - size, 0);
22908 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22909 this.dd.resetConstraints();
22910 this.dd.setXConstraint(
22911 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
22912 this.placement == Roo.SplitBar.LEFT ? c2 : c1
22914 this.dd.setYConstraint(0, 0);
22916 this.dd.resetConstraints();
22917 this.dd.setXConstraint(0, 0);
22918 this.dd.setYConstraint(
22919 this.placement == Roo.SplitBar.TOP ? c1 : c2,
22920 this.placement == Roo.SplitBar.TOP ? c2 : c1
22923 this.dragSpecs.startSize = size;
22924 this.dragSpecs.startPoint = [x, y];
22925 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
22929 * @private Called after the drag operation by the DDProxy
22931 onEndProxyDrag : function(e){
22932 Roo.get(this.proxy).setDisplayed(false);
22933 var endPoint = Roo.lib.Event.getXY(e);
22935 this.overlay.hide();
22938 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22939 newSize = this.dragSpecs.startSize +
22940 (this.placement == Roo.SplitBar.LEFT ?
22941 endPoint[0] - this.dragSpecs.startPoint[0] :
22942 this.dragSpecs.startPoint[0] - endPoint[0]
22945 newSize = this.dragSpecs.startSize +
22946 (this.placement == Roo.SplitBar.TOP ?
22947 endPoint[1] - this.dragSpecs.startPoint[1] :
22948 this.dragSpecs.startPoint[1] - endPoint[1]
22951 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
22952 if(newSize != this.dragSpecs.startSize){
22953 if(this.fireEvent('beforeapply', this, newSize) !== false){
22954 this.adapter.setElementSize(this, newSize);
22955 this.fireEvent("moved", this, newSize);
22956 this.fireEvent("resize", this, newSize);
22962 * Get the adapter this SplitBar uses
22963 * @return The adapter object
22965 getAdapter : function(){
22966 return this.adapter;
22970 * Set the adapter this SplitBar uses
22971 * @param {Object} adapter A SplitBar adapter object
22973 setAdapter : function(adapter){
22974 this.adapter = adapter;
22975 this.adapter.init(this);
22979 * Gets the minimum size for the resizing element
22980 * @return {Number} The minimum size
22982 getMinimumSize : function(){
22983 return this.minSize;
22987 * Sets the minimum size for the resizing element
22988 * @param {Number} minSize The minimum size
22990 setMinimumSize : function(minSize){
22991 this.minSize = minSize;
22995 * Gets the maximum size for the resizing element
22996 * @return {Number} The maximum size
22998 getMaximumSize : function(){
22999 return this.maxSize;
23003 * Sets the maximum size for the resizing element
23004 * @param {Number} maxSize The maximum size
23006 setMaximumSize : function(maxSize){
23007 this.maxSize = maxSize;
23011 * Sets the initialize size for the resizing element
23012 * @param {Number} size The initial size
23014 setCurrentSize : function(size){
23015 var oldAnimate = this.animate;
23016 this.animate = false;
23017 this.adapter.setElementSize(this, size);
23018 this.animate = oldAnimate;
23022 * Destroy this splitbar.
23023 * @param {Boolean} removeEl True to remove the element
23025 destroy : function(removeEl){
23027 this.shim.remove();
23030 this.proxy.parentNode.removeChild(this.proxy);
23038 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
23040 Roo.SplitBar.createProxy = function(dir){
23041 var proxy = new Roo.Element(document.createElement("div"));
23042 proxy.unselectable();
23043 var cls = 'x-splitbar-proxy';
23044 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23045 document.body.appendChild(proxy.dom);
23050 * @class Roo.SplitBar.BasicLayoutAdapter
23051 * Default Adapter. It assumes the splitter and resizing element are not positioned
23052 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23054 Roo.SplitBar.BasicLayoutAdapter = function(){
23057 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23058 // do nothing for now
23059 init : function(s){
23063 * Called before drag operations to get the current size of the resizing element.
23064 * @param {Roo.SplitBar} s The SplitBar using this adapter
23066 getElementSize : function(s){
23067 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23068 return s.resizingEl.getWidth();
23070 return s.resizingEl.getHeight();
23075 * Called after drag operations to set the size of the resizing element.
23076 * @param {Roo.SplitBar} s The SplitBar using this adapter
23077 * @param {Number} newSize The new size to set
23078 * @param {Function} onComplete A function to be invoked when resizing is complete
23080 setElementSize : function(s, newSize, onComplete){
23081 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23083 s.resizingEl.setWidth(newSize);
23085 onComplete(s, newSize);
23088 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23093 s.resizingEl.setHeight(newSize);
23095 onComplete(s, newSize);
23098 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23105 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23106 * @extends Roo.SplitBar.BasicLayoutAdapter
23107 * Adapter that moves the splitter element to align with the resized sizing element.
23108 * Used with an absolute positioned SplitBar.
23109 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23110 * document.body, make sure you assign an id to the body element.
23112 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23113 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23114 this.container = Roo.get(container);
23117 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23118 init : function(s){
23119 this.basic.init(s);
23122 getElementSize : function(s){
23123 return this.basic.getElementSize(s);
23126 setElementSize : function(s, newSize, onComplete){
23127 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23130 moveSplitter : function(s){
23131 var yes = Roo.SplitBar;
23132 switch(s.placement){
23134 s.el.setX(s.resizingEl.getRight());
23137 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23140 s.el.setY(s.resizingEl.getBottom());
23143 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23150 * Orientation constant - Create a vertical SplitBar
23154 Roo.SplitBar.VERTICAL = 1;
23157 * Orientation constant - Create a horizontal SplitBar
23161 Roo.SplitBar.HORIZONTAL = 2;
23164 * Placement constant - The resizing element is to the left of the splitter element
23168 Roo.SplitBar.LEFT = 1;
23171 * Placement constant - The resizing element is to the right of the splitter element
23175 Roo.SplitBar.RIGHT = 2;
23178 * Placement constant - The resizing element is positioned above the splitter element
23182 Roo.SplitBar.TOP = 3;
23185 * Placement constant - The resizing element is positioned under splitter element
23189 Roo.SplitBar.BOTTOM = 4;
23192 * Ext JS Library 1.1.1
23193 * Copyright(c) 2006-2007, Ext JS, LLC.
23195 * Originally Released Under LGPL - original licence link has changed is not relivant.
23198 * <script type="text/javascript">
23203 * @extends Roo.util.Observable
23204 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23205 * This class also supports single and multi selection modes. <br>
23206 * Create a data model bound view:
23208 var store = new Roo.data.Store(...);
23210 var view = new Roo.View("my-element",
23211 '<div id="{0}">{2} - {1}</div>', // auto create template
23213 singleSelect: true,
23214 selectedClass: "ydataview-selected",
23218 // listen for node click?
23219 view.on("click", function(vw, index, node, e){
23220 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23224 dataModel.load("foobar.xml");
23226 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23228 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23229 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23231 * Create a new View
23232 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
23233 * @param {String/DomHelper.Template} tpl The rendering template or a string to create a template with
23234 * @param {Object} config The config object
23236 Roo.View = function(container, tpl, config){
23237 this.el = Roo.get(container);
23238 if(typeof tpl == "string"){
23239 tpl = new Roo.Template(tpl);
23243 * The template used by this View
23244 * @type {Roo.DomHelper.Template}
23248 Roo.apply(this, config);
23253 * @event beforeclick
23254 * Fires before a click is processed. Returns false to cancel the default action.
23255 * @param {Roo.View} this
23256 * @param {Number} index The index of the target node
23257 * @param {HTMLElement} node The target node
23258 * @param {Roo.EventObject} e The raw event object
23260 "beforeclick" : true,
23263 * Fires when a template node is clicked.
23264 * @param {Roo.View} this
23265 * @param {Number} index The index of the target node
23266 * @param {HTMLElement} node The target node
23267 * @param {Roo.EventObject} e The raw event object
23272 * Fires when a template node is double clicked.
23273 * @param {Roo.View} this
23274 * @param {Number} index The index of the target node
23275 * @param {HTMLElement} node The target node
23276 * @param {Roo.EventObject} e The raw event object
23280 * @event contextmenu
23281 * Fires when a template node is right clicked.
23282 * @param {Roo.View} this
23283 * @param {Number} index The index of the target node
23284 * @param {HTMLElement} node The target node
23285 * @param {Roo.EventObject} e The raw event object
23287 "contextmenu" : true,
23289 * @event selectionchange
23290 * Fires when the selected nodes change.
23291 * @param {Roo.View} this
23292 * @param {Array} selections Array of the selected nodes
23294 "selectionchange" : true,
23297 * @event beforeselect
23298 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23299 * @param {Roo.View} this
23300 * @param {HTMLElement} node The node to be selected
23301 * @param {Array} selections Array of currently selected nodes
23303 "beforeselect" : true
23307 "click": this.onClick,
23308 "dblclick": this.onDblClick,
23309 "contextmenu": this.onContextMenu,
23313 this.selections = [];
23315 this.cmp = new Roo.CompositeElementLite([]);
23317 this.store = Roo.factory(this.store, Roo.data);
23318 this.setStore(this.store, true);
23320 Roo.View.superclass.constructor.call(this);
23323 Roo.extend(Roo.View, Roo.util.Observable, {
23325 * The css class to add to selected nodes
23326 * @type {Roo.DomHelper.Template}
23328 selectedClass : "x-view-selected",
23332 * Returns the element this view is bound to.
23333 * @return {Roo.Element}
23335 getEl : function(){
23340 * Refreshes the view.
23342 refresh : function(){
23344 this.clearSelections();
23345 this.el.update("");
23347 var records = this.store.getRange();
23348 if(records.length < 1){
23349 this.el.update(this.emptyText);
23352 for(var i = 0, len = records.length; i < len; i++){
23353 var data = this.prepareData(records[i].data, i, records[i]);
23354 html[html.length] = t.apply(data);
23356 this.el.update(html.join(""));
23357 this.nodes = this.el.dom.childNodes;
23358 this.updateIndexes(0);
23362 * Function to override to reformat the data that is sent to
23363 * the template for each node.
23364 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23365 * a JSON object for an UpdateManager bound view).
23367 prepareData : function(data){
23371 onUpdate : function(ds, record){
23372 this.clearSelections();
23373 var index = this.store.indexOf(record);
23374 var n = this.nodes[index];
23375 this.tpl.insertBefore(n, this.prepareData(record.data));
23376 n.parentNode.removeChild(n);
23377 this.updateIndexes(index, index);
23380 onAdd : function(ds, records, index){
23381 this.clearSelections();
23382 if(this.nodes.length == 0){
23386 var n = this.nodes[index];
23387 for(var i = 0, len = records.length; i < len; i++){
23388 var d = this.prepareData(records[i].data);
23390 this.tpl.insertBefore(n, d);
23392 this.tpl.append(this.el, d);
23395 this.updateIndexes(index);
23398 onRemove : function(ds, record, index){
23399 this.clearSelections();
23400 this.el.dom.removeChild(this.nodes[index]);
23401 this.updateIndexes(index);
23405 * Refresh an individual node.
23406 * @param {Number} index
23408 refreshNode : function(index){
23409 this.onUpdate(this.store, this.store.getAt(index));
23412 updateIndexes : function(startIndex, endIndex){
23413 var ns = this.nodes;
23414 startIndex = startIndex || 0;
23415 endIndex = endIndex || ns.length - 1;
23416 for(var i = startIndex; i <= endIndex; i++){
23417 ns[i].nodeIndex = i;
23422 * Changes the data store this view uses and refresh the view.
23423 * @param {Store} store
23425 setStore : function(store, initial){
23426 if(!initial && this.store){
23427 this.store.un("datachanged", this.refresh);
23428 this.store.un("add", this.onAdd);
23429 this.store.un("remove", this.onRemove);
23430 this.store.un("update", this.onUpdate);
23431 this.store.un("clear", this.refresh);
23435 store.on("datachanged", this.refresh, this);
23436 store.on("add", this.onAdd, this);
23437 store.on("remove", this.onRemove, this);
23438 store.on("update", this.onUpdate, this);
23439 store.on("clear", this.refresh, this);
23448 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23449 * @param {HTMLElement} node
23450 * @return {HTMLElement} The template node
23452 findItemFromChild : function(node){
23453 var el = this.el.dom;
23454 if(!node || node.parentNode == el){
23457 var p = node.parentNode;
23458 while(p && p != el){
23459 if(p.parentNode == el){
23468 onClick : function(e){
23469 var item = this.findItemFromChild(e.getTarget());
23471 var index = this.indexOf(item);
23472 if(this.onItemClick(item, index, e) !== false){
23473 this.fireEvent("click", this, index, item, e);
23476 this.clearSelections();
23481 onContextMenu : function(e){
23482 var item = this.findItemFromChild(e.getTarget());
23484 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23489 onDblClick : function(e){
23490 var item = this.findItemFromChild(e.getTarget());
23492 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23496 onItemClick : function(item, index, e){
23497 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23500 if(this.multiSelect || this.singleSelect){
23501 if(this.multiSelect && e.shiftKey && this.lastSelection){
23502 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23504 this.select(item, this.multiSelect && e.ctrlKey);
23505 this.lastSelection = item;
23507 e.preventDefault();
23513 * Get the number of selected nodes.
23516 getSelectionCount : function(){
23517 return this.selections.length;
23521 * Get the currently selected nodes.
23522 * @return {Array} An array of HTMLElements
23524 getSelectedNodes : function(){
23525 return this.selections;
23529 * Get the indexes of the selected nodes.
23532 getSelectedIndexes : function(){
23533 var indexes = [], s = this.selections;
23534 for(var i = 0, len = s.length; i < len; i++){
23535 indexes.push(s[i].nodeIndex);
23541 * Clear all selections
23542 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23544 clearSelections : function(suppressEvent){
23545 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23546 this.cmp.elements = this.selections;
23547 this.cmp.removeClass(this.selectedClass);
23548 this.selections = [];
23549 if(!suppressEvent){
23550 this.fireEvent("selectionchange", this, this.selections);
23556 * Returns true if the passed node is selected
23557 * @param {HTMLElement/Number} node The node or node index
23558 * @return {Boolean}
23560 isSelected : function(node){
23561 var s = this.selections;
23565 node = this.getNode(node);
23566 return s.indexOf(node) !== -1;
23571 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
23572 * @param {Boolean} keepExisting (optional) true to keep existing selections
23573 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23575 select : function(nodeInfo, keepExisting, suppressEvent){
23576 if(nodeInfo instanceof Array){
23578 this.clearSelections(true);
23580 for(var i = 0, len = nodeInfo.length; i < len; i++){
23581 this.select(nodeInfo[i], true, true);
23584 var node = this.getNode(nodeInfo);
23585 if(node && !this.isSelected(node)){
23587 this.clearSelections(true);
23589 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23590 Roo.fly(node).addClass(this.selectedClass);
23591 this.selections.push(node);
23592 if(!suppressEvent){
23593 this.fireEvent("selectionchange", this, this.selections);
23601 * Gets a template node.
23602 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23603 * @return {HTMLElement} The node or null if it wasn't found
23605 getNode : function(nodeInfo){
23606 if(typeof nodeInfo == "string"){
23607 return document.getElementById(nodeInfo);
23608 }else if(typeof nodeInfo == "number"){
23609 return this.nodes[nodeInfo];
23615 * Gets a range template nodes.
23616 * @param {Number} startIndex
23617 * @param {Number} endIndex
23618 * @return {Array} An array of nodes
23620 getNodes : function(start, end){
23621 var ns = this.nodes;
23622 start = start || 0;
23623 end = typeof end == "undefined" ? ns.length - 1 : end;
23626 for(var i = start; i <= end; i++){
23630 for(var i = start; i >= end; i--){
23638 * Finds the index of the passed node
23639 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23640 * @return {Number} The index of the node or -1
23642 indexOf : function(node){
23643 node = this.getNode(node);
23644 if(typeof node.nodeIndex == "number"){
23645 return node.nodeIndex;
23647 var ns = this.nodes;
23648 for(var i = 0, len = ns.length; i < len; i++){
23658 * Ext JS Library 1.1.1
23659 * Copyright(c) 2006-2007, Ext JS, LLC.
23661 * Originally Released Under LGPL - original licence link has changed is not relivant.
23664 * <script type="text/javascript">
23668 * @class Roo.JsonView
23669 * @extends Roo.View
23670 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23672 var view = new Roo.JsonView("my-element",
23673 '<div id="{id}">{foo} - {bar}</div>', // auto create template
23674 { multiSelect: true, jsonRoot: "data" }
23677 // listen for node click?
23678 view.on("click", function(vw, index, node, e){
23679 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23682 // direct load of JSON data
23683 view.load("foobar.php");
23685 // Example from my blog list
23686 var tpl = new Roo.Template(
23687 '<div class="entry">' +
23688 '<a class="entry-title" href="{link}">{title}</a>' +
23689 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23690 "</div><hr />"
23693 var moreView = new Roo.JsonView("entry-list", tpl, {
23696 moreView.on("beforerender", this.sortEntries, this);
23698 url: "/blog/get-posts.php",
23699 params: "allposts=true",
23700 text: "Loading Blog Entries..."
23704 * Create a new JsonView
23705 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
23706 * @param {Template} tpl The rendering template
23707 * @param {Object} config The config object
23709 Roo.JsonView = function(container, tpl, config){
23710 Roo.JsonView.superclass.constructor.call(this, container, tpl, config);
23712 var um = this.el.getUpdateManager();
23713 um.setRenderer(this);
23714 um.on("update", this.onLoad, this);
23715 um.on("failure", this.onLoadException, this);
23718 * @event beforerender
23719 * Fires before rendering of the downloaded JSON data.
23720 * @param {Roo.JsonView} this
23721 * @param {Object} data The JSON data loaded
23725 * Fires when data is loaded.
23726 * @param {Roo.JsonView} this
23727 * @param {Object} data The JSON data loaded
23728 * @param {Object} response The raw Connect response object
23731 * @event loadexception
23732 * Fires when loading fails.
23733 * @param {Roo.JsonView} this
23734 * @param {Object} response The raw Connect response object
23737 'beforerender' : true,
23739 'loadexception' : true
23742 Roo.extend(Roo.JsonView, Roo.View, {
23744 * The root property in the loaded JSON object that contains the data
23750 * Refreshes the view.
23752 refresh : function(){
23753 this.clearSelections();
23754 this.el.update("");
23756 var o = this.jsonData;
23757 if(o && o.length > 0){
23758 for(var i = 0, len = o.length; i < len; i++){
23759 var data = this.prepareData(o[i], i, o);
23760 html[html.length] = this.tpl.apply(data);
23763 html.push(this.emptyText);
23765 this.el.update(html.join(""));
23766 this.nodes = this.el.dom.childNodes;
23767 this.updateIndexes(0);
23771 * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
23772 * @param {Object/String/Function} url The URL for this request, or a function to call to get the URL, or a config object containing any of the following options:
23775 url: "your-url.php",
23776 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
23777 callback: yourFunction,
23778 scope: yourObject, //(optional scope)
23781 text: "Loading...",
23786 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
23787 * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
23788 * @param {String/Object} params (optional) The parameters to pass, as either a URL encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
23789 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
23790 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
23793 var um = this.el.getUpdateManager();
23794 um.update.apply(um, arguments);
23797 render : function(el, response){
23798 this.clearSelections();
23799 this.el.update("");
23802 o = Roo.util.JSON.decode(response.responseText);
23805 o = /** eval:var:o */ eval("o." + this.jsonRoot);
23810 * The current JSON data or null
23813 this.beforeRender();
23818 * Get the number of records in the current JSON dataset
23821 getCount : function(){
23822 return this.jsonData ? this.jsonData.length : 0;
23826 * Returns the JSON object for the specified node(s)
23827 * @param {HTMLElement/Array} node The node or an array of nodes
23828 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
23829 * you get the JSON object for the node
23831 getNodeData : function(node){
23832 if(node instanceof Array){
23834 for(var i = 0, len = node.length; i < len; i++){
23835 data.push(this.getNodeData(node[i]));
23839 return this.jsonData[this.indexOf(node)] || null;
23842 beforeRender : function(){
23843 this.snapshot = this.jsonData;
23845 this.sort.apply(this, this.sortInfo);
23847 this.fireEvent("beforerender", this, this.jsonData);
23850 onLoad : function(el, o){
23851 this.fireEvent("load", this, this.jsonData, o);
23854 onLoadException : function(el, o){
23855 this.fireEvent("loadexception", this, o);
23859 * Filter the data by a specific property.
23860 * @param {String} property A property on your JSON objects
23861 * @param {String/RegExp} value Either string that the property values
23862 * should start with, or a RegExp to test against the property
23864 filter : function(property, value){
23867 var ss = this.snapshot;
23868 if(typeof value == "string"){
23869 var vlen = value.length;
23871 this.clearFilter();
23874 value = value.toLowerCase();
23875 for(var i = 0, len = ss.length; i < len; i++){
23877 if(o[property].substr(0, vlen).toLowerCase() == value){
23881 } else if(value.exec){ // regex?
23882 for(var i = 0, len = ss.length; i < len; i++){
23884 if(value.test(o[property])){
23891 this.jsonData = data;
23897 * Filter by a function. The passed function will be called with each
23898 * object in the current dataset. If the function returns true the value is kept,
23899 * otherwise it is filtered.
23900 * @param {Function} fn
23901 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
23903 filterBy : function(fn, scope){
23906 var ss = this.snapshot;
23907 for(var i = 0, len = ss.length; i < len; i++){
23909 if(fn.call(scope || this, o)){
23913 this.jsonData = data;
23919 * Clears the current filter.
23921 clearFilter : function(){
23922 if(this.snapshot && this.jsonData != this.snapshot){
23923 this.jsonData = this.snapshot;
23930 * Sorts the data for this view and refreshes it.
23931 * @param {String} property A property on your JSON objects to sort on
23932 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
23933 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
23935 sort : function(property, dir, sortType){
23936 this.sortInfo = Array.prototype.slice.call(arguments, 0);
23939 var dsc = dir && dir.toLowerCase() == "desc";
23940 var f = function(o1, o2){
23941 var v1 = sortType ? sortType(o1[p]) : o1[p];
23942 var v2 = sortType ? sortType(o2[p]) : o2[p];
23945 return dsc ? +1 : -1;
23946 } else if(v1 > v2){
23947 return dsc ? -1 : +1;
23952 this.jsonData.sort(f);
23954 if(this.jsonData != this.snapshot){
23955 this.snapshot.sort(f);
23961 * Ext JS Library 1.1.1
23962 * Copyright(c) 2006-2007, Ext JS, LLC.
23964 * Originally Released Under LGPL - original licence link has changed is not relivant.
23967 * <script type="text/javascript">
23972 * @class Roo.ColorPalette
23973 * @extends Roo.Component
23974 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
23975 * Here's an example of typical usage:
23977 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
23978 cp.render('my-div');
23980 cp.on('select', function(palette, selColor){
23981 // do something with selColor
23985 * Create a new ColorPalette
23986 * @param {Object} config The config object
23988 Roo.ColorPalette = function(config){
23989 Roo.ColorPalette.superclass.constructor.call(this, config);
23993 * Fires when a color is selected
23994 * @param {ColorPalette} this
23995 * @param {String} color The 6-digit color hex code (without the # symbol)
24001 this.on("select", this.handler, this.scope, true);
24004 Roo.extend(Roo.ColorPalette, Roo.Component, {
24006 * @cfg {String} itemCls
24007 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24009 itemCls : "x-color-palette",
24011 * @cfg {String} value
24012 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24013 * the hex codes are case-sensitive.
24016 clickEvent:'click',
24018 ctype: "Roo.ColorPalette",
24021 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24023 allowReselect : false,
24026 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24027 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24028 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24029 * of colors with the width setting until the box is symmetrical.</p>
24030 * <p>You can override individual colors if needed:</p>
24032 var cp = new Roo.ColorPalette();
24033 cp.colors[0] = "FF0000"; // change the first box to red
24036 Or you can provide a custom array of your own for complete control:
24038 var cp = new Roo.ColorPalette();
24039 cp.colors = ["000000", "993300", "333300"];
24044 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24045 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24046 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24047 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24048 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24052 onRender : function(container, position){
24053 var t = new Roo.MasterTemplate(
24054 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24056 var c = this.colors;
24057 for(var i = 0, len = c.length; i < len; i++){
24060 var el = document.createElement("div");
24061 el.className = this.itemCls;
24063 container.dom.insertBefore(el, position);
24064 this.el = Roo.get(el);
24065 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24066 if(this.clickEvent != 'click'){
24067 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24072 afterRender : function(){
24073 Roo.ColorPalette.superclass.afterRender.call(this);
24075 var s = this.value;
24082 handleClick : function(e, t){
24083 e.preventDefault();
24084 if(!this.disabled){
24085 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24086 this.select(c.toUpperCase());
24091 * Selects the specified color in the palette (fires the select event)
24092 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24094 select : function(color){
24095 color = color.replace("#", "");
24096 if(color != this.value || this.allowReselect){
24099 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24101 el.child("a.color-"+color).addClass("x-color-palette-sel");
24102 this.value = color;
24103 this.fireEvent("select", this, color);
24108 * Ext JS Library 1.1.1
24109 * Copyright(c) 2006-2007, Ext JS, LLC.
24111 * Originally Released Under LGPL - original licence link has changed is not relivant.
24114 * <script type="text/javascript">
24118 * @class Roo.DatePicker
24119 * @extends Roo.Component
24120 * Simple date picker class.
24122 * Create a new DatePicker
24123 * @param {Object} config The config object
24125 Roo.DatePicker = function(config){
24126 Roo.DatePicker.superclass.constructor.call(this, config);
24128 this.value = config && config.value ?
24129 config.value.clearTime() : new Date().clearTime();
24134 * Fires when a date is selected
24135 * @param {DatePicker} this
24136 * @param {Date} date The selected date
24142 this.on("select", this.handler, this.scope || this);
24144 // build the disabledDatesRE
24145 if(!this.disabledDatesRE && this.disabledDates){
24146 var dd = this.disabledDates;
24148 for(var i = 0; i < dd.length; i++){
24150 if(i != dd.length-1) re += "|";
24152 this.disabledDatesRE = new RegExp(re + ")");
24156 Roo.extend(Roo.DatePicker, Roo.Component, {
24158 * @cfg {String} todayText
24159 * The text to display on the button that selects the current date (defaults to "Today")
24161 todayText : "Today",
24163 * @cfg {String} okText
24164 * The text to display on the ok button
24166 okText : " OK ", //   to give the user extra clicking room
24168 * @cfg {String} cancelText
24169 * The text to display on the cancel button
24171 cancelText : "Cancel",
24173 * @cfg {String} todayTip
24174 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24176 todayTip : "{0} (Spacebar)",
24178 * @cfg {Date} minDate
24179 * Minimum allowable date (JavaScript date object, defaults to null)
24183 * @cfg {Date} maxDate
24184 * Maximum allowable date (JavaScript date object, defaults to null)
24188 * @cfg {String} minText
24189 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24191 minText : "This date is before the minimum date",
24193 * @cfg {String} maxText
24194 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24196 maxText : "This date is after the maximum date",
24198 * @cfg {String} format
24199 * The default date format string which can be overriden for localization support. The format must be
24200 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24204 * @cfg {Array} disabledDays
24205 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24207 disabledDays : null,
24209 * @cfg {String} disabledDaysText
24210 * The tooltip to display when the date falls on a disabled day (defaults to "")
24212 disabledDaysText : "",
24214 * @cfg {RegExp} disabledDatesRE
24215 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24217 disabledDatesRE : null,
24219 * @cfg {String} disabledDatesText
24220 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24222 disabledDatesText : "",
24224 * @cfg {Boolean} constrainToViewport
24225 * True to constrain the date picker to the viewport (defaults to true)
24227 constrainToViewport : true,
24229 * @cfg {Array} monthNames
24230 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24232 monthNames : Date.monthNames,
24234 * @cfg {Array} dayNames
24235 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24237 dayNames : Date.dayNames,
24239 * @cfg {String} nextText
24240 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24242 nextText: 'Next Month (Control+Right)',
24244 * @cfg {String} prevText
24245 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24247 prevText: 'Previous Month (Control+Left)',
24249 * @cfg {String} monthYearText
24250 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24252 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24254 * @cfg {Number} startDay
24255 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24259 * @cfg {Bool} showClear
24260 * Show a clear button (usefull for date form elements that can be blank.)
24266 * Sets the value of the date field
24267 * @param {Date} value The date to set
24269 setValue : function(value){
24270 var old = this.value;
24271 this.value = value.clearTime(true);
24273 this.update(this.value);
24278 * Gets the current selected value of the date field
24279 * @return {Date} The selected date
24281 getValue : function(){
24286 focus : function(){
24288 this.update(this.activeDate);
24293 onRender : function(container, position){
24295 '<table cellspacing="0">',
24296 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',
24297 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24298 var dn = this.dayNames;
24299 for(var i = 0; i < 7; i++){
24300 var d = this.startDay+i;
24304 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24306 m[m.length] = "</tr></thead><tbody><tr>";
24307 for(var i = 0; i < 42; i++) {
24308 if(i % 7 == 0 && i != 0){
24309 m[m.length] = "</tr><tr>";
24311 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24313 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24314 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24316 var el = document.createElement("div");
24317 el.className = "x-date-picker";
24318 el.innerHTML = m.join("");
24320 container.dom.insertBefore(el, position);
24322 this.el = Roo.get(el);
24323 this.eventEl = Roo.get(el.firstChild);
24325 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24326 handler: this.showPrevMonth,
24328 preventDefault:true,
24332 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24333 handler: this.showNextMonth,
24335 preventDefault:true,
24339 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24341 this.monthPicker = this.el.down('div.x-date-mp');
24342 this.monthPicker.enableDisplayMode('block');
24344 var kn = new Roo.KeyNav(this.eventEl, {
24345 "left" : function(e){
24347 this.showPrevMonth() :
24348 this.update(this.activeDate.add("d", -1));
24351 "right" : function(e){
24353 this.showNextMonth() :
24354 this.update(this.activeDate.add("d", 1));
24357 "up" : function(e){
24359 this.showNextYear() :
24360 this.update(this.activeDate.add("d", -7));
24363 "down" : function(e){
24365 this.showPrevYear() :
24366 this.update(this.activeDate.add("d", 7));
24369 "pageUp" : function(e){
24370 this.showNextMonth();
24373 "pageDown" : function(e){
24374 this.showPrevMonth();
24377 "enter" : function(e){
24378 e.stopPropagation();
24385 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24387 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24389 this.el.unselectable();
24391 this.cells = this.el.select("table.x-date-inner tbody td");
24392 this.textNodes = this.el.query("table.x-date-inner tbody span");
24394 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24396 tooltip: this.monthYearText
24399 this.mbtn.on('click', this.showMonthPicker, this);
24400 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24403 var today = (new Date()).dateFormat(this.format);
24405 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24407 text: String.format(this.todayText, today),
24408 tooltip: String.format(this.todayTip, today),
24409 handler: this.selectToday,
24413 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24416 if (this.showClear) {
24418 baseTb.add( new Roo.Toolbar.Fill());
24421 cls: 'x-btn-icon x-btn-clear',
24422 handler: function() {
24424 this.fireEvent("select", this, '');
24434 this.update(this.value);
24437 createMonthPicker : function(){
24438 if(!this.monthPicker.dom.firstChild){
24439 var buf = ['<table border="0" cellspacing="0">'];
24440 for(var i = 0; i < 6; i++){
24442 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24443 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24445 '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
24446 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24450 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24452 '</button><button type="button" class="x-date-mp-cancel">',
24454 '</button></td></tr>',
24457 this.monthPicker.update(buf.join(''));
24458 this.monthPicker.on('click', this.onMonthClick, this);
24459 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24461 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24462 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24464 this.mpMonths.each(function(m, a, i){
24467 m.dom.xmonth = 5 + Math.round(i * .5);
24469 m.dom.xmonth = Math.round((i-1) * .5);
24475 showMonthPicker : function(){
24476 this.createMonthPicker();
24477 var size = this.el.getSize();
24478 this.monthPicker.setSize(size);
24479 this.monthPicker.child('table').setSize(size);
24481 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24482 this.updateMPMonth(this.mpSelMonth);
24483 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24484 this.updateMPYear(this.mpSelYear);
24486 this.monthPicker.slideIn('t', {duration:.2});
24489 updateMPYear : function(y){
24491 var ys = this.mpYears.elements;
24492 for(var i = 1; i <= 10; i++){
24493 var td = ys[i-1], y2;
24495 y2 = y + Math.round(i * .5);
24496 td.firstChild.innerHTML = y2;
24499 y2 = y - (5-Math.round(i * .5));
24500 td.firstChild.innerHTML = y2;
24503 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24507 updateMPMonth : function(sm){
24508 this.mpMonths.each(function(m, a, i){
24509 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24513 selectMPMonth: function(m){
24517 onMonthClick : function(e, t){
24519 var el = new Roo.Element(t), pn;
24520 if(el.is('button.x-date-mp-cancel')){
24521 this.hideMonthPicker();
24523 else if(el.is('button.x-date-mp-ok')){
24524 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24525 this.hideMonthPicker();
24527 else if(pn = el.up('td.x-date-mp-month', 2)){
24528 this.mpMonths.removeClass('x-date-mp-sel');
24529 pn.addClass('x-date-mp-sel');
24530 this.mpSelMonth = pn.dom.xmonth;
24532 else if(pn = el.up('td.x-date-mp-year', 2)){
24533 this.mpYears.removeClass('x-date-mp-sel');
24534 pn.addClass('x-date-mp-sel');
24535 this.mpSelYear = pn.dom.xyear;
24537 else if(el.is('a.x-date-mp-prev')){
24538 this.updateMPYear(this.mpyear-10);
24540 else if(el.is('a.x-date-mp-next')){
24541 this.updateMPYear(this.mpyear+10);
24545 onMonthDblClick : function(e, t){
24547 var el = new Roo.Element(t), pn;
24548 if(pn = el.up('td.x-date-mp-month', 2)){
24549 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24550 this.hideMonthPicker();
24552 else if(pn = el.up('td.x-date-mp-year', 2)){
24553 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24554 this.hideMonthPicker();
24558 hideMonthPicker : function(disableAnim){
24559 if(this.monthPicker){
24560 if(disableAnim === true){
24561 this.monthPicker.hide();
24563 this.monthPicker.slideOut('t', {duration:.2});
24569 showPrevMonth : function(e){
24570 this.update(this.activeDate.add("mo", -1));
24574 showNextMonth : function(e){
24575 this.update(this.activeDate.add("mo", 1));
24579 showPrevYear : function(){
24580 this.update(this.activeDate.add("y", -1));
24584 showNextYear : function(){
24585 this.update(this.activeDate.add("y", 1));
24589 handleMouseWheel : function(e){
24590 var delta = e.getWheelDelta();
24592 this.showPrevMonth();
24594 } else if(delta < 0){
24595 this.showNextMonth();
24601 handleDateClick : function(e, t){
24603 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24604 this.setValue(new Date(t.dateValue));
24605 this.fireEvent("select", this, this.value);
24610 selectToday : function(){
24611 this.setValue(new Date().clearTime());
24612 this.fireEvent("select", this, this.value);
24616 update : function(date){
24617 var vd = this.activeDate;
24618 this.activeDate = date;
24620 var t = date.getTime();
24621 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24622 this.cells.removeClass("x-date-selected");
24623 this.cells.each(function(c){
24624 if(c.dom.firstChild.dateValue == t){
24625 c.addClass("x-date-selected");
24626 setTimeout(function(){
24627 try{c.dom.firstChild.focus();}catch(e){}
24635 var days = date.getDaysInMonth();
24636 var firstOfMonth = date.getFirstDateOfMonth();
24637 var startingPos = firstOfMonth.getDay()-this.startDay;
24639 if(startingPos <= this.startDay){
24643 var pm = date.add("mo", -1);
24644 var prevStart = pm.getDaysInMonth()-startingPos;
24646 var cells = this.cells.elements;
24647 var textEls = this.textNodes;
24648 days += startingPos;
24650 // convert everything to numbers so it's fast
24651 var day = 86400000;
24652 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24653 var today = new Date().clearTime().getTime();
24654 var sel = date.clearTime().getTime();
24655 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24656 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24657 var ddMatch = this.disabledDatesRE;
24658 var ddText = this.disabledDatesText;
24659 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24660 var ddaysText = this.disabledDaysText;
24661 var format = this.format;
24663 var setCellClass = function(cal, cell){
24665 var t = d.getTime();
24666 cell.firstChild.dateValue = t;
24668 cell.className += " x-date-today";
24669 cell.title = cal.todayText;
24672 cell.className += " x-date-selected";
24673 setTimeout(function(){
24674 try{cell.firstChild.focus();}catch(e){}
24679 cell.className = " x-date-disabled";
24680 cell.title = cal.minText;
24684 cell.className = " x-date-disabled";
24685 cell.title = cal.maxText;
24689 if(ddays.indexOf(d.getDay()) != -1){
24690 cell.title = ddaysText;
24691 cell.className = " x-date-disabled";
24694 if(ddMatch && format){
24695 var fvalue = d.dateFormat(format);
24696 if(ddMatch.test(fvalue)){
24697 cell.title = ddText.replace("%0", fvalue);
24698 cell.className = " x-date-disabled";
24704 for(; i < startingPos; i++) {
24705 textEls[i].innerHTML = (++prevStart);
24706 d.setDate(d.getDate()+1);
24707 cells[i].className = "x-date-prevday";
24708 setCellClass(this, cells[i]);
24710 for(; i < days; i++){
24711 intDay = i - startingPos + 1;
24712 textEls[i].innerHTML = (intDay);
24713 d.setDate(d.getDate()+1);
24714 cells[i].className = "x-date-active";
24715 setCellClass(this, cells[i]);
24718 for(; i < 42; i++) {
24719 textEls[i].innerHTML = (++extraDays);
24720 d.setDate(d.getDate()+1);
24721 cells[i].className = "x-date-nextday";
24722 setCellClass(this, cells[i]);
24725 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
24727 if(!this.internalRender){
24728 var main = this.el.dom.firstChild;
24729 var w = main.offsetWidth;
24730 this.el.setWidth(w + this.el.getBorderWidth("lr"));
24731 Roo.fly(main).setWidth(w);
24732 this.internalRender = true;
24733 // opera does not respect the auto grow header center column
24734 // then, after it gets a width opera refuses to recalculate
24735 // without a second pass
24736 if(Roo.isOpera && !this.secondPass){
24737 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
24738 this.secondPass = true;
24739 this.update.defer(10, this, [date]);
24745 * Ext JS Library 1.1.1
24746 * Copyright(c) 2006-2007, Ext JS, LLC.
24748 * Originally Released Under LGPL - original licence link has changed is not relivant.
24751 * <script type="text/javascript">
24754 * @class Roo.TabPanel
24755 * @extends Roo.util.Observable
24756 * A lightweight tab container.
24760 // basic tabs 1, built from existing content
24761 var tabs = new Roo.TabPanel("tabs1");
24762 tabs.addTab("script", "View Script");
24763 tabs.addTab("markup", "View Markup");
24764 tabs.activate("script");
24766 // more advanced tabs, built from javascript
24767 var jtabs = new Roo.TabPanel("jtabs");
24768 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
24770 // set up the UpdateManager
24771 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
24772 var updater = tab2.getUpdateManager();
24773 updater.setDefaultUrl("ajax1.htm");
24774 tab2.on('activate', updater.refresh, updater, true);
24776 // Use setUrl for Ajax loading
24777 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
24778 tab3.setUrl("ajax2.htm", null, true);
24781 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
24784 jtabs.activate("jtabs-1");
24787 * Create a new TabPanel.
24788 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
24789 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
24791 Roo.TabPanel = function(container, config){
24793 * The container element for this TabPanel.
24794 * @type Roo.Element
24796 this.el = Roo.get(container, true);
24798 if(typeof config == "boolean"){
24799 this.tabPosition = config ? "bottom" : "top";
24801 Roo.apply(this, config);
24804 if(this.tabPosition == "bottom"){
24805 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24806 this.el.addClass("x-tabs-bottom");
24808 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
24809 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
24810 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
24812 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
24814 if(this.tabPosition != "bottom"){
24815 /** The body element that contains {@link Roo.TabPanelItem} bodies.
24816 * @type Roo.Element
24818 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24819 this.el.addClass("x-tabs-top");
24823 this.bodyEl.setStyle("position", "relative");
24825 this.active = null;
24826 this.activateDelegate = this.activate.createDelegate(this);
24831 * Fires when the active tab changes
24832 * @param {Roo.TabPanel} this
24833 * @param {Roo.TabPanelItem} activePanel The new active tab
24837 * @event beforetabchange
24838 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
24839 * @param {Roo.TabPanel} this
24840 * @param {Object} e Set cancel to true on this object to cancel the tab change
24841 * @param {Roo.TabPanelItem} tab The tab being changed to
24843 "beforetabchange" : true
24846 Roo.EventManager.onWindowResize(this.onResize, this);
24847 this.cpad = this.el.getPadding("lr");
24848 this.hiddenCount = 0;
24850 Roo.TabPanel.superclass.constructor.call(this);
24853 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
24855 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
24857 tabPosition : "top",
24859 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
24861 currentTabWidth : 0,
24863 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
24867 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
24871 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
24873 preferredTabWidth : 175,
24875 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
24877 resizeTabs : false,
24879 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
24881 monitorResize : true,
24884 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
24885 * @param {String} id The id of the div to use <b>or create</b>
24886 * @param {String} text The text for the tab
24887 * @param {String} content (optional) Content to put in the TabPanelItem body
24888 * @param {Boolean} closable (optional) True to create a close icon on the tab
24889 * @return {Roo.TabPanelItem} The created TabPanelItem
24891 addTab : function(id, text, content, closable){
24892 var item = new Roo.TabPanelItem(this, id, text, closable);
24893 this.addTabItem(item);
24895 item.setContent(content);
24901 * Returns the {@link Roo.TabPanelItem} with the specified id/index
24902 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
24903 * @return {Roo.TabPanelItem}
24905 getTab : function(id){
24906 return this.items[id];
24910 * Hides the {@link Roo.TabPanelItem} with the specified id/index
24911 * @param {String/Number} id The id or index of the TabPanelItem to hide.
24913 hideTab : function(id){
24914 var t = this.items[id];
24917 this.hiddenCount++;
24918 this.autoSizeTabs();
24923 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
24924 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
24926 unhideTab : function(id){
24927 var t = this.items[id];
24929 t.setHidden(false);
24930 this.hiddenCount--;
24931 this.autoSizeTabs();
24936 * Adds an existing {@link Roo.TabPanelItem}.
24937 * @param {Roo.TabPanelItem} item The TabPanelItem to add
24939 addTabItem : function(item){
24940 this.items[item.id] = item;
24941 this.items.push(item);
24942 if(this.resizeTabs){
24943 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
24944 this.autoSizeTabs();
24951 * Removes a {@link Roo.TabPanelItem}.
24952 * @param {String/Number} id The id or index of the TabPanelItem to remove.
24954 removeTab : function(id){
24955 var items = this.items;
24956 var tab = items[id];
24958 var index = items.indexOf(tab);
24959 if(this.active == tab && items.length > 1){
24960 var newTab = this.getNextAvailable(index);
24961 if(newTab)newTab.activate();
24963 this.stripEl.dom.removeChild(tab.pnode.dom);
24964 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
24965 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
24967 items.splice(index, 1);
24968 delete this.items[tab.id];
24969 tab.fireEvent("close", tab);
24970 tab.purgeListeners();
24971 this.autoSizeTabs();
24974 getNextAvailable : function(start){
24975 var items = this.items;
24977 // look for a next tab that will slide over to
24978 // replace the one being removed
24979 while(index < items.length){
24980 var item = items[++index];
24981 if(item && !item.isHidden()){
24985 // if one isn't found select the previous tab (on the left)
24988 var item = items[--index];
24989 if(item && !item.isHidden()){
24997 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
24998 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25000 disableTab : function(id){
25001 var tab = this.items[id];
25002 if(tab && this.active != tab){
25008 * Enables a {@link Roo.TabPanelItem} that is disabled.
25009 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25011 enableTab : function(id){
25012 var tab = this.items[id];
25017 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25018 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25019 * @return {Roo.TabPanelItem} The TabPanelItem.
25021 activate : function(id){
25022 var tab = this.items[id];
25026 if(tab == this.active || tab.disabled){
25030 this.fireEvent("beforetabchange", this, e, tab);
25031 if(e.cancel !== true && !tab.disabled){
25033 this.active.hide();
25035 this.active = this.items[id];
25036 this.active.show();
25037 this.fireEvent("tabchange", this, this.active);
25043 * Gets the active {@link Roo.TabPanelItem}.
25044 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25046 getActiveTab : function(){
25047 return this.active;
25051 * Updates the tab body element to fit the height of the container element
25052 * for overflow scrolling
25053 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25055 syncHeight : function(targetHeight){
25056 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25057 var bm = this.bodyEl.getMargins();
25058 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25059 this.bodyEl.setHeight(newHeight);
25063 onResize : function(){
25064 if(this.monitorResize){
25065 this.autoSizeTabs();
25070 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25072 beginUpdate : function(){
25073 this.updating = true;
25077 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25079 endUpdate : function(){
25080 this.updating = false;
25081 this.autoSizeTabs();
25085 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25087 autoSizeTabs : function(){
25088 var count = this.items.length;
25089 var vcount = count - this.hiddenCount;
25090 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25091 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25092 var availWidth = Math.floor(w / vcount);
25093 var b = this.stripBody;
25094 if(b.getWidth() > w){
25095 var tabs = this.items;
25096 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25097 if(availWidth < this.minTabWidth){
25098 /*if(!this.sleft){ // incomplete scrolling code
25099 this.createScrollButtons();
25102 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25105 if(this.currentTabWidth < this.preferredTabWidth){
25106 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25112 * Returns the number of tabs in this TabPanel.
25115 getCount : function(){
25116 return this.items.length;
25120 * Resizes all the tabs to the passed width
25121 * @param {Number} The new width
25123 setTabWidth : function(width){
25124 this.currentTabWidth = width;
25125 for(var i = 0, len = this.items.length; i < len; i++) {
25126 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25131 * Destroys this TabPanel
25132 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25134 destroy : function(removeEl){
25135 Roo.EventManager.removeResizeListener(this.onResize, this);
25136 for(var i = 0, len = this.items.length; i < len; i++){
25137 this.items[i].purgeListeners();
25139 if(removeEl === true){
25140 this.el.update("");
25147 * @class Roo.TabPanelItem
25148 * @extends Roo.util.Observable
25149 * Represents an individual item (tab plus body) in a TabPanel.
25150 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25151 * @param {String} id The id of this TabPanelItem
25152 * @param {String} text The text for the tab of this TabPanelItem
25153 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25155 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25157 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25158 * @type Roo.TabPanel
25160 this.tabPanel = tabPanel;
25162 * The id for this TabPanelItem
25167 this.disabled = false;
25171 this.loaded = false;
25172 this.closable = closable;
25175 * The body element for this TabPanelItem.
25176 * @type Roo.Element
25178 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25179 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25180 this.bodyEl.setStyle("display", "block");
25181 this.bodyEl.setStyle("zoom", "1");
25184 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25186 this.el = Roo.get(els.el, true);
25187 this.inner = Roo.get(els.inner, true);
25188 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25189 this.pnode = Roo.get(els.el.parentNode, true);
25190 this.el.on("mousedown", this.onTabMouseDown, this);
25191 this.el.on("click", this.onTabClick, this);
25194 var c = Roo.get(els.close, true);
25195 c.dom.title = this.closeText;
25196 c.addClassOnOver("close-over");
25197 c.on("click", this.closeClick, this);
25203 * Fires when this tab becomes the active tab.
25204 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25205 * @param {Roo.TabPanelItem} this
25209 * @event beforeclose
25210 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25211 * @param {Roo.TabPanelItem} this
25212 * @param {Object} e Set cancel to true on this object to cancel the close.
25214 "beforeclose": true,
25217 * Fires when this tab is closed.
25218 * @param {Roo.TabPanelItem} this
25222 * @event deactivate
25223 * Fires when this tab is no longer the active tab.
25224 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25225 * @param {Roo.TabPanelItem} this
25227 "deactivate" : true
25229 this.hidden = false;
25231 Roo.TabPanelItem.superclass.constructor.call(this);
25234 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25235 purgeListeners : function(){
25236 Roo.util.Observable.prototype.purgeListeners.call(this);
25237 this.el.removeAllListeners();
25240 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25243 this.pnode.addClass("on");
25246 this.tabPanel.stripWrap.repaint();
25248 this.fireEvent("activate", this.tabPanel, this);
25252 * Returns true if this tab is the active tab.
25253 * @return {Boolean}
25255 isActive : function(){
25256 return this.tabPanel.getActiveTab() == this;
25260 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25263 this.pnode.removeClass("on");
25265 this.fireEvent("deactivate", this.tabPanel, this);
25268 hideAction : function(){
25269 this.bodyEl.hide();
25270 this.bodyEl.setStyle("position", "absolute");
25271 this.bodyEl.setLeft("-20000px");
25272 this.bodyEl.setTop("-20000px");
25275 showAction : function(){
25276 this.bodyEl.setStyle("position", "relative");
25277 this.bodyEl.setTop("");
25278 this.bodyEl.setLeft("");
25279 this.bodyEl.show();
25283 * Set the tooltip for the tab.
25284 * @param {String} tooltip The tab's tooltip
25286 setTooltip : function(text){
25287 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25288 this.textEl.dom.qtip = text;
25289 this.textEl.dom.removeAttribute('title');
25291 this.textEl.dom.title = text;
25295 onTabClick : function(e){
25296 e.preventDefault();
25297 this.tabPanel.activate(this.id);
25300 onTabMouseDown : function(e){
25301 e.preventDefault();
25302 this.tabPanel.activate(this.id);
25305 getWidth : function(){
25306 return this.inner.getWidth();
25309 setWidth : function(width){
25310 var iwidth = width - this.pnode.getPadding("lr");
25311 this.inner.setWidth(iwidth);
25312 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25313 this.pnode.setWidth(width);
25317 * Show or hide the tab
25318 * @param {Boolean} hidden True to hide or false to show.
25320 setHidden : function(hidden){
25321 this.hidden = hidden;
25322 this.pnode.setStyle("display", hidden ? "none" : "");
25326 * Returns true if this tab is "hidden"
25327 * @return {Boolean}
25329 isHidden : function(){
25330 return this.hidden;
25334 * Returns the text for this tab
25337 getText : function(){
25341 autoSize : function(){
25342 //this.el.beginMeasure();
25343 this.textEl.setWidth(1);
25344 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25345 //this.el.endMeasure();
25349 * Sets the text for the tab (Note: this also sets the tooltip text)
25350 * @param {String} text The tab's text and tooltip
25352 setText : function(text){
25354 this.textEl.update(text);
25355 this.setTooltip(text);
25356 if(!this.tabPanel.resizeTabs){
25361 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25363 activate : function(){
25364 this.tabPanel.activate(this.id);
25368 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25370 disable : function(){
25371 if(this.tabPanel.active != this){
25372 this.disabled = true;
25373 this.pnode.addClass("disabled");
25378 * Enables this TabPanelItem if it was previously disabled.
25380 enable : function(){
25381 this.disabled = false;
25382 this.pnode.removeClass("disabled");
25386 * Sets the content for this TabPanelItem.
25387 * @param {String} content The content
25388 * @param {Boolean} loadScripts true to look for and load scripts
25390 setContent : function(content, loadScripts){
25391 this.bodyEl.update(content, loadScripts);
25395 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25396 * @return {Roo.UpdateManager} The UpdateManager
25398 getUpdateManager : function(){
25399 return this.bodyEl.getUpdateManager();
25403 * Set a URL to be used to load the content for this TabPanelItem.
25404 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25405 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
25406 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
25407 * @return {Roo.UpdateManager} The UpdateManager
25409 setUrl : function(url, params, loadOnce){
25410 if(this.refreshDelegate){
25411 this.un('activate', this.refreshDelegate);
25413 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25414 this.on("activate", this.refreshDelegate);
25415 return this.bodyEl.getUpdateManager();
25419 _handleRefresh : function(url, params, loadOnce){
25420 if(!loadOnce || !this.loaded){
25421 var updater = this.bodyEl.getUpdateManager();
25422 updater.update(url, params, this._setLoaded.createDelegate(this));
25427 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25428 * Will fail silently if the setUrl method has not been called.
25429 * This does not activate the panel, just updates its content.
25431 refresh : function(){
25432 if(this.refreshDelegate){
25433 this.loaded = false;
25434 this.refreshDelegate();
25439 _setLoaded : function(){
25440 this.loaded = true;
25444 closeClick : function(e){
25447 this.fireEvent("beforeclose", this, o);
25448 if(o.cancel !== true){
25449 this.tabPanel.removeTab(this.id);
25453 * The text displayed in the tooltip for the close icon.
25456 closeText : "Close this tab"
25460 Roo.TabPanel.prototype.createStrip = function(container){
25461 var strip = document.createElement("div");
25462 strip.className = "x-tabs-wrap";
25463 container.appendChild(strip);
25467 Roo.TabPanel.prototype.createStripList = function(strip){
25468 // div wrapper for retard IE
25469 strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
25470 return strip.firstChild.firstChild.firstChild.firstChild;
25473 Roo.TabPanel.prototype.createBody = function(container){
25474 var body = document.createElement("div");
25475 Roo.id(body, "tab-body");
25476 Roo.fly(body).addClass("x-tabs-body");
25477 container.appendChild(body);
25481 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25482 var body = Roo.getDom(id);
25484 body = document.createElement("div");
25487 Roo.fly(body).addClass("x-tabs-item-body");
25488 bodyEl.insertBefore(body, bodyEl.firstChild);
25492 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25493 var td = document.createElement("td");
25494 stripEl.appendChild(td);
25496 td.className = "x-tabs-closable";
25497 if(!this.closeTpl){
25498 this.closeTpl = new Roo.Template(
25499 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25500 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25501 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25504 var el = this.closeTpl.overwrite(td, {"text": text});
25505 var close = el.getElementsByTagName("div")[0];
25506 var inner = el.getElementsByTagName("em")[0];
25507 return {"el": el, "close": close, "inner": inner};
25510 this.tabTpl = new Roo.Template(
25511 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25512 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25515 var el = this.tabTpl.overwrite(td, {"text": text});
25516 var inner = el.getElementsByTagName("em")[0];
25517 return {"el": el, "inner": inner};
25521 * Ext JS Library 1.1.1
25522 * Copyright(c) 2006-2007, Ext JS, LLC.
25524 * Originally Released Under LGPL - original licence link has changed is not relivant.
25527 * <script type="text/javascript">
25531 * @class Roo.Button
25532 * @extends Roo.util.Observable
25533 * Simple Button class
25534 * @cfg {String} text The button text
25535 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25536 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25537 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25538 * @cfg {Object} scope The scope of the handler
25539 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25540 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25541 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25542 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25543 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25544 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25545 applies if enableToggle = true)
25546 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25547 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25548 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25550 * Create a new button
25551 * @param {Object} config The config object
25553 Roo.Button = function(renderTo, config)
25557 renderTo = config.renderTo || false;
25560 Roo.apply(this, config);
25564 * Fires when this button is clicked
25565 * @param {Button} this
25566 * @param {EventObject} e The click event
25571 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25572 * @param {Button} this
25573 * @param {Boolean} pressed
25578 * Fires when the mouse hovers over the button
25579 * @param {Button} this
25580 * @param {Event} e The event object
25582 'mouseover' : true,
25585 * Fires when the mouse exits the button
25586 * @param {Button} this
25587 * @param {Event} e The event object
25592 * Fires when the button is rendered
25593 * @param {Button} this
25598 this.menu = Roo.menu.MenuMgr.get(this.menu);
25601 this.render(renderTo);
25604 Roo.util.Observable.call(this);
25607 Roo.extend(Roo.Button, Roo.util.Observable, {
25613 * Read-only. True if this button is hidden
25618 * Read-only. True if this button is disabled
25623 * Read-only. True if this button is pressed (only if enableToggle = true)
25629 * @cfg {Number} tabIndex
25630 * The DOM tabIndex for this button (defaults to undefined)
25632 tabIndex : undefined,
25635 * @cfg {Boolean} enableToggle
25636 * True to enable pressed/not pressed toggling (defaults to false)
25638 enableToggle: false,
25640 * @cfg {Mixed} menu
25641 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25645 * @cfg {String} menuAlign
25646 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25648 menuAlign : "tl-bl?",
25651 * @cfg {String} iconCls
25652 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25654 iconCls : undefined,
25656 * @cfg {String} type
25657 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25662 menuClassTarget: 'tr',
25665 * @cfg {String} clickEvent
25666 * The type of event to map to the button's event handler (defaults to 'click')
25668 clickEvent : 'click',
25671 * @cfg {Boolean} handleMouseEvents
25672 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25674 handleMouseEvents : true,
25677 * @cfg {String} tooltipType
25678 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
25680 tooltipType : 'qtip',
25683 * @cfg {String} cls
25684 * A CSS class to apply to the button's main element.
25688 * @cfg {Roo.Template} template (Optional)
25689 * An {@link Roo.Template} with which to create the Button's main element. This Template must
25690 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
25691 * require code modifications if required elements (e.g. a button) aren't present.
25695 render : function(renderTo){
25697 if(this.hideParent){
25698 this.parentEl = Roo.get(renderTo);
25700 if(!this.dhconfig){
25701 if(!this.template){
25702 if(!Roo.Button.buttonTemplate){
25703 // hideous table template
25704 Roo.Button.buttonTemplate = new Roo.Template(
25705 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
25706 '<td class="x-btn-left"><i> </i></td><td class="x-btn-center"><em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td><td class="x-btn-right"><i> </i></td>',
25707 "</tr></tbody></table>");
25709 this.template = Roo.Button.buttonTemplate;
25711 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
25712 var btnEl = btn.child("button:first");
25713 btnEl.on('focus', this.onFocus, this);
25714 btnEl.on('blur', this.onBlur, this);
25716 btn.addClass(this.cls);
25719 btnEl.setStyle('background-image', 'url(' +this.icon +')');
25722 btnEl.addClass(this.iconCls);
25724 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
25727 if(this.tabIndex !== undefined){
25728 btnEl.dom.tabIndex = this.tabIndex;
25731 if(typeof this.tooltip == 'object'){
25732 Roo.QuickTips.tips(Roo.apply({
25736 btnEl.dom[this.tooltipType] = this.tooltip;
25740 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
25744 this.el.dom.id = this.el.id = this.id;
25747 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
25748 this.menu.on("show", this.onMenuShow, this);
25749 this.menu.on("hide", this.onMenuHide, this);
25751 btn.addClass("x-btn");
25752 if(Roo.isIE && !Roo.isIE7){
25753 this.autoWidth.defer(1, this);
25757 if(this.handleMouseEvents){
25758 btn.on("mouseover", this.onMouseOver, this);
25759 btn.on("mouseout", this.onMouseOut, this);
25760 btn.on("mousedown", this.onMouseDown, this);
25762 btn.on(this.clickEvent, this.onClick, this);
25763 //btn.on("mouseup", this.onMouseUp, this);
25770 Roo.ButtonToggleMgr.register(this);
25772 this.el.addClass("x-btn-pressed");
25775 var repeater = new Roo.util.ClickRepeater(btn,
25776 typeof this.repeat == "object" ? this.repeat : {}
25778 repeater.on("click", this.onClick, this);
25780 this.fireEvent('render', this);
25784 * Returns the button's underlying element
25785 * @return {Roo.Element} The element
25787 getEl : function(){
25792 * Destroys this Button and removes any listeners.
25794 destroy : function(){
25795 Roo.ButtonToggleMgr.unregister(this);
25796 this.el.removeAllListeners();
25797 this.purgeListeners();
25802 autoWidth : function(){
25804 this.el.setWidth("auto");
25805 if(Roo.isIE7 && Roo.isStrict){
25806 var ib = this.el.child('button');
25807 if(ib && ib.getWidth() > 20){
25809 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
25814 this.el.beginMeasure();
25816 if(this.el.getWidth() < this.minWidth){
25817 this.el.setWidth(this.minWidth);
25820 this.el.endMeasure();
25827 * Assigns this button's click handler
25828 * @param {Function} handler The function to call when the button is clicked
25829 * @param {Object} scope (optional) Scope for the function passed in
25831 setHandler : function(handler, scope){
25832 this.handler = handler;
25833 this.scope = scope;
25837 * Sets this button's text
25838 * @param {String} text The button text
25840 setText : function(text){
25843 this.el.child("td.x-btn-center button.x-btn-text").update(text);
25849 * Gets the text for this button
25850 * @return {String} The button text
25852 getText : function(){
25860 this.hidden = false;
25862 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
25870 this.hidden = true;
25872 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
25877 * Convenience function for boolean show/hide
25878 * @param {Boolean} visible True to show, false to hide
25880 setVisible: function(visible){
25889 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
25890 * @param {Boolean} state (optional) Force a particular state
25892 toggle : function(state){
25893 state = state === undefined ? !this.pressed : state;
25894 if(state != this.pressed){
25896 this.el.addClass("x-btn-pressed");
25897 this.pressed = true;
25898 this.fireEvent("toggle", this, true);
25900 this.el.removeClass("x-btn-pressed");
25901 this.pressed = false;
25902 this.fireEvent("toggle", this, false);
25904 if(this.toggleHandler){
25905 this.toggleHandler.call(this.scope || this, this, state);
25913 focus : function(){
25914 this.el.child('button:first').focus();
25918 * Disable this button
25920 disable : function(){
25922 this.el.addClass("x-btn-disabled");
25924 this.disabled = true;
25928 * Enable this button
25930 enable : function(){
25932 this.el.removeClass("x-btn-disabled");
25934 this.disabled = false;
25938 * Convenience function for boolean enable/disable
25939 * @param {Boolean} enabled True to enable, false to disable
25941 setDisabled : function(v){
25942 this[v !== true ? "enable" : "disable"]();
25946 onClick : function(e){
25948 e.preventDefault();
25953 if(!this.disabled){
25954 if(this.enableToggle){
25957 if(this.menu && !this.menu.isVisible()){
25958 this.menu.show(this.el, this.menuAlign);
25960 this.fireEvent("click", this, e);
25962 this.el.removeClass("x-btn-over");
25963 this.handler.call(this.scope || this, this, e);
25968 onMouseOver : function(e){
25969 if(!this.disabled){
25970 this.el.addClass("x-btn-over");
25971 this.fireEvent('mouseover', this, e);
25975 onMouseOut : function(e){
25976 if(!e.within(this.el, true)){
25977 this.el.removeClass("x-btn-over");
25978 this.fireEvent('mouseout', this, e);
25982 onFocus : function(e){
25983 if(!this.disabled){
25984 this.el.addClass("x-btn-focus");
25988 onBlur : function(e){
25989 this.el.removeClass("x-btn-focus");
25992 onMouseDown : function(e){
25993 if(!this.disabled && e.button == 0){
25994 this.el.addClass("x-btn-click");
25995 Roo.get(document).on('mouseup', this.onMouseUp, this);
25999 onMouseUp : function(e){
26001 this.el.removeClass("x-btn-click");
26002 Roo.get(document).un('mouseup', this.onMouseUp, this);
26006 onMenuShow : function(e){
26007 this.el.addClass("x-btn-menu-active");
26010 onMenuHide : function(e){
26011 this.el.removeClass("x-btn-menu-active");
26015 // Private utility class used by Button
26016 Roo.ButtonToggleMgr = function(){
26019 function toggleGroup(btn, state){
26021 var g = groups[btn.toggleGroup];
26022 for(var i = 0, l = g.length; i < l; i++){
26024 g[i].toggle(false);
26031 register : function(btn){
26032 if(!btn.toggleGroup){
26035 var g = groups[btn.toggleGroup];
26037 g = groups[btn.toggleGroup] = [];
26040 btn.on("toggle", toggleGroup);
26043 unregister : function(btn){
26044 if(!btn.toggleGroup){
26047 var g = groups[btn.toggleGroup];
26050 btn.un("toggle", toggleGroup);
26056 * Ext JS Library 1.1.1
26057 * Copyright(c) 2006-2007, Ext JS, LLC.
26059 * Originally Released Under LGPL - original licence link has changed is not relivant.
26062 * <script type="text/javascript">
26066 * @class Roo.SplitButton
26067 * @extends Roo.Button
26068 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26069 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26070 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26071 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26072 * @cfg {String} arrowTooltip The title attribute of the arrow
26074 * Create a new menu button
26075 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26076 * @param {Object} config The config object
26078 Roo.SplitButton = function(renderTo, config){
26079 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26081 * @event arrowclick
26082 * Fires when this button's arrow is clicked
26083 * @param {SplitButton} this
26084 * @param {EventObject} e The click event
26086 this.addEvents({"arrowclick":true});
26089 Roo.extend(Roo.SplitButton, Roo.Button, {
26090 render : function(renderTo){
26091 // this is one sweet looking template!
26092 var tpl = new Roo.Template(
26093 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26094 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26095 '<tr><td class="x-btn-left"><i> </i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',
26096 "</tbody></table></td><td>",
26097 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26098 '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button"> </button></td><td class="x-btn-right"><i> </i></td></tr>',
26099 "</tbody></table></td></tr></table>"
26101 var btn = tpl.append(renderTo, [this.text, this.type], true);
26102 var btnEl = btn.child("button");
26104 btn.addClass(this.cls);
26107 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26110 btnEl.addClass(this.iconCls);
26112 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26116 if(this.handleMouseEvents){
26117 btn.on("mouseover", this.onMouseOver, this);
26118 btn.on("mouseout", this.onMouseOut, this);
26119 btn.on("mousedown", this.onMouseDown, this);
26120 btn.on("mouseup", this.onMouseUp, this);
26122 btn.on(this.clickEvent, this.onClick, this);
26124 if(typeof this.tooltip == 'object'){
26125 Roo.QuickTips.tips(Roo.apply({
26129 btnEl.dom[this.tooltipType] = this.tooltip;
26132 if(this.arrowTooltip){
26133 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26142 this.el.addClass("x-btn-pressed");
26144 if(Roo.isIE && !Roo.isIE7){
26145 this.autoWidth.defer(1, this);
26150 this.menu.on("show", this.onMenuShow, this);
26151 this.menu.on("hide", this.onMenuHide, this);
26153 this.fireEvent('render', this);
26157 autoWidth : function(){
26159 var tbl = this.el.child("table:first");
26160 var tbl2 = this.el.child("table:last");
26161 this.el.setWidth("auto");
26162 tbl.setWidth("auto");
26163 if(Roo.isIE7 && Roo.isStrict){
26164 var ib = this.el.child('button:first');
26165 if(ib && ib.getWidth() > 20){
26167 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26172 this.el.beginMeasure();
26174 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26175 tbl.setWidth(this.minWidth-tbl2.getWidth());
26178 this.el.endMeasure();
26181 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26185 * Sets this button's click handler
26186 * @param {Function} handler The function to call when the button is clicked
26187 * @param {Object} scope (optional) Scope for the function passed above
26189 setHandler : function(handler, scope){
26190 this.handler = handler;
26191 this.scope = scope;
26195 * Sets this button's arrow click handler
26196 * @param {Function} handler The function to call when the arrow is clicked
26197 * @param {Object} scope (optional) Scope for the function passed above
26199 setArrowHandler : function(handler, scope){
26200 this.arrowHandler = handler;
26201 this.scope = scope;
26207 focus : function(){
26209 this.el.child("button:first").focus();
26214 onClick : function(e){
26215 e.preventDefault();
26216 if(!this.disabled){
26217 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26218 if(this.menu && !this.menu.isVisible()){
26219 this.menu.show(this.el, this.menuAlign);
26221 this.fireEvent("arrowclick", this, e);
26222 if(this.arrowHandler){
26223 this.arrowHandler.call(this.scope || this, this, e);
26226 this.fireEvent("click", this, e);
26228 this.handler.call(this.scope || this, this, e);
26234 onMouseDown : function(e){
26235 if(!this.disabled){
26236 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26240 onMouseUp : function(e){
26241 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26246 // backwards compat
26247 Roo.MenuButton = Roo.SplitButton;/*
26249 * Ext JS Library 1.1.1
26250 * Copyright(c) 2006-2007, Ext JS, LLC.
26252 * Originally Released Under LGPL - original licence link has changed is not relivant.
26255 * <script type="text/javascript">
26259 * @class Roo.Toolbar
26260 * Basic Toolbar class.
26262 * Creates a new Toolbar
26263 * @param {Object} config The config object
26265 Roo.Toolbar = function(container, buttons, config)
26267 /// old consturctor format still supported..
26268 if(container instanceof Array){ // omit the container for later rendering
26269 buttons = container;
26273 if (typeof(container) == 'object' && container.xtype) {
26274 config = container;
26275 container = config.container;
26276 buttons = config.buttons; // not really - use items!!
26279 if (config && config.items) {
26280 xitems = config.items;
26281 delete config.items;
26283 Roo.apply(this, config);
26284 this.buttons = buttons;
26287 this.render(container);
26289 Roo.each(xitems, function(b) {
26295 Roo.Toolbar.prototype = {
26297 * @cfg {Roo.data.Store} items
26298 * array of button configs or elements to add
26302 * @cfg {String/HTMLElement/Element} container
26303 * The id or element that will contain the toolbar
26306 render : function(ct){
26307 this.el = Roo.get(ct);
26309 this.el.addClass(this.cls);
26311 // using a table allows for vertical alignment
26312 // 100% width is needed by Safari...
26313 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26314 this.tr = this.el.child("tr", true);
26316 this.items = new Roo.util.MixedCollection(false, function(o){
26317 return o.id || ("item" + (++autoId));
26320 this.add.apply(this, this.buttons);
26321 delete this.buttons;
26326 * Adds element(s) to the toolbar -- this function takes a variable number of
26327 * arguments of mixed type and adds them to the toolbar.
26328 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26330 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26331 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26332 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26333 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26334 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26335 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26336 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26337 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26338 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26340 * @param {Mixed} arg2
26341 * @param {Mixed} etc.
26344 var a = arguments, l = a.length;
26345 for(var i = 0; i < l; i++){
26350 _add : function(el) {
26353 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26356 if (el.applyTo){ // some kind of form field
26357 return this.addField(el);
26359 if (el.render){ // some kind of Toolbar.Item
26360 return this.addItem(el);
26362 if (typeof el == "string"){ // string
26363 if(el == "separator" || el == "-"){
26364 return this.addSeparator();
26367 return this.addSpacer();
26370 return this.addFill();
26372 return this.addText(el);
26375 if(el.tagName){ // element
26376 return this.addElement(el);
26378 if(typeof el == "object"){ // must be button config?
26379 return this.addButton(el);
26381 // and now what?!?!
26387 * Add an Xtype element
26388 * @param {Object} xtype Xtype Object
26389 * @return {Object} created Object
26391 addxtype : function(e){
26392 return this.add(e);
26396 * Returns the Element for this toolbar.
26397 * @return {Roo.Element}
26399 getEl : function(){
26405 * @return {Roo.Toolbar.Item} The separator item
26407 addSeparator : function(){
26408 return this.addItem(new Roo.Toolbar.Separator());
26412 * Adds a spacer element
26413 * @return {Roo.Toolbar.Spacer} The spacer item
26415 addSpacer : function(){
26416 return this.addItem(new Roo.Toolbar.Spacer());
26420 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26421 * @return {Roo.Toolbar.Fill} The fill item
26423 addFill : function(){
26424 return this.addItem(new Roo.Toolbar.Fill());
26428 * Adds any standard HTML element to the toolbar
26429 * @param {String/HTMLElement/Element} el The element or id of the element to add
26430 * @return {Roo.Toolbar.Item} The element's item
26432 addElement : function(el){
26433 return this.addItem(new Roo.Toolbar.Item(el));
26436 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26437 * @type Roo.util.MixedCollection
26442 * Adds any Toolbar.Item or subclass
26443 * @param {Roo.Toolbar.Item} item
26444 * @return {Roo.Toolbar.Item} The item
26446 addItem : function(item){
26447 var td = this.nextBlock();
26449 this.items.add(item);
26454 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26455 * @param {Object/Array} config A button config or array of configs
26456 * @return {Roo.Toolbar.Button/Array}
26458 addButton : function(config){
26459 if(config instanceof Array){
26461 for(var i = 0, len = config.length; i < len; i++) {
26462 buttons.push(this.addButton(config[i]));
26467 if(!(config instanceof Roo.Toolbar.Button)){
26469 new Roo.Toolbar.SplitButton(config) :
26470 new Roo.Toolbar.Button(config);
26472 var td = this.nextBlock();
26479 * Adds text to the toolbar
26480 * @param {String} text The text to add
26481 * @return {Roo.Toolbar.Item} The element's item
26483 addText : function(text){
26484 return this.addItem(new Roo.Toolbar.TextItem(text));
26488 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26489 * @param {Number} index The index where the item is to be inserted
26490 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26491 * @return {Roo.Toolbar.Button/Item}
26493 insertButton : function(index, item){
26494 if(item instanceof Array){
26496 for(var i = 0, len = item.length; i < len; i++) {
26497 buttons.push(this.insertButton(index + i, item[i]));
26501 if (!(item instanceof Roo.Toolbar.Button)){
26502 item = new Roo.Toolbar.Button(item);
26504 var td = document.createElement("td");
26505 this.tr.insertBefore(td, this.tr.childNodes[index]);
26507 this.items.insert(index, item);
26512 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26513 * @param {Object} config
26514 * @return {Roo.Toolbar.Item} The element's item
26516 addDom : function(config, returnEl){
26517 var td = this.nextBlock();
26518 Roo.DomHelper.overwrite(td, config);
26519 var ti = new Roo.Toolbar.Item(td.firstChild);
26521 this.items.add(ti);
26526 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26527 * @type Roo.util.MixedCollection
26532 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26533 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26534 * @param {Roo.form.Field} field
26535 * @return {Roo.ToolbarItem}
26539 addField : function(field) {
26540 if (!this.fields) {
26542 this.fields = new Roo.util.MixedCollection(false, function(o){
26543 return o.id || ("item" + (++autoId));
26548 var td = this.nextBlock();
26550 var ti = new Roo.Toolbar.Item(td.firstChild);
26552 this.items.add(ti);
26553 this.fields.add(field);
26564 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26565 this.el.child('div').hide();
26573 this.el.child('div').show();
26577 nextBlock : function(){
26578 var td = document.createElement("td");
26579 this.tr.appendChild(td);
26584 destroy : function(){
26585 if(this.items){ // rendered?
26586 Roo.destroy.apply(Roo, this.items.items);
26588 if(this.fields){ // rendered?
26589 Roo.destroy.apply(Roo, this.fields.items);
26591 Roo.Element.uncache(this.el, this.tr);
26596 * @class Roo.Toolbar.Item
26597 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26599 * Creates a new Item
26600 * @param {HTMLElement} el
26602 Roo.Toolbar.Item = function(el){
26603 this.el = Roo.getDom(el);
26604 this.id = Roo.id(this.el);
26605 this.hidden = false;
26608 Roo.Toolbar.Item.prototype = {
26611 * Get this item's HTML Element
26612 * @return {HTMLElement}
26614 getEl : function(){
26619 render : function(td){
26621 td.appendChild(this.el);
26625 * Removes and destroys this item.
26627 destroy : function(){
26628 this.td.parentNode.removeChild(this.td);
26635 this.hidden = false;
26636 this.td.style.display = "";
26643 this.hidden = true;
26644 this.td.style.display = "none";
26648 * Convenience function for boolean show/hide.
26649 * @param {Boolean} visible true to show/false to hide
26651 setVisible: function(visible){
26660 * Try to focus this item.
26662 focus : function(){
26663 Roo.fly(this.el).focus();
26667 * Disables this item.
26669 disable : function(){
26670 Roo.fly(this.td).addClass("x-item-disabled");
26671 this.disabled = true;
26672 this.el.disabled = true;
26676 * Enables this item.
26678 enable : function(){
26679 Roo.fly(this.td).removeClass("x-item-disabled");
26680 this.disabled = false;
26681 this.el.disabled = false;
26687 * @class Roo.Toolbar.Separator
26688 * @extends Roo.Toolbar.Item
26689 * A simple toolbar separator class
26691 * Creates a new Separator
26693 Roo.Toolbar.Separator = function(){
26694 var s = document.createElement("span");
26695 s.className = "ytb-sep";
26696 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
26698 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
26699 enable:Roo.emptyFn,
26700 disable:Roo.emptyFn,
26705 * @class Roo.Toolbar.Spacer
26706 * @extends Roo.Toolbar.Item
26707 * A simple element that adds extra horizontal space to a toolbar.
26709 * Creates a new Spacer
26711 Roo.Toolbar.Spacer = function(){
26712 var s = document.createElement("div");
26713 s.className = "ytb-spacer";
26714 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
26716 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
26717 enable:Roo.emptyFn,
26718 disable:Roo.emptyFn,
26723 * @class Roo.Toolbar.Fill
26724 * @extends Roo.Toolbar.Spacer
26725 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
26727 * Creates a new Spacer
26729 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
26731 render : function(td){
26732 td.style.width = '100%';
26733 Roo.Toolbar.Fill.superclass.render.call(this, td);
26738 * @class Roo.Toolbar.TextItem
26739 * @extends Roo.Toolbar.Item
26740 * A simple class that renders text directly into a toolbar.
26742 * Creates a new TextItem
26743 * @param {String} text
26745 Roo.Toolbar.TextItem = function(text){
26746 if (typeof(text) == 'object') {
26749 var s = document.createElement("span");
26750 s.className = "ytb-text";
26751 s.innerHTML = text;
26752 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
26754 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
26755 enable:Roo.emptyFn,
26756 disable:Roo.emptyFn,
26761 * @class Roo.Toolbar.Button
26762 * @extends Roo.Button
26763 * A button that renders into a toolbar.
26765 * Creates a new Button
26766 * @param {Object} config A standard {@link Roo.Button} config object
26768 Roo.Toolbar.Button = function(config){
26769 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
26771 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
26772 render : function(td){
26774 Roo.Toolbar.Button.superclass.render.call(this, td);
26778 * Removes and destroys this button
26780 destroy : function(){
26781 Roo.Toolbar.Button.superclass.destroy.call(this);
26782 this.td.parentNode.removeChild(this.td);
26786 * Shows this button
26789 this.hidden = false;
26790 this.td.style.display = "";
26794 * Hides this button
26797 this.hidden = true;
26798 this.td.style.display = "none";
26802 * Disables this item
26804 disable : function(){
26805 Roo.fly(this.td).addClass("x-item-disabled");
26806 this.disabled = true;
26810 * Enables this item
26812 enable : function(){
26813 Roo.fly(this.td).removeClass("x-item-disabled");
26814 this.disabled = false;
26817 // backwards compat
26818 Roo.ToolbarButton = Roo.Toolbar.Button;
26821 * @class Roo.Toolbar.SplitButton
26822 * @extends Roo.SplitButton
26823 * A menu button that renders into a toolbar.
26825 * Creates a new SplitButton
26826 * @param {Object} config A standard {@link Roo.SplitButton} config object
26828 Roo.Toolbar.SplitButton = function(config){
26829 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
26831 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
26832 render : function(td){
26834 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
26838 * Removes and destroys this button
26840 destroy : function(){
26841 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
26842 this.td.parentNode.removeChild(this.td);
26846 * Shows this button
26849 this.hidden = false;
26850 this.td.style.display = "";
26854 * Hides this button
26857 this.hidden = true;
26858 this.td.style.display = "none";
26862 // backwards compat
26863 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
26865 * Ext JS Library 1.1.1
26866 * Copyright(c) 2006-2007, Ext JS, LLC.
26868 * Originally Released Under LGPL - original licence link has changed is not relivant.
26871 * <script type="text/javascript">
26875 * @class Roo.PagingToolbar
26876 * @extends Roo.Toolbar
26877 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26879 * Create a new PagingToolbar
26880 * @param {Object} config The config object
26882 Roo.PagingToolbar = function(el, ds, config)
26884 // old args format still supported... - xtype is prefered..
26885 if (typeof(el) == 'object' && el.xtype) {
26886 // created from xtype...
26888 ds = el.dataSource;
26889 el = config.container;
26893 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
26896 this.renderButtons(this.el);
26900 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
26902 * @cfg {Roo.data.Store} dataSource
26903 * The underlying data store providing the paged data
26906 * @cfg {String/HTMLElement/Element} container
26907 * container The id or element that will contain the toolbar
26910 * @cfg {Boolean} displayInfo
26911 * True to display the displayMsg (defaults to false)
26914 * @cfg {Number} pageSize
26915 * The number of records to display per page (defaults to 20)
26919 * @cfg {String} displayMsg
26920 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26922 displayMsg : 'Displaying {0} - {1} of {2}',
26924 * @cfg {String} emptyMsg
26925 * The message to display when no records are found (defaults to "No data to display")
26927 emptyMsg : 'No data to display',
26929 * Customizable piece of the default paging text (defaults to "Page")
26932 beforePageText : "Page",
26934 * Customizable piece of the default paging text (defaults to "of %0")
26937 afterPageText : "of {0}",
26939 * Customizable piece of the default paging text (defaults to "First Page")
26942 firstText : "First Page",
26944 * Customizable piece of the default paging text (defaults to "Previous Page")
26947 prevText : "Previous Page",
26949 * Customizable piece of the default paging text (defaults to "Next Page")
26952 nextText : "Next Page",
26954 * Customizable piece of the default paging text (defaults to "Last Page")
26957 lastText : "Last Page",
26959 * Customizable piece of the default paging text (defaults to "Refresh")
26962 refreshText : "Refresh",
26965 renderButtons : function(el){
26966 Roo.PagingToolbar.superclass.render.call(this, el);
26967 this.first = this.addButton({
26968 tooltip: this.firstText,
26969 cls: "x-btn-icon x-grid-page-first",
26971 handler: this.onClick.createDelegate(this, ["first"])
26973 this.prev = this.addButton({
26974 tooltip: this.prevText,
26975 cls: "x-btn-icon x-grid-page-prev",
26977 handler: this.onClick.createDelegate(this, ["prev"])
26979 this.addSeparator();
26980 this.add(this.beforePageText);
26981 this.field = Roo.get(this.addDom({
26986 cls: "x-grid-page-number"
26988 this.field.on("keydown", this.onPagingKeydown, this);
26989 this.field.on("focus", function(){this.dom.select();});
26990 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
26991 this.field.setHeight(18);
26992 this.addSeparator();
26993 this.next = this.addButton({
26994 tooltip: this.nextText,
26995 cls: "x-btn-icon x-grid-page-next",
26997 handler: this.onClick.createDelegate(this, ["next"])
26999 this.last = this.addButton({
27000 tooltip: this.lastText,
27001 cls: "x-btn-icon x-grid-page-last",
27003 handler: this.onClick.createDelegate(this, ["last"])
27005 this.addSeparator();
27006 this.loading = this.addButton({
27007 tooltip: this.refreshText,
27008 cls: "x-btn-icon x-grid-loading",
27009 handler: this.onClick.createDelegate(this, ["refresh"])
27012 if(this.displayInfo){
27013 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27018 updateInfo : function(){
27019 if(this.displayEl){
27020 var count = this.ds.getCount();
27021 var msg = count == 0 ?
27025 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27027 this.displayEl.update(msg);
27032 onLoad : function(ds, r, o){
27033 this.cursor = o.params ? o.params.start : 0;
27034 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27036 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27037 this.field.dom.value = ap;
27038 this.first.setDisabled(ap == 1);
27039 this.prev.setDisabled(ap == 1);
27040 this.next.setDisabled(ap == ps);
27041 this.last.setDisabled(ap == ps);
27042 this.loading.enable();
27047 getPageData : function(){
27048 var total = this.ds.getTotalCount();
27051 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27052 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27057 onLoadError : function(){
27058 this.loading.enable();
27062 onPagingKeydown : function(e){
27063 var k = e.getKey();
27064 var d = this.getPageData();
27066 var v = this.field.dom.value, pageNum;
27067 if(!v || isNaN(pageNum = parseInt(v, 10))){
27068 this.field.dom.value = d.activePage;
27071 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27072 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27075 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
27077 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27078 this.field.dom.value = pageNum;
27079 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27082 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27084 var v = this.field.dom.value, pageNum;
27085 var increment = (e.shiftKey) ? 10 : 1;
27086 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27088 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27089 this.field.dom.value = d.activePage;
27092 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27094 this.field.dom.value = parseInt(v, 10) + increment;
27095 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27096 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27103 beforeLoad : function(){
27105 this.loading.disable();
27110 onClick : function(which){
27114 ds.load({params:{start: 0, limit: this.pageSize}});
27117 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27120 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27123 var total = ds.getTotalCount();
27124 var extra = total % this.pageSize;
27125 var lastStart = extra ? (total - extra) : total-this.pageSize;
27126 ds.load({params:{start: lastStart, limit: this.pageSize}});
27129 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27135 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27136 * @param {Roo.data.Store} store The data store to unbind
27138 unbind : function(ds){
27139 ds.un("beforeload", this.beforeLoad, this);
27140 ds.un("load", this.onLoad, this);
27141 ds.un("loadexception", this.onLoadError, this);
27142 ds.un("remove", this.updateInfo, this);
27143 ds.un("add", this.updateInfo, this);
27144 this.ds = undefined;
27148 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27149 * @param {Roo.data.Store} store The data store to bind
27151 bind : function(ds){
27152 ds.on("beforeload", this.beforeLoad, this);
27153 ds.on("load", this.onLoad, this);
27154 ds.on("loadexception", this.onLoadError, this);
27155 ds.on("remove", this.updateInfo, this);
27156 ds.on("add", this.updateInfo, this);
27161 * Ext JS Library 1.1.1
27162 * Copyright(c) 2006-2007, Ext JS, LLC.
27164 * Originally Released Under LGPL - original licence link has changed is not relivant.
27167 * <script type="text/javascript">
27171 * @class Roo.Resizable
27172 * @extends Roo.util.Observable
27173 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27174 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27175 * 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
27176 * the element will be wrapped for you automatically.</p>
27177 * <p>Here is the list of valid resize handles:</p>
27180 ------ -------------------
27191 * <p>Here's an example showing the creation of a typical Resizable:</p>
27193 var resizer = new Roo.Resizable("element-id", {
27201 resizer.on("resize", myHandler);
27203 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27204 * resizer.east.setDisplayed(false);</p>
27205 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27206 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27207 * resize operation's new size (defaults to [0, 0])
27208 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27209 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27210 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27211 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27212 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27213 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27214 * @cfg {Number} width The width of the element in pixels (defaults to null)
27215 * @cfg {Number} height The height of the element in pixels (defaults to null)
27216 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27217 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27218 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27219 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27220 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27221 * in favor of the handles config option (defaults to false)
27222 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27223 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27224 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27225 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27226 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27227 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27228 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27229 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27230 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27231 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27232 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27234 * Create a new resizable component
27235 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27236 * @param {Object} config configuration options
27238 Roo.Resizable = function(el, config){
27239 this.el = Roo.get(el);
27241 if(config && config.wrap){
27242 config.resizeChild = this.el;
27243 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27244 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27245 this.el.setStyle("overflow", "hidden");
27246 this.el.setPositioning(config.resizeChild.getPositioning());
27247 config.resizeChild.clearPositioning();
27248 if(!config.width || !config.height){
27249 var csize = config.resizeChild.getSize();
27250 this.el.setSize(csize.width, csize.height);
27252 if(config.pinned && !config.adjustments){
27253 config.adjustments = "auto";
27257 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27258 this.proxy.unselectable();
27259 this.proxy.enableDisplayMode('block');
27261 Roo.apply(this, config);
27264 this.disableTrackOver = true;
27265 this.el.addClass("x-resizable-pinned");
27267 // if the element isn't positioned, make it relative
27268 var position = this.el.getStyle("position");
27269 if(position != "absolute" && position != "fixed"){
27270 this.el.setStyle("position", "relative");
27272 if(!this.handles){ // no handles passed, must be legacy style
27273 this.handles = 's,e,se';
27274 if(this.multiDirectional){
27275 this.handles += ',n,w';
27278 if(this.handles == "all"){
27279 this.handles = "n s e w ne nw se sw";
27281 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27282 var ps = Roo.Resizable.positions;
27283 for(var i = 0, len = hs.length; i < len; i++){
27284 if(hs[i] && ps[hs[i]]){
27285 var pos = ps[hs[i]];
27286 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27290 this.corner = this.southeast;
27292 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1){
27293 this.updateBox = true;
27296 this.activeHandle = null;
27298 if(this.resizeChild){
27299 if(typeof this.resizeChild == "boolean"){
27300 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27302 this.resizeChild = Roo.get(this.resizeChild, true);
27306 if(this.adjustments == "auto"){
27307 var rc = this.resizeChild;
27308 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27309 if(rc && (hw || hn)){
27310 rc.position("relative");
27311 rc.setLeft(hw ? hw.el.getWidth() : 0);
27312 rc.setTop(hn ? hn.el.getHeight() : 0);
27314 this.adjustments = [
27315 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27316 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27320 if(this.draggable){
27321 this.dd = this.dynamic ?
27322 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27323 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27329 * @event beforeresize
27330 * Fired before resize is allowed. Set enabled to false to cancel resize.
27331 * @param {Roo.Resizable} this
27332 * @param {Roo.EventObject} e The mousedown event
27334 "beforeresize" : true,
27337 * Fired after a resize.
27338 * @param {Roo.Resizable} this
27339 * @param {Number} width The new width
27340 * @param {Number} height The new height
27341 * @param {Roo.EventObject} e The mouseup event
27346 if(this.width !== null && this.height !== null){
27347 this.resizeTo(this.width, this.height);
27349 this.updateChildSize();
27352 this.el.dom.style.zoom = 1;
27354 Roo.Resizable.superclass.constructor.call(this);
27357 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27358 resizeChild : false,
27359 adjustments : [0, 0],
27369 multiDirectional : false,
27370 disableTrackOver : false,
27371 easing : 'easeOutStrong',
27372 widthIncrement : 0,
27373 heightIncrement : 0,
27377 preserveRatio : false,
27378 transparent: false,
27384 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27386 constrainTo: undefined,
27388 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27390 resizeRegion: undefined,
27394 * Perform a manual resize
27395 * @param {Number} width
27396 * @param {Number} height
27398 resizeTo : function(width, height){
27399 this.el.setSize(width, height);
27400 this.updateChildSize();
27401 this.fireEvent("resize", this, width, height, null);
27405 startSizing : function(e, handle){
27406 this.fireEvent("beforeresize", this, e);
27407 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27410 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27411 this.overlay.unselectable();
27412 this.overlay.enableDisplayMode("block");
27413 this.overlay.on("mousemove", this.onMouseMove, this);
27414 this.overlay.on("mouseup", this.onMouseUp, this);
27416 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27418 this.resizing = true;
27419 this.startBox = this.el.getBox();
27420 this.startPoint = e.getXY();
27421 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27422 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27424 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27425 this.overlay.show();
27427 if(this.constrainTo) {
27428 var ct = Roo.get(this.constrainTo);
27429 this.resizeRegion = ct.getRegion().adjust(
27430 ct.getFrameWidth('t'),
27431 ct.getFrameWidth('l'),
27432 -ct.getFrameWidth('b'),
27433 -ct.getFrameWidth('r')
27437 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27439 this.proxy.setBox(this.startBox);
27441 this.proxy.setStyle('visibility', 'visible');
27447 onMouseDown : function(handle, e){
27450 this.activeHandle = handle;
27451 this.startSizing(e, handle);
27456 onMouseUp : function(e){
27457 var size = this.resizeElement();
27458 this.resizing = false;
27460 this.overlay.hide();
27462 this.fireEvent("resize", this, size.width, size.height, e);
27466 updateChildSize : function(){
27467 if(this.resizeChild){
27469 var child = this.resizeChild;
27470 var adj = this.adjustments;
27471 if(el.dom.offsetWidth){
27472 var b = el.getSize(true);
27473 child.setSize(b.width+adj[0], b.height+adj[1]);
27475 // Second call here for IE
27476 // The first call enables instant resizing and
27477 // the second call corrects scroll bars if they
27480 setTimeout(function(){
27481 if(el.dom.offsetWidth){
27482 var b = el.getSize(true);
27483 child.setSize(b.width+adj[0], b.height+adj[1]);
27491 snap : function(value, inc, min){
27492 if(!inc || !value) return value;
27493 var newValue = value;
27494 var m = value % inc;
27497 newValue = value + (inc-m);
27499 newValue = value - m;
27502 return Math.max(min, newValue);
27506 resizeElement : function(){
27507 var box = this.proxy.getBox();
27508 if(this.updateBox){
27509 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27511 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27513 this.updateChildSize();
27521 constrain : function(v, diff, m, mx){
27524 }else if(v - diff > mx){
27531 onMouseMove : function(e){
27533 try{// try catch so if something goes wrong the user doesn't get hung
27535 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27539 //var curXY = this.startPoint;
27540 var curSize = this.curSize || this.startBox;
27541 var x = this.startBox.x, y = this.startBox.y;
27542 var ox = x, oy = y;
27543 var w = curSize.width, h = curSize.height;
27544 var ow = w, oh = h;
27545 var mw = this.minWidth, mh = this.minHeight;
27546 var mxw = this.maxWidth, mxh = this.maxHeight;
27547 var wi = this.widthIncrement;
27548 var hi = this.heightIncrement;
27550 var eventXY = e.getXY();
27551 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27552 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27554 var pos = this.activeHandle.position;
27559 w = Math.min(Math.max(mw, w), mxw);
27563 h = Math.min(Math.max(mh, h), mxh);
27568 w = Math.min(Math.max(mw, w), mxw);
27569 h = Math.min(Math.max(mh, h), mxh);
27572 diffY = this.constrain(h, diffY, mh, mxh);
27577 diffX = this.constrain(w, diffX, mw, mxw);
27583 w = Math.min(Math.max(mw, w), mxw);
27584 diffY = this.constrain(h, diffY, mh, mxh);
27589 diffX = this.constrain(w, diffX, mw, mxw);
27590 diffY = this.constrain(h, diffY, mh, mxh);
27597 diffX = this.constrain(w, diffX, mw, mxw);
27599 h = Math.min(Math.max(mh, h), mxh);
27605 var sw = this.snap(w, wi, mw);
27606 var sh = this.snap(h, hi, mh);
27607 if(sw != w || sh != h){
27630 if(this.preserveRatio){
27635 h = Math.min(Math.max(mh, h), mxh);
27640 w = Math.min(Math.max(mw, w), mxw);
27645 w = Math.min(Math.max(mw, w), mxw);
27651 w = Math.min(Math.max(mw, w), mxw);
27657 h = Math.min(Math.max(mh, h), mxh);
27665 h = Math.min(Math.max(mh, h), mxh);
27675 h = Math.min(Math.max(mh, h), mxh);
27683 this.proxy.setBounds(x, y, w, h);
27685 this.resizeElement();
27692 handleOver : function(){
27694 this.el.addClass("x-resizable-over");
27699 handleOut : function(){
27700 if(!this.resizing){
27701 this.el.removeClass("x-resizable-over");
27706 * Returns the element this component is bound to.
27707 * @return {Roo.Element}
27709 getEl : function(){
27714 * Returns the resizeChild element (or null).
27715 * @return {Roo.Element}
27717 getResizeChild : function(){
27718 return this.resizeChild;
27722 * Destroys this resizable. If the element was wrapped and
27723 * removeEl is not true then the element remains.
27724 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
27726 destroy : function(removeEl){
27727 this.proxy.remove();
27729 this.overlay.removeAllListeners();
27730 this.overlay.remove();
27732 var ps = Roo.Resizable.positions;
27734 if(typeof ps[k] != "function" && this[ps[k]]){
27735 var h = this[ps[k]];
27736 h.el.removeAllListeners();
27741 this.el.update("");
27748 // hash to map config positions to true positions
27749 Roo.Resizable.positions = {
27750 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast"
27754 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
27756 // only initialize the template if resizable is used
27757 var tpl = Roo.DomHelper.createTemplate(
27758 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
27761 Roo.Resizable.Handle.prototype.tpl = tpl;
27763 this.position = pos;
27765 this.el = this.tpl.append(rz.el.dom, [this.position], true);
27766 this.el.unselectable();
27768 this.el.setOpacity(0);
27770 this.el.on("mousedown", this.onMouseDown, this);
27771 if(!disableTrackOver){
27772 this.el.on("mouseover", this.onMouseOver, this);
27773 this.el.on("mouseout", this.onMouseOut, this);
27778 Roo.Resizable.Handle.prototype = {
27779 afterResize : function(rz){
27783 onMouseDown : function(e){
27784 this.rz.onMouseDown(this, e);
27787 onMouseOver : function(e){
27788 this.rz.handleOver(this, e);
27791 onMouseOut : function(e){
27792 this.rz.handleOut(this, e);
27796 * Ext JS Library 1.1.1
27797 * Copyright(c) 2006-2007, Ext JS, LLC.
27799 * Originally Released Under LGPL - original licence link has changed is not relivant.
27802 * <script type="text/javascript">
27806 * @class Roo.Editor
27807 * @extends Roo.Component
27808 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
27810 * Create a new Editor
27811 * @param {Roo.form.Field} field The Field object (or descendant)
27812 * @param {Object} config The config object
27814 Roo.Editor = function(field, config){
27815 Roo.Editor.superclass.constructor.call(this, config);
27816 this.field = field;
27819 * @event beforestartedit
27820 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
27821 * false from the handler of this event.
27822 * @param {Editor} this
27823 * @param {Roo.Element} boundEl The underlying element bound to this editor
27824 * @param {Mixed} value The field value being set
27826 "beforestartedit" : true,
27829 * Fires when this editor is displayed
27830 * @param {Roo.Element} boundEl The underlying element bound to this editor
27831 * @param {Mixed} value The starting field value
27833 "startedit" : true,
27835 * @event beforecomplete
27836 * Fires after a change has been made to the field, but before the change is reflected in the underlying
27837 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
27838 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
27839 * event will not fire since no edit actually occurred.
27840 * @param {Editor} this
27841 * @param {Mixed} value The current field value
27842 * @param {Mixed} startValue The original field value
27844 "beforecomplete" : true,
27847 * Fires after editing is complete and any changed value has been written to the underlying field.
27848 * @param {Editor} this
27849 * @param {Mixed} value The current field value
27850 * @param {Mixed} startValue The original field value
27854 * @event specialkey
27855 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
27856 * {@link Roo.EventObject#getKey} to determine which key was pressed.
27857 * @param {Roo.form.Field} this
27858 * @param {Roo.EventObject} e The event object
27860 "specialkey" : true
27864 Roo.extend(Roo.Editor, Roo.Component, {
27866 * @cfg {Boolean/String} autosize
27867 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
27868 * or "height" to adopt the height only (defaults to false)
27871 * @cfg {Boolean} revertInvalid
27872 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
27873 * validation fails (defaults to true)
27876 * @cfg {Boolean} ignoreNoChange
27877 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
27878 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
27879 * will never be ignored.
27882 * @cfg {Boolean} hideEl
27883 * False to keep the bound element visible while the editor is displayed (defaults to true)
27886 * @cfg {Mixed} value
27887 * The data value of the underlying field (defaults to "")
27891 * @cfg {String} alignment
27892 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
27896 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
27897 * for bottom-right shadow (defaults to "frame")
27901 * @cfg {Boolean} constrain True to constrain the editor to the viewport
27905 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
27907 completeOnEnter : false,
27909 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
27911 cancelOnEsc : false,
27913 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
27918 onRender : function(ct, position){
27919 this.el = new Roo.Layer({
27920 shadow: this.shadow,
27926 constrain: this.constrain
27928 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
27929 if(this.field.msgTarget != 'title'){
27930 this.field.msgTarget = 'qtip';
27932 this.field.render(this.el);
27934 this.field.el.dom.setAttribute('autocomplete', 'off');
27936 this.field.on("specialkey", this.onSpecialKey, this);
27937 if(this.swallowKeys){
27938 this.field.el.swallowEvent(['keydown','keypress']);
27941 this.field.on("blur", this.onBlur, this);
27942 if(this.field.grow){
27943 this.field.on("autosize", this.el.sync, this.el, {delay:1});
27947 onSpecialKey : function(field, e){
27948 if(this.completeOnEnter && e.getKey() == e.ENTER){
27950 this.completeEdit();
27951 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
27954 this.fireEvent('specialkey', field, e);
27959 * Starts the editing process and shows the editor.
27960 * @param {String/HTMLElement/Element} el The element to edit
27961 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
27962 * to the innerHTML of el.
27964 startEdit : function(el, value){
27966 this.completeEdit();
27968 this.boundEl = Roo.get(el);
27969 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
27970 if(!this.rendered){
27971 this.render(this.parentEl || document.body);
27973 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
27976 this.startValue = v;
27977 this.field.setValue(v);
27979 var sz = this.boundEl.getSize();
27980 switch(this.autoSize){
27982 this.setSize(sz.width, "");
27985 this.setSize("", sz.height);
27988 this.setSize(sz.width, sz.height);
27991 this.el.alignTo(this.boundEl, this.alignment);
27992 this.editing = true;
27994 Roo.QuickTips.disable();
28000 * Sets the height and width of this editor.
28001 * @param {Number} width The new width
28002 * @param {Number} height The new height
28004 setSize : function(w, h){
28005 this.field.setSize(w, h);
28012 * Realigns the editor to the bound field based on the current alignment config value.
28014 realign : function(){
28015 this.el.alignTo(this.boundEl, this.alignment);
28019 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28020 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28022 completeEdit : function(remainVisible){
28026 var v = this.getValue();
28027 if(this.revertInvalid !== false && !this.field.isValid()){
28028 v = this.startValue;
28029 this.cancelEdit(true);
28031 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28032 this.editing = false;
28036 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28037 this.editing = false;
28038 if(this.updateEl && this.boundEl){
28039 this.boundEl.update(v);
28041 if(remainVisible !== true){
28044 this.fireEvent("complete", this, v, this.startValue);
28049 onShow : function(){
28051 if(this.hideEl !== false){
28052 this.boundEl.hide();
28055 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28056 this.fixIEFocus = true;
28057 this.deferredFocus.defer(50, this);
28059 this.field.focus();
28061 this.fireEvent("startedit", this.boundEl, this.startValue);
28064 deferredFocus : function(){
28066 this.field.focus();
28071 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28072 * reverted to the original starting value.
28073 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28074 * cancel (defaults to false)
28076 cancelEdit : function(remainVisible){
28078 this.setValue(this.startValue);
28079 if(remainVisible !== true){
28086 onBlur : function(){
28087 if(this.allowBlur !== true && this.editing){
28088 this.completeEdit();
28093 onHide : function(){
28095 this.completeEdit();
28099 if(this.field.collapse){
28100 this.field.collapse();
28103 if(this.hideEl !== false){
28104 this.boundEl.show();
28107 Roo.QuickTips.enable();
28112 * Sets the data value of the editor
28113 * @param {Mixed} value Any valid value supported by the underlying field
28115 setValue : function(v){
28116 this.field.setValue(v);
28120 * Gets the data value of the editor
28121 * @return {Mixed} The data value
28123 getValue : function(){
28124 return this.field.getValue();
28128 * Ext JS Library 1.1.1
28129 * Copyright(c) 2006-2007, Ext JS, LLC.
28131 * Originally Released Under LGPL - original licence link has changed is not relivant.
28134 * <script type="text/javascript">
28138 * @class Roo.BasicDialog
28139 * @extends Roo.util.Observable
28140 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28142 var dlg = new Roo.BasicDialog("my-dlg", {
28151 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28152 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28153 dlg.addButton('Cancel', dlg.hide, dlg);
28156 <b>A Dialog should always be a direct child of the body element.</b>
28157 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28158 * @cfg {String} title Default text to display in the title bar (defaults to null)
28159 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28160 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28161 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28162 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28163 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28164 * (defaults to null with no animation)
28165 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28166 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28167 * property for valid values (defaults to 'all')
28168 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28169 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28170 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28171 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28172 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28173 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28174 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28175 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28176 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28177 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28178 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28179 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28180 * draggable = true (defaults to false)
28181 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28182 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28183 * shadow (defaults to false)
28184 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28185 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28186 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28187 * @cfg {Array} buttons Array of buttons
28188 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28190 * Create a new BasicDialog.
28191 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28192 * @param {Object} config Configuration options
28194 Roo.BasicDialog = function(el, config){
28195 this.el = Roo.get(el);
28196 var dh = Roo.DomHelper;
28197 if(!this.el && config && config.autoCreate){
28198 if(typeof config.autoCreate == "object"){
28199 if(!config.autoCreate.id){
28200 config.autoCreate.id = el;
28202 this.el = dh.append(document.body,
28203 config.autoCreate, true);
28205 this.el = dh.append(document.body,
28206 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28210 el.setDisplayed(true);
28211 el.hide = this.hideAction;
28213 el.addClass("x-dlg");
28215 Roo.apply(this, config);
28217 this.proxy = el.createProxy("x-dlg-proxy");
28218 this.proxy.hide = this.hideAction;
28219 this.proxy.setOpacity(.5);
28223 el.setWidth(config.width);
28226 el.setHeight(config.height);
28228 this.size = el.getSize();
28229 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28230 this.xy = [config.x,config.y];
28232 this.xy = el.getCenterXY(true);
28234 /** The header element @type Roo.Element */
28235 this.header = el.child("> .x-dlg-hd");
28236 /** The body element @type Roo.Element */
28237 this.body = el.child("> .x-dlg-bd");
28238 /** The footer element @type Roo.Element */
28239 this.footer = el.child("> .x-dlg-ft");
28242 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28245 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28248 this.header.unselectable();
28250 this.header.update(this.title);
28252 // this element allows the dialog to be focused for keyboard event
28253 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28254 this.focusEl.swallowEvent("click", true);
28256 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28258 // wrap the body and footer for special rendering
28259 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28261 this.bwrap.dom.appendChild(this.footer.dom);
28264 this.bg = this.el.createChild({
28265 tag: "div", cls:"x-dlg-bg",
28266 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28268 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28271 if(this.autoScroll !== false && !this.autoTabs){
28272 this.body.setStyle("overflow", "auto");
28275 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28277 if(this.closable !== false){
28278 this.el.addClass("x-dlg-closable");
28279 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28280 this.close.on("click", this.closeClick, this);
28281 this.close.addClassOnOver("x-dlg-close-over");
28283 if(this.collapsible !== false){
28284 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28285 this.collapseBtn.on("click", this.collapseClick, this);
28286 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28287 this.header.on("dblclick", this.collapseClick, this);
28289 if(this.resizable !== false){
28290 this.el.addClass("x-dlg-resizable");
28291 this.resizer = new Roo.Resizable(el, {
28292 minWidth: this.minWidth || 80,
28293 minHeight:this.minHeight || 80,
28294 handles: this.resizeHandles || "all",
28297 this.resizer.on("beforeresize", this.beforeResize, this);
28298 this.resizer.on("resize", this.onResize, this);
28300 if(this.draggable !== false){
28301 el.addClass("x-dlg-draggable");
28302 if (!this.proxyDrag) {
28303 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28306 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28308 dd.setHandleElId(this.header.id);
28309 dd.endDrag = this.endMove.createDelegate(this);
28310 dd.startDrag = this.startMove.createDelegate(this);
28311 dd.onDrag = this.onDrag.createDelegate(this);
28316 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28317 this.mask.enableDisplayMode("block");
28319 this.el.addClass("x-dlg-modal");
28322 this.shadow = new Roo.Shadow({
28323 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28324 offset : this.shadowOffset
28327 this.shadowOffset = 0;
28329 if(Roo.useShims && this.shim !== false){
28330 this.shim = this.el.createShim();
28331 this.shim.hide = this.hideAction;
28339 if (this.buttons) {
28340 var bts= this.buttons;
28342 Roo.each(bts, function(b) {
28351 * Fires when a key is pressed
28352 * @param {Roo.BasicDialog} this
28353 * @param {Roo.EventObject} e
28358 * Fires when this dialog is moved by the user.
28359 * @param {Roo.BasicDialog} this
28360 * @param {Number} x The new page X
28361 * @param {Number} y The new page Y
28366 * Fires when this dialog is resized by the user.
28367 * @param {Roo.BasicDialog} this
28368 * @param {Number} width The new width
28369 * @param {Number} height The new height
28373 * @event beforehide
28374 * Fires before this dialog is hidden.
28375 * @param {Roo.BasicDialog} this
28377 "beforehide" : true,
28380 * Fires when this dialog is hidden.
28381 * @param {Roo.BasicDialog} this
28385 * @event beforeshow
28386 * Fires before this dialog is shown.
28387 * @param {Roo.BasicDialog} this
28389 "beforeshow" : true,
28392 * Fires when this dialog is shown.
28393 * @param {Roo.BasicDialog} this
28397 el.on("keydown", this.onKeyDown, this);
28398 el.on("mousedown", this.toFront, this);
28399 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28401 Roo.DialogManager.register(this);
28402 Roo.BasicDialog.superclass.constructor.call(this);
28405 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28406 shadowOffset: Roo.isIE ? 6 : 5,
28409 minButtonWidth: 75,
28410 defaultButton: null,
28411 buttonAlign: "right",
28416 * Sets the dialog title text
28417 * @param {String} text The title text to display
28418 * @return {Roo.BasicDialog} this
28420 setTitle : function(text){
28421 this.header.update(text);
28426 closeClick : function(){
28431 collapseClick : function(){
28432 this[this.collapsed ? "expand" : "collapse"]();
28436 * Collapses the dialog to its minimized state (only the title bar is visible).
28437 * Equivalent to the user clicking the collapse dialog button.
28439 collapse : function(){
28440 if(!this.collapsed){
28441 this.collapsed = true;
28442 this.el.addClass("x-dlg-collapsed");
28443 this.restoreHeight = this.el.getHeight();
28444 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28449 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28450 * clicking the expand dialog button.
28452 expand : function(){
28453 if(this.collapsed){
28454 this.collapsed = false;
28455 this.el.removeClass("x-dlg-collapsed");
28456 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28461 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28462 * @return {Roo.TabPanel} The tabs component
28464 initTabs : function(){
28465 var tabs = this.getTabs();
28466 while(tabs.getTab(0)){
28469 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28471 tabs.addTab(Roo.id(dom), dom.title);
28479 beforeResize : function(){
28480 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28484 onResize : function(){
28485 this.refreshSize();
28486 this.syncBodyHeight();
28487 this.adjustAssets();
28489 this.fireEvent("resize", this, this.size.width, this.size.height);
28493 onKeyDown : function(e){
28494 if(this.isVisible()){
28495 this.fireEvent("keydown", this, e);
28500 * Resizes the dialog.
28501 * @param {Number} width
28502 * @param {Number} height
28503 * @return {Roo.BasicDialog} this
28505 resizeTo : function(width, height){
28506 this.el.setSize(width, height);
28507 this.size = {width: width, height: height};
28508 this.syncBodyHeight();
28509 if(this.fixedcenter){
28512 if(this.isVisible()){
28513 this.constrainXY();
28514 this.adjustAssets();
28516 this.fireEvent("resize", this, width, height);
28522 * Resizes the dialog to fit the specified content size.
28523 * @param {Number} width
28524 * @param {Number} height
28525 * @return {Roo.BasicDialog} this
28527 setContentSize : function(w, h){
28528 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28529 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28530 //if(!this.el.isBorderBox()){
28531 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28532 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28535 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28536 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28538 this.resizeTo(w, h);
28543 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28544 * executed in response to a particular key being pressed while the dialog is active.
28545 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28546 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28547 * @param {Function} fn The function to call
28548 * @param {Object} scope (optional) The scope of the function
28549 * @return {Roo.BasicDialog} this
28551 addKeyListener : function(key, fn, scope){
28552 var keyCode, shift, ctrl, alt;
28553 if(typeof key == "object" && !(key instanceof Array)){
28554 keyCode = key["key"];
28555 shift = key["shift"];
28556 ctrl = key["ctrl"];
28561 var handler = function(dlg, e){
28562 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28563 var k = e.getKey();
28564 if(keyCode instanceof Array){
28565 for(var i = 0, len = keyCode.length; i < len; i++){
28566 if(keyCode[i] == k){
28567 fn.call(scope || window, dlg, k, e);
28573 fn.call(scope || window, dlg, k, e);
28578 this.on("keydown", handler);
28583 * Returns the TabPanel component (creates it if it doesn't exist).
28584 * Note: If you wish to simply check for the existence of tabs without creating them,
28585 * check for a null 'tabs' property.
28586 * @return {Roo.TabPanel} The tabs component
28588 getTabs : function(){
28590 this.el.addClass("x-dlg-auto-tabs");
28591 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28592 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28598 * Adds a button to the footer section of the dialog.
28599 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28600 * object or a valid Roo.DomHelper element config
28601 * @param {Function} handler The function called when the button is clicked
28602 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28603 * @return {Roo.Button} The new button
28605 addButton : function(config, handler, scope){
28606 var dh = Roo.DomHelper;
28608 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28610 if(!this.btnContainer){
28611 var tb = this.footer.createChild({
28613 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28614 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28616 this.btnContainer = tb.firstChild.firstChild.firstChild;
28621 minWidth: this.minButtonWidth,
28624 if(typeof config == "string"){
28625 bconfig.text = config;
28628 bconfig.dhconfig = config;
28630 Roo.apply(bconfig, config);
28634 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
28635 bconfig.position = Math.max(0, bconfig.position);
28636 fc = this.btnContainer.childNodes[bconfig.position];
28639 var btn = new Roo.Button(
28641 this.btnContainer.insertBefore(document.createElement("td"),fc)
28642 : this.btnContainer.appendChild(document.createElement("td")),
28643 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
28646 this.syncBodyHeight();
28649 * Array of all the buttons that have been added to this dialog via addButton
28654 this.buttons.push(btn);
28659 * Sets the default button to be focused when the dialog is displayed.
28660 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
28661 * @return {Roo.BasicDialog} this
28663 setDefaultButton : function(btn){
28664 this.defaultButton = btn;
28669 getHeaderFooterHeight : function(safe){
28672 height += this.header.getHeight();
28675 var fm = this.footer.getMargins();
28676 height += (this.footer.getHeight()+fm.top+fm.bottom);
28678 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
28679 height += this.centerBg.getPadding("tb");
28684 syncBodyHeight : function(){
28685 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
28686 var height = this.size.height - this.getHeaderFooterHeight(false);
28687 bd.setHeight(height-bd.getMargins("tb"));
28688 var hh = this.header.getHeight();
28689 var h = this.size.height-hh;
28691 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
28692 bw.setHeight(h-cb.getPadding("tb"));
28693 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
28694 bd.setWidth(bw.getWidth(true));
28696 this.tabs.syncHeight();
28698 this.tabs.el.repaint();
28704 * Restores the previous state of the dialog if Roo.state is configured.
28705 * @return {Roo.BasicDialog} this
28707 restoreState : function(){
28708 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
28709 if(box && box.width){
28710 this.xy = [box.x, box.y];
28711 this.resizeTo(box.width, box.height);
28717 beforeShow : function(){
28719 if(this.fixedcenter){
28720 this.xy = this.el.getCenterXY(true);
28723 Roo.get(document.body).addClass("x-body-masked");
28724 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28727 this.constrainXY();
28731 animShow : function(){
28732 var b = Roo.get(this.animateTarget, true).getBox();
28733 this.proxy.setSize(b.width, b.height);
28734 this.proxy.setLocation(b.x, b.y);
28736 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
28737 true, .35, this.showEl.createDelegate(this));
28741 * Shows the dialog.
28742 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
28743 * @return {Roo.BasicDialog} this
28745 show : function(animateTarget){
28746 if (this.fireEvent("beforeshow", this) === false){
28749 if(this.syncHeightBeforeShow){
28750 this.syncBodyHeight();
28751 }else if(this.firstShow){
28752 this.firstShow = false;
28753 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
28755 this.animateTarget = animateTarget || this.animateTarget;
28756 if(!this.el.isVisible()){
28758 if(this.animateTarget){
28768 showEl : function(){
28770 this.el.setXY(this.xy);
28772 this.adjustAssets(true);
28775 // IE peekaboo bug - fix found by Dave Fenwick
28779 this.fireEvent("show", this);
28783 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
28784 * dialog itself will receive focus.
28786 focus : function(){
28787 if(this.defaultButton){
28788 this.defaultButton.focus();
28790 this.focusEl.focus();
28795 constrainXY : function(){
28796 if(this.constraintoviewport !== false){
28797 if(!this.viewSize){
28798 if(this.container){
28799 var s = this.container.getSize();
28800 this.viewSize = [s.width, s.height];
28802 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
28805 var s = Roo.get(this.container||document).getScroll();
28807 var x = this.xy[0], y = this.xy[1];
28808 var w = this.size.width, h = this.size.height;
28809 var vw = this.viewSize[0], vh = this.viewSize[1];
28810 // only move it if it needs it
28812 // first validate right/bottom
28813 if(x + w > vw+s.left){
28817 if(y + h > vh+s.top){
28821 // then make sure top/left isn't negative
28833 if(this.isVisible()){
28834 this.el.setLocation(x, y);
28835 this.adjustAssets();
28842 onDrag : function(){
28843 if(!this.proxyDrag){
28844 this.xy = this.el.getXY();
28845 this.adjustAssets();
28850 adjustAssets : function(doShow){
28851 var x = this.xy[0], y = this.xy[1];
28852 var w = this.size.width, h = this.size.height;
28853 if(doShow === true){
28855 this.shadow.show(this.el);
28861 if(this.shadow && this.shadow.isVisible()){
28862 this.shadow.show(this.el);
28864 if(this.shim && this.shim.isVisible()){
28865 this.shim.setBounds(x, y, w, h);
28870 adjustViewport : function(w, h){
28872 w = Roo.lib.Dom.getViewWidth();
28873 h = Roo.lib.Dom.getViewHeight();
28876 this.viewSize = [w, h];
28877 if(this.modal && this.mask.isVisible()){
28878 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
28879 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28881 if(this.isVisible()){
28882 this.constrainXY();
28887 * Destroys this dialog and all its supporting elements (including any tabs, shim,
28888 * shadow, proxy, mask, etc.) Also removes all event listeners.
28889 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28891 destroy : function(removeEl){
28892 if(this.isVisible()){
28893 this.animateTarget = null;
28896 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
28898 this.tabs.destroy(removeEl);
28911 for(var i = 0, len = this.buttons.length; i < len; i++){
28912 this.buttons[i].destroy();
28915 this.el.removeAllListeners();
28916 if(removeEl === true){
28917 this.el.update("");
28920 Roo.DialogManager.unregister(this);
28924 startMove : function(){
28925 if(this.proxyDrag){
28928 if(this.constraintoviewport !== false){
28929 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
28934 endMove : function(){
28935 if(!this.proxyDrag){
28936 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
28938 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
28941 this.refreshSize();
28942 this.adjustAssets();
28944 this.fireEvent("move", this, this.xy[0], this.xy[1]);
28948 * Brings this dialog to the front of any other visible dialogs
28949 * @return {Roo.BasicDialog} this
28951 toFront : function(){
28952 Roo.DialogManager.bringToFront(this);
28957 * Sends this dialog to the back (under) of any other visible dialogs
28958 * @return {Roo.BasicDialog} this
28960 toBack : function(){
28961 Roo.DialogManager.sendToBack(this);
28966 * Centers this dialog in the viewport
28967 * @return {Roo.BasicDialog} this
28969 center : function(){
28970 var xy = this.el.getCenterXY(true);
28971 this.moveTo(xy[0], xy[1]);
28976 * Moves the dialog's top-left corner to the specified point
28977 * @param {Number} x
28978 * @param {Number} y
28979 * @return {Roo.BasicDialog} this
28981 moveTo : function(x, y){
28983 if(this.isVisible()){
28984 this.el.setXY(this.xy);
28985 this.adjustAssets();
28991 * Aligns the dialog to the specified element
28992 * @param {String/HTMLElement/Roo.Element} element The element to align to.
28993 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
28994 * @param {Array} offsets (optional) Offset the positioning by [x, y]
28995 * @return {Roo.BasicDialog} this
28997 alignTo : function(element, position, offsets){
28998 this.xy = this.el.getAlignToXY(element, position, offsets);
28999 if(this.isVisible()){
29000 this.el.setXY(this.xy);
29001 this.adjustAssets();
29007 * Anchors an element to another element and realigns it when the window is resized.
29008 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29009 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29010 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29011 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29012 * is a number, it is used as the buffer delay (defaults to 50ms).
29013 * @return {Roo.BasicDialog} this
29015 anchorTo : function(el, alignment, offsets, monitorScroll){
29016 var action = function(){
29017 this.alignTo(el, alignment, offsets);
29019 Roo.EventManager.onWindowResize(action, this);
29020 var tm = typeof monitorScroll;
29021 if(tm != 'undefined'){
29022 Roo.EventManager.on(window, 'scroll', action, this,
29023 {buffer: tm == 'number' ? monitorScroll : 50});
29030 * Returns true if the dialog is visible
29031 * @return {Boolean}
29033 isVisible : function(){
29034 return this.el.isVisible();
29038 animHide : function(callback){
29039 var b = Roo.get(this.animateTarget).getBox();
29041 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29043 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29044 this.hideEl.createDelegate(this, [callback]));
29048 * Hides the dialog.
29049 * @param {Function} callback (optional) Function to call when the dialog is hidden
29050 * @return {Roo.BasicDialog} this
29052 hide : function(callback){
29053 if (this.fireEvent("beforehide", this) === false){
29057 this.shadow.hide();
29062 if(this.animateTarget){
29063 this.animHide(callback);
29066 this.hideEl(callback);
29072 hideEl : function(callback){
29076 Roo.get(document.body).removeClass("x-body-masked");
29078 this.fireEvent("hide", this);
29079 if(typeof callback == "function"){
29085 hideAction : function(){
29086 this.setLeft("-10000px");
29087 this.setTop("-10000px");
29088 this.setStyle("visibility", "hidden");
29092 refreshSize : function(){
29093 this.size = this.el.getSize();
29094 this.xy = this.el.getXY();
29095 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29099 // z-index is managed by the DialogManager and may be overwritten at any time
29100 setZIndex : function(index){
29102 this.mask.setStyle("z-index", index);
29105 this.shim.setStyle("z-index", ++index);
29108 this.shadow.setZIndex(++index);
29110 this.el.setStyle("z-index", ++index);
29112 this.proxy.setStyle("z-index", ++index);
29115 this.resizer.proxy.setStyle("z-index", ++index);
29118 this.lastZIndex = index;
29122 * Returns the element for this dialog
29123 * @return {Roo.Element} The underlying dialog Element
29125 getEl : function(){
29131 * @class Roo.DialogManager
29132 * Provides global access to BasicDialogs that have been created and
29133 * support for z-indexing (layering) multiple open dialogs.
29135 Roo.DialogManager = function(){
29137 var accessList = [];
29141 var sortDialogs = function(d1, d2){
29142 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29146 var orderDialogs = function(){
29147 accessList.sort(sortDialogs);
29148 var seed = Roo.DialogManager.zseed;
29149 for(var i = 0, len = accessList.length; i < len; i++){
29150 var dlg = accessList[i];
29152 dlg.setZIndex(seed + (i*10));
29159 * The starting z-index for BasicDialogs (defaults to 9000)
29160 * @type Number The z-index value
29165 register : function(dlg){
29166 list[dlg.id] = dlg;
29167 accessList.push(dlg);
29171 unregister : function(dlg){
29172 delete list[dlg.id];
29175 if(!accessList.indexOf){
29176 for( i = 0, len = accessList.length; i < len; i++){
29177 if(accessList[i] == dlg){
29178 accessList.splice(i, 1);
29183 i = accessList.indexOf(dlg);
29185 accessList.splice(i, 1);
29191 * Gets a registered dialog by id
29192 * @param {String/Object} id The id of the dialog or a dialog
29193 * @return {Roo.BasicDialog} this
29195 get : function(id){
29196 return typeof id == "object" ? id : list[id];
29200 * Brings the specified dialog to the front
29201 * @param {String/Object} dlg The id of the dialog or a dialog
29202 * @return {Roo.BasicDialog} this
29204 bringToFront : function(dlg){
29205 dlg = this.get(dlg);
29208 dlg._lastAccess = new Date().getTime();
29215 * Sends the specified dialog to the back
29216 * @param {String/Object} dlg The id of the dialog or a dialog
29217 * @return {Roo.BasicDialog} this
29219 sendToBack : function(dlg){
29220 dlg = this.get(dlg);
29221 dlg._lastAccess = -(new Date().getTime());
29227 * Hides all dialogs
29229 hideAll : function(){
29230 for(var id in list){
29231 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29240 * @class Roo.LayoutDialog
29241 * @extends Roo.BasicDialog
29242 * Dialog which provides adjustments for working with a layout in a Dialog.
29243 * Add your necessary layout config options to the dialog's config.<br>
29244 * Example usage (including a nested layout):
29247 dialog = new Roo.LayoutDialog("download-dlg", {
29256 // layout config merges with the dialog config
29258 tabPosition: "top",
29259 alwaysShowTabs: true
29262 dialog.addKeyListener(27, dialog.hide, dialog);
29263 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29264 dialog.addButton("Build It!", this.getDownload, this);
29266 // we can even add nested layouts
29267 var innerLayout = new Roo.BorderLayout("dl-inner", {
29277 innerLayout.beginUpdate();
29278 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29279 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29280 innerLayout.endUpdate(true);
29282 var layout = dialog.getLayout();
29283 layout.beginUpdate();
29284 layout.add("center", new Roo.ContentPanel("standard-panel",
29285 {title: "Download the Source", fitToFrame:true}));
29286 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29287 {title: "Build your own roo.js"}));
29288 layout.getRegion("center").showPanel(sp);
29289 layout.endUpdate();
29293 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29294 * @param {Object} config configuration options
29296 Roo.LayoutDialog = function(el, cfg){
29299 if (typeof(cfg) == 'undefined') {
29300 config = Roo.apply({}, el);
29301 el = Roo.get( document.documentElement || document.body).createChild();
29302 //config.autoCreate = true;
29306 config.autoTabs = false;
29307 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29308 this.body.setStyle({overflow:"hidden", position:"relative"});
29309 this.layout = new Roo.BorderLayout(this.body.dom, config);
29310 this.layout.monitorWindowResize = false;
29311 this.el.addClass("x-dlg-auto-layout");
29312 // fix case when center region overwrites center function
29313 this.center = Roo.BasicDialog.prototype.center;
29314 this.on("show", this.layout.layout, this.layout, true);
29315 if (config.items) {
29316 var xitems = config.items;
29317 delete config.items;
29318 Roo.each(xitems, this.addxtype, this);
29323 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29325 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29328 endUpdate : function(){
29329 this.layout.endUpdate();
29333 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29336 beginUpdate : function(){
29337 this.layout.beginUpdate();
29341 * Get the BorderLayout for this dialog
29342 * @return {Roo.BorderLayout}
29344 getLayout : function(){
29345 return this.layout;
29348 showEl : function(){
29349 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29351 this.layout.layout();
29356 // Use the syncHeightBeforeShow config option to control this automatically
29357 syncBodyHeight : function(){
29358 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29359 if(this.layout){this.layout.layout();}
29363 * Add an xtype element (actually adds to the layout.)
29364 * @return {Object} xdata xtype object data.
29367 addxtype : function(c) {
29368 return this.layout.addxtype(c);
29372 * Ext JS Library 1.1.1
29373 * Copyright(c) 2006-2007, Ext JS, LLC.
29375 * Originally Released Under LGPL - original licence link has changed is not relivant.
29378 * <script type="text/javascript">
29382 * @class Roo.MessageBox
29383 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29387 Roo.Msg.alert('Status', 'Changes saved successfully.');
29389 // Prompt for user data:
29390 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29392 // process text value...
29396 // Show a dialog using config options:
29398 title:'Save Changes?',
29399 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29400 buttons: Roo.Msg.YESNOCANCEL,
29407 Roo.MessageBox = function(){
29408 var dlg, opt, mask, waitTimer;
29409 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29410 var buttons, activeTextEl, bwidth;
29413 var handleButton = function(button){
29415 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29419 var handleHide = function(){
29420 if(opt && opt.cls){
29421 dlg.el.removeClass(opt.cls);
29424 Roo.TaskMgr.stop(waitTimer);
29430 var updateButtons = function(b){
29433 buttons["ok"].hide();
29434 buttons["cancel"].hide();
29435 buttons["yes"].hide();
29436 buttons["no"].hide();
29437 dlg.footer.dom.style.display = 'none';
29440 dlg.footer.dom.style.display = '';
29441 for(var k in buttons){
29442 if(typeof buttons[k] != "function"){
29445 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29446 width += buttons[k].el.getWidth()+15;
29456 var handleEsc = function(d, k, e){
29457 if(opt && opt.closable !== false){
29467 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29468 * @return {Roo.BasicDialog} The BasicDialog element
29470 getDialog : function(){
29472 dlg = new Roo.BasicDialog("x-msg-box", {
29477 constraintoviewport:false,
29479 collapsible : false,
29482 width:400, height:100,
29483 buttonAlign:"center",
29484 closeClick : function(){
29485 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29486 handleButton("no");
29488 handleButton("cancel");
29492 dlg.on("hide", handleHide);
29494 dlg.addKeyListener(27, handleEsc);
29496 var bt = this.buttonText;
29497 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29498 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29499 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29500 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29501 bodyEl = dlg.body.createChild({
29503 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>'
29505 msgEl = bodyEl.dom.firstChild;
29506 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29507 textboxEl.enableDisplayMode();
29508 textboxEl.addKeyListener([10,13], function(){
29509 if(dlg.isVisible() && opt && opt.buttons){
29510 if(opt.buttons.ok){
29511 handleButton("ok");
29512 }else if(opt.buttons.yes){
29513 handleButton("yes");
29517 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29518 textareaEl.enableDisplayMode();
29519 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29520 progressEl.enableDisplayMode();
29521 var pf = progressEl.dom.firstChild;
29523 pp = Roo.get(pf.firstChild);
29524 pp.setHeight(pf.offsetHeight);
29532 * Updates the message box body text
29533 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29534 * the XHTML-compliant non-breaking space character '&#160;')
29535 * @return {Roo.MessageBox} This message box
29537 updateText : function(text){
29538 if(!dlg.isVisible() && !opt.width){
29539 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29541 msgEl.innerHTML = text || ' ';
29542 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29543 Math.max(opt.minWidth || this.minWidth, bwidth));
29545 activeTextEl.setWidth(w);
29547 if(dlg.isVisible()){
29548 dlg.fixedcenter = false;
29550 dlg.setContentSize(w, bodyEl.getHeight());
29551 if(dlg.isVisible()){
29552 dlg.fixedcenter = true;
29558 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29559 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29560 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29561 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29562 * @return {Roo.MessageBox} This message box
29564 updateProgress : function(value, text){
29566 this.updateText(text);
29568 if (pp) { // weird bug on my firefox - for some reason this is not defined
29569 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29575 * Returns true if the message box is currently displayed
29576 * @return {Boolean} True if the message box is visible, else false
29578 isVisible : function(){
29579 return dlg && dlg.isVisible();
29583 * Hides the message box if it is displayed
29586 if(this.isVisible()){
29592 * Displays a new message box, or reinitializes an existing message box, based on the config options
29593 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29594 * The following config object properties are supported:
29596 Property Type Description
29597 ---------- --------------- ------------------------------------------------------------------------------------
29598 animEl String/Element An id or Element from which the message box should animate as it opens and
29599 closes (defaults to undefined)
29600 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29601 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29602 closable Boolean False to hide the top-right close button (defaults to true). Note that
29603 progress and wait dialogs will ignore this property and always hide the
29604 close button as they can only be closed programmatically.
29605 cls String A custom CSS class to apply to the message box element
29606 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29607 displayed (defaults to 75)
29608 fn Function A callback function to execute after closing the dialog. The arguments to the
29609 function will be btn (the name of the button that was clicked, if applicable,
29610 e.g. "ok"), and text (the value of the active text field, if applicable).
29611 Progress and wait dialogs will ignore this option since they do not respond to
29612 user actions and can only be closed programmatically, so any required function
29613 should be called by the same code after it closes the dialog.
29614 icon String A CSS class that provides a background image to be used as an icon for
29615 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29616 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29617 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29618 modal Boolean False to allow user interaction with the page while the message box is
29619 displayed (defaults to true)
29620 msg String A string that will replace the existing message box body text (defaults
29621 to the XHTML-compliant non-breaking space character ' ')
29622 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
29623 progress Boolean True to display a progress bar (defaults to false)
29624 progressText String The text to display inside the progress bar if progress = true (defaults to '')
29625 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
29626 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
29627 title String The title text
29628 value String The string value to set into the active textbox element if displayed
29629 wait Boolean True to display a progress bar (defaults to false)
29630 width Number The width of the dialog in pixels
29637 msg: 'Please enter your address:',
29639 buttons: Roo.MessageBox.OKCANCEL,
29642 animEl: 'addAddressBtn'
29645 * @param {Object} config Configuration options
29646 * @return {Roo.MessageBox} This message box
29648 show : function(options){
29649 if(this.isVisible()){
29652 var d = this.getDialog();
29654 d.setTitle(opt.title || " ");
29655 d.close.setDisplayed(opt.closable !== false);
29656 activeTextEl = textboxEl;
29657 opt.prompt = opt.prompt || (opt.multiline ? true : false);
29662 textareaEl.setHeight(typeof opt.multiline == "number" ?
29663 opt.multiline : this.defaultTextHeight);
29664 activeTextEl = textareaEl;
29673 progressEl.setDisplayed(opt.progress === true);
29674 this.updateProgress(0);
29675 activeTextEl.dom.value = opt.value || "";
29677 dlg.setDefaultButton(activeTextEl);
29679 var bs = opt.buttons;
29682 db = buttons["ok"];
29683 }else if(bs && bs.yes){
29684 db = buttons["yes"];
29686 dlg.setDefaultButton(db);
29688 bwidth = updateButtons(opt.buttons);
29689 this.updateText(opt.msg);
29691 d.el.addClass(opt.cls);
29693 d.proxyDrag = opt.proxyDrag === true;
29694 d.modal = opt.modal !== false;
29695 d.mask = opt.modal !== false ? mask : false;
29696 if(!d.isVisible()){
29697 // force it to the end of the z-index stack so it gets a cursor in FF
29698 document.body.appendChild(dlg.el.dom);
29699 d.animateTarget = null;
29700 d.show(options.animEl);
29706 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
29707 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
29708 * and closing the message box when the process is complete.
29709 * @param {String} title The title bar text
29710 * @param {String} msg The message box body text
29711 * @return {Roo.MessageBox} This message box
29713 progress : function(title, msg){
29720 minWidth: this.minProgressWidth,
29727 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
29728 * If a callback function is passed it will be called after the user clicks the button, and the
29729 * id of the button that was clicked will be passed as the only parameter to the callback
29730 * (could also be the top-right close button).
29731 * @param {String} title The title bar text
29732 * @param {String} msg The message box body text
29733 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29734 * @param {Object} scope (optional) The scope of the callback function
29735 * @return {Roo.MessageBox} This message box
29737 alert : function(title, msg, fn, scope){
29750 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
29751 * interaction while waiting for a long-running process to complete that does not have defined intervals.
29752 * You are responsible for closing the message box when the process is complete.
29753 * @param {String} msg The message box body text
29754 * @param {String} title (optional) The title bar text
29755 * @return {Roo.MessageBox} This message box
29757 wait : function(msg, title){
29768 waitTimer = Roo.TaskMgr.start({
29770 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
29778 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
29779 * If a callback function is passed it will be called after the user clicks either button, and the id of the
29780 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
29781 * @param {String} title The title bar text
29782 * @param {String} msg The message box body text
29783 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29784 * @param {Object} scope (optional) The scope of the callback function
29785 * @return {Roo.MessageBox} This message box
29787 confirm : function(title, msg, fn, scope){
29791 buttons: this.YESNO,
29800 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
29801 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
29802 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
29803 * (could also be the top-right close button) and the text that was entered will be passed as the two
29804 * parameters to the callback.
29805 * @param {String} title The title bar text
29806 * @param {String} msg The message box body text
29807 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29808 * @param {Object} scope (optional) The scope of the callback function
29809 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
29810 * property, or the height in pixels to create the textbox (defaults to false / single-line)
29811 * @return {Roo.MessageBox} This message box
29813 prompt : function(title, msg, fn, scope, multiline){
29817 buttons: this.OKCANCEL,
29822 multiline: multiline,
29829 * Button config that displays a single OK button
29834 * Button config that displays Yes and No buttons
29837 YESNO : {yes:true, no:true},
29839 * Button config that displays OK and Cancel buttons
29842 OKCANCEL : {ok:true, cancel:true},
29844 * Button config that displays Yes, No and Cancel buttons
29847 YESNOCANCEL : {yes:true, no:true, cancel:true},
29850 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
29853 defaultTextHeight : 75,
29855 * The maximum width in pixels of the message box (defaults to 600)
29860 * The minimum width in pixels of the message box (defaults to 100)
29865 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
29866 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
29869 minProgressWidth : 250,
29871 * An object containing the default button text strings that can be overriden for localized language support.
29872 * Supported properties are: ok, cancel, yes and no.
29873 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
29886 * Shorthand for {@link Roo.MessageBox}
29888 Roo.Msg = Roo.MessageBox;/*
29890 * Ext JS Library 1.1.1
29891 * Copyright(c) 2006-2007, Ext JS, LLC.
29893 * Originally Released Under LGPL - original licence link has changed is not relivant.
29896 * <script type="text/javascript">
29899 * @class Roo.QuickTips
29900 * Provides attractive and customizable tooltips for any element.
29903 Roo.QuickTips = function(){
29904 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
29905 var ce, bd, xy, dd;
29906 var visible = false, disabled = true, inited = false;
29907 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
29909 var onOver = function(e){
29913 var t = e.getTarget();
29914 if(!t || t.nodeType !== 1 || t == document || t == document.body){
29917 if(ce && t == ce.el){
29918 clearTimeout(hideProc);
29921 if(t && tagEls[t.id]){
29922 tagEls[t.id].el = t;
29923 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
29926 var ttp, et = Roo.fly(t);
29927 var ns = cfg.namespace;
29928 if(tm.interceptTitles && t.title){
29931 t.removeAttribute("title");
29932 e.preventDefault();
29934 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
29937 showProc = show.defer(tm.showDelay, tm, [{
29940 width: et.getAttributeNS(ns, cfg.width),
29941 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
29942 title: et.getAttributeNS(ns, cfg.title),
29943 cls: et.getAttributeNS(ns, cfg.cls)
29948 var onOut = function(e){
29949 clearTimeout(showProc);
29950 var t = e.getTarget();
29951 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
29952 hideProc = setTimeout(hide, tm.hideDelay);
29956 var onMove = function(e){
29962 if(tm.trackMouse && ce){
29967 var onDown = function(e){
29968 clearTimeout(showProc);
29969 clearTimeout(hideProc);
29971 if(tm.hideOnClick){
29974 tm.enable.defer(100, tm);
29979 var getPad = function(){
29980 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
29983 var show = function(o){
29987 clearTimeout(dismissProc);
29989 if(removeCls){ // in case manually hidden
29990 el.removeClass(removeCls);
29994 el.addClass(ce.cls);
29995 removeCls = ce.cls;
29998 tipTitle.update(ce.title);
30001 tipTitle.update('');
30004 el.dom.style.width = tm.maxWidth+'px';
30005 //tipBody.dom.style.width = '';
30006 tipBodyText.update(o.text);
30007 var p = getPad(), w = ce.width;
30009 var td = tipBodyText.dom;
30010 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30011 if(aw > tm.maxWidth){
30013 }else if(aw < tm.minWidth){
30019 //tipBody.setWidth(w);
30020 el.setWidth(parseInt(w, 10) + p);
30021 if(ce.autoHide === false){
30022 close.setDisplayed(true);
30027 close.setDisplayed(false);
30033 el.avoidY = xy[1]-18;
30038 el.setStyle("visibility", "visible");
30039 el.fadeIn({callback: afterShow});
30045 var afterShow = function(){
30049 if(tm.autoDismiss && ce.autoHide !== false){
30050 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30055 var hide = function(noanim){
30056 clearTimeout(dismissProc);
30057 clearTimeout(hideProc);
30059 if(el.isVisible()){
30061 if(noanim !== true && tm.animate){
30062 el.fadeOut({callback: afterHide});
30069 var afterHide = function(){
30072 el.removeClass(removeCls);
30079 * @cfg {Number} minWidth
30080 * The minimum width of the quick tip (defaults to 40)
30084 * @cfg {Number} maxWidth
30085 * The maximum width of the quick tip (defaults to 300)
30089 * @cfg {Boolean} interceptTitles
30090 * True to automatically use the element's DOM title value if available (defaults to false)
30092 interceptTitles : false,
30094 * @cfg {Boolean} trackMouse
30095 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30097 trackMouse : false,
30099 * @cfg {Boolean} hideOnClick
30100 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30102 hideOnClick : true,
30104 * @cfg {Number} showDelay
30105 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30109 * @cfg {Number} hideDelay
30110 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30114 * @cfg {Boolean} autoHide
30115 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30116 * Used in conjunction with hideDelay.
30121 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30122 * (defaults to true). Used in conjunction with autoDismissDelay.
30124 autoDismiss : true,
30127 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30129 autoDismissDelay : 5000,
30131 * @cfg {Boolean} animate
30132 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30137 * @cfg {String} title
30138 * Title text to display (defaults to ''). This can be any valid HTML markup.
30142 * @cfg {String} text
30143 * Body text to display (defaults to ''). This can be any valid HTML markup.
30147 * @cfg {String} cls
30148 * A CSS class to apply to the base quick tip element (defaults to '').
30152 * @cfg {Number} width
30153 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30154 * minWidth or maxWidth.
30159 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30160 * or display QuickTips in a page.
30163 tm = Roo.QuickTips;
30164 cfg = tm.tagConfig;
30166 if(!Roo.isReady){ // allow calling of init() before onReady
30167 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30170 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30171 el.fxDefaults = {stopFx: true};
30172 // maximum custom styling
30173 //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>');
30174 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>');
30175 tipTitle = el.child('h3');
30176 tipTitle.enableDisplayMode("block");
30177 tipBody = el.child('div.x-tip-bd');
30178 tipBodyText = el.child('div.x-tip-bd-inner');
30179 //bdLeft = el.child('div.x-tip-bd-left');
30180 //bdRight = el.child('div.x-tip-bd-right');
30181 close = el.child('div.x-tip-close');
30182 close.enableDisplayMode("block");
30183 close.on("click", hide);
30184 var d = Roo.get(document);
30185 d.on("mousedown", onDown);
30186 d.on("mouseover", onOver);
30187 d.on("mouseout", onOut);
30188 d.on("mousemove", onMove);
30189 esc = d.addKeyListener(27, hide);
30192 dd = el.initDD("default", null, {
30193 onDrag : function(){
30197 dd.setHandleElId(tipTitle.id);
30206 * Configures a new quick tip instance and assigns it to a target element. The following config options
30209 Property Type Description
30210 ---------- --------------------- ------------------------------------------------------------------------
30211 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30213 * @param {Object} config The config object
30215 register : function(config){
30216 var cs = config instanceof Array ? config : arguments;
30217 for(var i = 0, len = cs.length; i < len; i++) {
30219 var target = c.target;
30221 if(target instanceof Array){
30222 for(var j = 0, jlen = target.length; j < jlen; j++){
30223 tagEls[target[j]] = c;
30226 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30233 * Removes this quick tip from its element and destroys it.
30234 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30236 unregister : function(el){
30237 delete tagEls[Roo.id(el)];
30241 * Enable this quick tip.
30243 enable : function(){
30244 if(inited && disabled){
30246 if(locks.length < 1){
30253 * Disable this quick tip.
30255 disable : function(){
30257 clearTimeout(showProc);
30258 clearTimeout(hideProc);
30259 clearTimeout(dismissProc);
30267 * Returns true if the quick tip is enabled, else false.
30269 isEnabled : function(){
30276 attribute : "qtip",
30286 // backwards compat
30287 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30289 * Ext JS Library 1.1.1
30290 * Copyright(c) 2006-2007, Ext JS, LLC.
30292 * Originally Released Under LGPL - original licence link has changed is not relivant.
30295 * <script type="text/javascript">
30300 * @class Roo.tree.TreePanel
30301 * @extends Roo.data.Tree
30303 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30304 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30305 * @cfg {Boolean} enableDD true to enable drag and drop
30306 * @cfg {Boolean} enableDrag true to enable just drag
30307 * @cfg {Boolean} enableDrop true to enable just drop
30308 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30309 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30310 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30311 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30312 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30313 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30314 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30315 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30316 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30317 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30318 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30319 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30320 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30321 * @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>
30322 * @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>
30325 * @param {String/HTMLElement/Element} el The container element
30326 * @param {Object} config
30328 Roo.tree.TreePanel = function(el, config){
30330 var loader = false;
30332 root = config.root;
30333 delete config.root;
30335 if (config.loader) {
30336 loader = config.loader;
30337 delete config.loader;
30340 Roo.apply(this, config);
30341 Roo.tree.TreePanel.superclass.constructor.call(this);
30342 this.el = Roo.get(el);
30343 this.el.addClass('x-tree');
30344 //console.log(root);
30346 this.setRootNode( Roo.factory(root, Roo.tree));
30349 this.loader = Roo.factory(loader, Roo.tree);
30352 * Read-only. The id of the container element becomes this TreePanel's id.
30354 this.id = this.el.id;
30357 * @event beforeload
30358 * Fires before a node is loaded, return false to cancel
30359 * @param {Node} node The node being loaded
30361 "beforeload" : true,
30364 * Fires when a node is loaded
30365 * @param {Node} node The node that was loaded
30369 * @event textchange
30370 * Fires when the text for a node is changed
30371 * @param {Node} node The node
30372 * @param {String} text The new text
30373 * @param {String} oldText The old text
30375 "textchange" : true,
30377 * @event beforeexpand
30378 * Fires before a node is expanded, return false to cancel.
30379 * @param {Node} node The node
30380 * @param {Boolean} deep
30381 * @param {Boolean} anim
30383 "beforeexpand" : true,
30385 * @event beforecollapse
30386 * Fires before a node is collapsed, return false to cancel.
30387 * @param {Node} node The node
30388 * @param {Boolean} deep
30389 * @param {Boolean} anim
30391 "beforecollapse" : true,
30394 * Fires when a node is expanded
30395 * @param {Node} node The node
30399 * @event disabledchange
30400 * Fires when the disabled status of a node changes
30401 * @param {Node} node The node
30402 * @param {Boolean} disabled
30404 "disabledchange" : true,
30407 * Fires when a node is collapsed
30408 * @param {Node} node The node
30412 * @event beforeclick
30413 * Fires before click processing on a node. Return false to cancel the default action.
30414 * @param {Node} node The node
30415 * @param {Roo.EventObject} e The event object
30417 "beforeclick":true,
30419 * @event checkchange
30420 * Fires when a node with a checkbox's checked property changes
30421 * @param {Node} this This node
30422 * @param {Boolean} checked
30424 "checkchange":true,
30427 * Fires when a node is clicked
30428 * @param {Node} node The node
30429 * @param {Roo.EventObject} e The event object
30434 * Fires when a node is double clicked
30435 * @param {Node} node The node
30436 * @param {Roo.EventObject} e The event object
30440 * @event contextmenu
30441 * Fires when a node is right clicked
30442 * @param {Node} node The node
30443 * @param {Roo.EventObject} e The event object
30445 "contextmenu":true,
30447 * @event beforechildrenrendered
30448 * Fires right before the child nodes for a node are rendered
30449 * @param {Node} node The node
30451 "beforechildrenrendered":true,
30454 * Fires when a node starts being dragged
30455 * @param {Roo.tree.TreePanel} this
30456 * @param {Roo.tree.TreeNode} node
30457 * @param {event} e The raw browser event
30459 "startdrag" : true,
30462 * Fires when a drag operation is complete
30463 * @param {Roo.tree.TreePanel} this
30464 * @param {Roo.tree.TreeNode} node
30465 * @param {event} e The raw browser event
30470 * Fires when a dragged node is dropped on a valid DD target
30471 * @param {Roo.tree.TreePanel} this
30472 * @param {Roo.tree.TreeNode} node
30473 * @param {DD} dd The dd it was dropped on
30474 * @param {event} e The raw browser event
30478 * @event beforenodedrop
30479 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30480 * passed to handlers has the following properties:<br />
30481 * <ul style="padding:5px;padding-left:16px;">
30482 * <li>tree - The TreePanel</li>
30483 * <li>target - The node being targeted for the drop</li>
30484 * <li>data - The drag data from the drag source</li>
30485 * <li>point - The point of the drop - append, above or below</li>
30486 * <li>source - The drag source</li>
30487 * <li>rawEvent - Raw mouse event</li>
30488 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30489 * to be inserted by setting them on this object.</li>
30490 * <li>cancel - Set this to true to cancel the drop.</li>
30492 * @param {Object} dropEvent
30494 "beforenodedrop" : true,
30497 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30498 * passed to handlers has the following properties:<br />
30499 * <ul style="padding:5px;padding-left:16px;">
30500 * <li>tree - The TreePanel</li>
30501 * <li>target - The node being targeted for the drop</li>
30502 * <li>data - The drag data from the drag source</li>
30503 * <li>point - The point of the drop - append, above or below</li>
30504 * <li>source - The drag source</li>
30505 * <li>rawEvent - Raw mouse event</li>
30506 * <li>dropNode - Dropped node(s).</li>
30508 * @param {Object} dropEvent
30512 * @event nodedragover
30513 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30514 * passed to handlers has the following properties:<br />
30515 * <ul style="padding:5px;padding-left:16px;">
30516 * <li>tree - The TreePanel</li>
30517 * <li>target - The node being targeted for the drop</li>
30518 * <li>data - The drag data from the drag source</li>
30519 * <li>point - The point of the drop - append, above or below</li>
30520 * <li>source - The drag source</li>
30521 * <li>rawEvent - Raw mouse event</li>
30522 * <li>dropNode - Drop node(s) provided by the source.</li>
30523 * <li>cancel - Set this to true to signal drop not allowed.</li>
30525 * @param {Object} dragOverEvent
30527 "nodedragover" : true
30530 if(this.singleExpand){
30531 this.on("beforeexpand", this.restrictExpand, this);
30534 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30535 rootVisible : true,
30536 animate: Roo.enableFx,
30539 hlDrop : Roo.enableFx,
30543 rendererTip: false,
30545 restrictExpand : function(node){
30546 var p = node.parentNode;
30548 if(p.expandedChild && p.expandedChild.parentNode == p){
30549 p.expandedChild.collapse();
30551 p.expandedChild = node;
30555 // private override
30556 setRootNode : function(node){
30557 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30558 if(!this.rootVisible){
30559 node.ui = new Roo.tree.RootTreeNodeUI(node);
30565 * Returns the container element for this TreePanel
30567 getEl : function(){
30572 * Returns the default TreeLoader for this TreePanel
30574 getLoader : function(){
30575 return this.loader;
30581 expandAll : function(){
30582 this.root.expand(true);
30586 * Collapse all nodes
30588 collapseAll : function(){
30589 this.root.collapse(true);
30593 * Returns the selection model used by this TreePanel
30595 getSelectionModel : function(){
30596 if(!this.selModel){
30597 this.selModel = new Roo.tree.DefaultSelectionModel();
30599 return this.selModel;
30603 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30604 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30605 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30608 getChecked : function(a, startNode){
30609 startNode = startNode || this.root;
30611 var f = function(){
30612 if(this.attributes.checked){
30613 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30616 startNode.cascade(f);
30621 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30622 * @param {String} path
30623 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30624 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
30625 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
30627 expandPath : function(path, attr, callback){
30628 attr = attr || "id";
30629 var keys = path.split(this.pathSeparator);
30630 var curNode = this.root;
30631 if(curNode.attributes[attr] != keys[1]){ // invalid root
30633 callback(false, null);
30638 var f = function(){
30639 if(++index == keys.length){
30641 callback(true, curNode);
30645 var c = curNode.findChild(attr, keys[index]);
30648 callback(false, curNode);
30653 c.expand(false, false, f);
30655 curNode.expand(false, false, f);
30659 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30660 * @param {String} path
30661 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30662 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
30663 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
30665 selectPath : function(path, attr, callback){
30666 attr = attr || "id";
30667 var keys = path.split(this.pathSeparator);
30668 var v = keys.pop();
30669 if(keys.length > 0){
30670 var f = function(success, node){
30671 if(success && node){
30672 var n = node.findChild(attr, v);
30678 }else if(callback){
30679 callback(false, n);
30683 callback(false, n);
30687 this.expandPath(keys.join(this.pathSeparator), attr, f);
30689 this.root.select();
30691 callback(true, this.root);
30696 getTreeEl : function(){
30701 * Trigger rendering of this TreePanel
30703 render : function(){
30704 if (this.innerCt) {
30705 return this; // stop it rendering more than once!!
30708 this.innerCt = this.el.createChild({tag:"ul",
30709 cls:"x-tree-root-ct " +
30710 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
30712 if(this.containerScroll){
30713 Roo.dd.ScrollManager.register(this.el);
30715 if((this.enableDD || this.enableDrop) && !this.dropZone){
30717 * The dropZone used by this tree if drop is enabled
30718 * @type Roo.tree.TreeDropZone
30720 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
30721 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
30724 if((this.enableDD || this.enableDrag) && !this.dragZone){
30726 * The dragZone used by this tree if drag is enabled
30727 * @type Roo.tree.TreeDragZone
30729 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
30730 ddGroup: this.ddGroup || "TreeDD",
30731 scroll: this.ddScroll
30734 this.getSelectionModel().init(this);
30736 console.log("ROOT not set in tree");
30739 this.root.render();
30740 if(!this.rootVisible){
30741 this.root.renderChildren();
30747 * Ext JS Library 1.1.1
30748 * Copyright(c) 2006-2007, Ext JS, LLC.
30750 * Originally Released Under LGPL - original licence link has changed is not relivant.
30753 * <script type="text/javascript">
30758 * @class Roo.tree.DefaultSelectionModel
30759 * @extends Roo.util.Observable
30760 * The default single selection for a TreePanel.
30762 Roo.tree.DefaultSelectionModel = function(){
30763 this.selNode = null;
30767 * @event selectionchange
30768 * Fires when the selected node changes
30769 * @param {DefaultSelectionModel} this
30770 * @param {TreeNode} node the new selection
30772 "selectionchange" : true,
30775 * @event beforeselect
30776 * Fires before the selected node changes, return false to cancel the change
30777 * @param {DefaultSelectionModel} this
30778 * @param {TreeNode} node the new selection
30779 * @param {TreeNode} node the old selection
30781 "beforeselect" : true
30785 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
30786 init : function(tree){
30788 tree.getTreeEl().on("keydown", this.onKeyDown, this);
30789 tree.on("click", this.onNodeClick, this);
30792 onNodeClick : function(node, e){
30793 if (e.ctrlKey && this.selNode == node) {
30794 this.unselect(node);
30802 * @param {TreeNode} node The node to select
30803 * @return {TreeNode} The selected node
30805 select : function(node){
30806 var last = this.selNode;
30807 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
30809 last.ui.onSelectedChange(false);
30811 this.selNode = node;
30812 node.ui.onSelectedChange(true);
30813 this.fireEvent("selectionchange", this, node, last);
30820 * @param {TreeNode} node The node to unselect
30822 unselect : function(node){
30823 if(this.selNode == node){
30824 this.clearSelections();
30829 * Clear all selections
30831 clearSelections : function(){
30832 var n = this.selNode;
30834 n.ui.onSelectedChange(false);
30835 this.selNode = null;
30836 this.fireEvent("selectionchange", this, null);
30842 * Get the selected node
30843 * @return {TreeNode} The selected node
30845 getSelectedNode : function(){
30846 return this.selNode;
30850 * Returns true if the node is selected
30851 * @param {TreeNode} node The node to check
30852 * @return {Boolean}
30854 isSelected : function(node){
30855 return this.selNode == node;
30859 * Selects the node above the selected node in the tree, intelligently walking the nodes
30860 * @return TreeNode The new selection
30862 selectPrevious : function(){
30863 var s = this.selNode || this.lastSelNode;
30867 var ps = s.previousSibling;
30869 if(!ps.isExpanded() || ps.childNodes.length < 1){
30870 return this.select(ps);
30872 var lc = ps.lastChild;
30873 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
30876 return this.select(lc);
30878 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
30879 return this.select(s.parentNode);
30885 * Selects the node above the selected node in the tree, intelligently walking the nodes
30886 * @return TreeNode The new selection
30888 selectNext : function(){
30889 var s = this.selNode || this.lastSelNode;
30893 if(s.firstChild && s.isExpanded()){
30894 return this.select(s.firstChild);
30895 }else if(s.nextSibling){
30896 return this.select(s.nextSibling);
30897 }else if(s.parentNode){
30899 s.parentNode.bubble(function(){
30900 if(this.nextSibling){
30901 newS = this.getOwnerTree().selModel.select(this.nextSibling);
30910 onKeyDown : function(e){
30911 var s = this.selNode || this.lastSelNode;
30912 // undesirable, but required
30917 var k = e.getKey();
30925 this.selectPrevious();
30928 e.preventDefault();
30929 if(s.hasChildNodes()){
30930 if(!s.isExpanded()){
30932 }else if(s.firstChild){
30933 this.select(s.firstChild, e);
30938 e.preventDefault();
30939 if(s.hasChildNodes() && s.isExpanded()){
30941 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
30942 this.select(s.parentNode, e);
30950 * @class Roo.tree.MultiSelectionModel
30951 * @extends Roo.util.Observable
30952 * Multi selection for a TreePanel.
30954 Roo.tree.MultiSelectionModel = function(){
30955 this.selNodes = [];
30959 * @event selectionchange
30960 * Fires when the selected nodes change
30961 * @param {MultiSelectionModel} this
30962 * @param {Array} nodes Array of the selected nodes
30964 "selectionchange" : true
30968 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
30969 init : function(tree){
30971 tree.getTreeEl().on("keydown", this.onKeyDown, this);
30972 tree.on("click", this.onNodeClick, this);
30975 onNodeClick : function(node, e){
30976 this.select(node, e, e.ctrlKey);
30981 * @param {TreeNode} node The node to select
30982 * @param {EventObject} e (optional) An event associated with the selection
30983 * @param {Boolean} keepExisting True to retain existing selections
30984 * @return {TreeNode} The selected node
30986 select : function(node, e, keepExisting){
30987 if(keepExisting !== true){
30988 this.clearSelections(true);
30990 if(this.isSelected(node)){
30991 this.lastSelNode = node;
30994 this.selNodes.push(node);
30995 this.selMap[node.id] = node;
30996 this.lastSelNode = node;
30997 node.ui.onSelectedChange(true);
30998 this.fireEvent("selectionchange", this, this.selNodes);
31004 * @param {TreeNode} node The node to unselect
31006 unselect : function(node){
31007 if(this.selMap[node.id]){
31008 node.ui.onSelectedChange(false);
31009 var sn = this.selNodes;
31012 index = sn.indexOf(node);
31014 for(var i = 0, len = sn.length; i < len; i++){
31022 this.selNodes.splice(index, 1);
31024 delete this.selMap[node.id];
31025 this.fireEvent("selectionchange", this, this.selNodes);
31030 * Clear all selections
31032 clearSelections : function(suppressEvent){
31033 var sn = this.selNodes;
31035 for(var i = 0, len = sn.length; i < len; i++){
31036 sn[i].ui.onSelectedChange(false);
31038 this.selNodes = [];
31040 if(suppressEvent !== true){
31041 this.fireEvent("selectionchange", this, this.selNodes);
31047 * Returns true if the node is selected
31048 * @param {TreeNode} node The node to check
31049 * @return {Boolean}
31051 isSelected : function(node){
31052 return this.selMap[node.id] ? true : false;
31056 * Returns an array of the selected nodes
31059 getSelectedNodes : function(){
31060 return this.selNodes;
31063 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31065 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31067 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31070 * Ext JS Library 1.1.1
31071 * Copyright(c) 2006-2007, Ext JS, LLC.
31073 * Originally Released Under LGPL - original licence link has changed is not relivant.
31076 * <script type="text/javascript">
31080 * @class Roo.tree.TreeNode
31081 * @extends Roo.data.Node
31082 * @cfg {String} text The text for this node
31083 * @cfg {Boolean} expanded true to start the node expanded
31084 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31085 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31086 * @cfg {Boolean} disabled true to start the node disabled
31087 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31088 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31089 * @cfg {String} cls A css class to be added to the node
31090 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31091 * @cfg {String} href URL of the link used for the node (defaults to #)
31092 * @cfg {String} hrefTarget target frame for the link
31093 * @cfg {String} qtip An Ext QuickTip for the node
31094 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31095 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31096 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31097 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31098 * (defaults to undefined with no checkbox rendered)
31100 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31102 Roo.tree.TreeNode = function(attributes){
31103 attributes = attributes || {};
31104 if(typeof attributes == "string"){
31105 attributes = {text: attributes};
31107 this.childrenRendered = false;
31108 this.rendered = false;
31109 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31110 this.expanded = attributes.expanded === true;
31111 this.isTarget = attributes.isTarget !== false;
31112 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31113 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31116 * Read-only. The text for this node. To change it use setText().
31119 this.text = attributes.text;
31121 * True if this node is disabled.
31124 this.disabled = attributes.disabled === true;
31128 * @event textchange
31129 * Fires when the text for this node is changed
31130 * @param {Node} this This node
31131 * @param {String} text The new text
31132 * @param {String} oldText The old text
31134 "textchange" : true,
31136 * @event beforeexpand
31137 * Fires before this node is expanded, return false to cancel.
31138 * @param {Node} this This node
31139 * @param {Boolean} deep
31140 * @param {Boolean} anim
31142 "beforeexpand" : true,
31144 * @event beforecollapse
31145 * Fires before this node is collapsed, return false to cancel.
31146 * @param {Node} this This node
31147 * @param {Boolean} deep
31148 * @param {Boolean} anim
31150 "beforecollapse" : true,
31153 * Fires when this node is expanded
31154 * @param {Node} this This node
31158 * @event disabledchange
31159 * Fires when the disabled status of this node changes
31160 * @param {Node} this This node
31161 * @param {Boolean} disabled
31163 "disabledchange" : true,
31166 * Fires when this node is collapsed
31167 * @param {Node} this This node
31171 * @event beforeclick
31172 * Fires before click processing. Return false to cancel the default action.
31173 * @param {Node} this This node
31174 * @param {Roo.EventObject} e The event object
31176 "beforeclick":true,
31178 * @event checkchange
31179 * Fires when a node with a checkbox's checked property changes
31180 * @param {Node} this This node
31181 * @param {Boolean} checked
31183 "checkchange":true,
31186 * Fires when this node is clicked
31187 * @param {Node} this This node
31188 * @param {Roo.EventObject} e The event object
31193 * Fires when this node is double clicked
31194 * @param {Node} this This node
31195 * @param {Roo.EventObject} e The event object
31199 * @event contextmenu
31200 * Fires when this node is right clicked
31201 * @param {Node} this This node
31202 * @param {Roo.EventObject} e The event object
31204 "contextmenu":true,
31206 * @event beforechildrenrendered
31207 * Fires right before the child nodes for this node are rendered
31208 * @param {Node} this This node
31210 "beforechildrenrendered":true
31213 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31216 * Read-only. The UI for this node
31219 this.ui = new uiClass(this);
31221 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31222 preventHScroll: true,
31224 * Returns true if this node is expanded
31225 * @return {Boolean}
31227 isExpanded : function(){
31228 return this.expanded;
31232 * Returns the UI object for this node
31233 * @return {TreeNodeUI}
31235 getUI : function(){
31239 // private override
31240 setFirstChild : function(node){
31241 var of = this.firstChild;
31242 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31243 if(this.childrenRendered && of && node != of){
31244 of.renderIndent(true, true);
31247 this.renderIndent(true, true);
31251 // private override
31252 setLastChild : function(node){
31253 var ol = this.lastChild;
31254 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31255 if(this.childrenRendered && ol && node != ol){
31256 ol.renderIndent(true, true);
31259 this.renderIndent(true, true);
31263 // these methods are overridden to provide lazy rendering support
31264 // private override
31265 appendChild : function(){
31266 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31267 if(node && this.childrenRendered){
31270 this.ui.updateExpandIcon();
31274 // private override
31275 removeChild : function(node){
31276 this.ownerTree.getSelectionModel().unselect(node);
31277 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31278 // if it's been rendered remove dom node
31279 if(this.childrenRendered){
31282 if(this.childNodes.length < 1){
31283 this.collapse(false, false);
31285 this.ui.updateExpandIcon();
31287 if(!this.firstChild) {
31288 this.childrenRendered = false;
31293 // private override
31294 insertBefore : function(node, refNode){
31295 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31296 if(newNode && refNode && this.childrenRendered){
31299 this.ui.updateExpandIcon();
31304 * Sets the text for this node
31305 * @param {String} text
31307 setText : function(text){
31308 var oldText = this.text;
31310 this.attributes.text = text;
31311 if(this.rendered){ // event without subscribing
31312 this.ui.onTextChange(this, text, oldText);
31314 this.fireEvent("textchange", this, text, oldText);
31318 * Triggers selection of this node
31320 select : function(){
31321 this.getOwnerTree().getSelectionModel().select(this);
31325 * Triggers deselection of this node
31327 unselect : function(){
31328 this.getOwnerTree().getSelectionModel().unselect(this);
31332 * Returns true if this node is selected
31333 * @return {Boolean}
31335 isSelected : function(){
31336 return this.getOwnerTree().getSelectionModel().isSelected(this);
31340 * Expand this node.
31341 * @param {Boolean} deep (optional) True to expand all children as well
31342 * @param {Boolean} anim (optional) false to cancel the default animation
31343 * @param {Function} callback (optional) A callback to be called when
31344 * expanding this node completes (does not wait for deep expand to complete).
31345 * Called with 1 parameter, this node.
31347 expand : function(deep, anim, callback){
31348 if(!this.expanded){
31349 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31352 if(!this.childrenRendered){
31353 this.renderChildren();
31355 this.expanded = true;
31356 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31357 this.ui.animExpand(function(){
31358 this.fireEvent("expand", this);
31359 if(typeof callback == "function"){
31363 this.expandChildNodes(true);
31365 }.createDelegate(this));
31369 this.fireEvent("expand", this);
31370 if(typeof callback == "function"){
31375 if(typeof callback == "function"){
31380 this.expandChildNodes(true);
31384 isHiddenRoot : function(){
31385 return this.isRoot && !this.getOwnerTree().rootVisible;
31389 * Collapse this node.
31390 * @param {Boolean} deep (optional) True to collapse all children as well
31391 * @param {Boolean} anim (optional) false to cancel the default animation
31393 collapse : function(deep, anim){
31394 if(this.expanded && !this.isHiddenRoot()){
31395 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31398 this.expanded = false;
31399 if((this.getOwnerTree().animate && anim !== false) || anim){
31400 this.ui.animCollapse(function(){
31401 this.fireEvent("collapse", this);
31403 this.collapseChildNodes(true);
31405 }.createDelegate(this));
31408 this.ui.collapse();
31409 this.fireEvent("collapse", this);
31413 var cs = this.childNodes;
31414 for(var i = 0, len = cs.length; i < len; i++) {
31415 cs[i].collapse(true, false);
31421 delayedExpand : function(delay){
31422 if(!this.expandProcId){
31423 this.expandProcId = this.expand.defer(delay, this);
31428 cancelExpand : function(){
31429 if(this.expandProcId){
31430 clearTimeout(this.expandProcId);
31432 this.expandProcId = false;
31436 * Toggles expanded/collapsed state of the node
31438 toggle : function(){
31447 * Ensures all parent nodes are expanded
31449 ensureVisible : function(callback){
31450 var tree = this.getOwnerTree();
31451 tree.expandPath(this.parentNode.getPath(), false, function(){
31452 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31453 Roo.callback(callback);
31454 }.createDelegate(this));
31458 * Expand all child nodes
31459 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31461 expandChildNodes : function(deep){
31462 var cs = this.childNodes;
31463 for(var i = 0, len = cs.length; i < len; i++) {
31464 cs[i].expand(deep);
31469 * Collapse all child nodes
31470 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31472 collapseChildNodes : function(deep){
31473 var cs = this.childNodes;
31474 for(var i = 0, len = cs.length; i < len; i++) {
31475 cs[i].collapse(deep);
31480 * Disables this node
31482 disable : function(){
31483 this.disabled = true;
31485 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31486 this.ui.onDisableChange(this, true);
31488 this.fireEvent("disabledchange", this, true);
31492 * Enables this node
31494 enable : function(){
31495 this.disabled = false;
31496 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31497 this.ui.onDisableChange(this, false);
31499 this.fireEvent("disabledchange", this, false);
31503 renderChildren : function(suppressEvent){
31504 if(suppressEvent !== false){
31505 this.fireEvent("beforechildrenrendered", this);
31507 var cs = this.childNodes;
31508 for(var i = 0, len = cs.length; i < len; i++){
31509 cs[i].render(true);
31511 this.childrenRendered = true;
31515 sort : function(fn, scope){
31516 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31517 if(this.childrenRendered){
31518 var cs = this.childNodes;
31519 for(var i = 0, len = cs.length; i < len; i++){
31520 cs[i].render(true);
31526 render : function(bulkRender){
31527 this.ui.render(bulkRender);
31528 if(!this.rendered){
31529 this.rendered = true;
31531 this.expanded = false;
31532 this.expand(false, false);
31538 renderIndent : function(deep, refresh){
31540 this.ui.childIndent = null;
31542 this.ui.renderIndent();
31543 if(deep === true && this.childrenRendered){
31544 var cs = this.childNodes;
31545 for(var i = 0, len = cs.length; i < len; i++){
31546 cs[i].renderIndent(true, refresh);
31552 * Ext JS Library 1.1.1
31553 * Copyright(c) 2006-2007, Ext JS, LLC.
31555 * Originally Released Under LGPL - original licence link has changed is not relivant.
31558 * <script type="text/javascript">
31562 * @class Roo.tree.AsyncTreeNode
31563 * @extends Roo.tree.TreeNode
31564 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31566 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31568 Roo.tree.AsyncTreeNode = function(config){
31569 this.loaded = false;
31570 this.loading = false;
31571 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31573 * @event beforeload
31574 * Fires before this node is loaded, return false to cancel
31575 * @param {Node} this This node
31577 this.addEvents({'beforeload':true, 'load': true});
31580 * Fires when this node is loaded
31581 * @param {Node} this This node
31584 * The loader used by this node (defaults to using the tree's defined loader)
31589 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31590 expand : function(deep, anim, callback){
31591 if(this.loading){ // if an async load is already running, waiting til it's done
31593 var f = function(){
31594 if(!this.loading){ // done loading
31595 clearInterval(timer);
31596 this.expand(deep, anim, callback);
31598 }.createDelegate(this);
31599 timer = setInterval(f, 200);
31603 if(this.fireEvent("beforeload", this) === false){
31606 this.loading = true;
31607 this.ui.beforeLoad(this);
31608 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31610 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31614 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31618 * Returns true if this node is currently loading
31619 * @return {Boolean}
31621 isLoading : function(){
31622 return this.loading;
31625 loadComplete : function(deep, anim, callback){
31626 this.loading = false;
31627 this.loaded = true;
31628 this.ui.afterLoad(this);
31629 this.fireEvent("load", this);
31630 this.expand(deep, anim, callback);
31634 * Returns true if this node has been loaded
31635 * @return {Boolean}
31637 isLoaded : function(){
31638 return this.loaded;
31641 hasChildNodes : function(){
31642 if(!this.isLeaf() && !this.loaded){
31645 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
31650 * Trigger a reload for this node
31651 * @param {Function} callback
31653 reload : function(callback){
31654 this.collapse(false, false);
31655 while(this.firstChild){
31656 this.removeChild(this.firstChild);
31658 this.childrenRendered = false;
31659 this.loaded = false;
31660 if(this.isHiddenRoot()){
31661 this.expanded = false;
31663 this.expand(false, false, callback);
31667 * Ext JS Library 1.1.1
31668 * Copyright(c) 2006-2007, Ext JS, LLC.
31670 * Originally Released Under LGPL - original licence link has changed is not relivant.
31673 * <script type="text/javascript">
31677 * @class Roo.tree.TreeNodeUI
31679 * @param {Object} node The node to render
31680 * The TreeNode UI implementation is separate from the
31681 * tree implementation. Unless you are customizing the tree UI,
31682 * you should never have to use this directly.
31684 Roo.tree.TreeNodeUI = function(node){
31686 this.rendered = false;
31687 this.animating = false;
31688 this.emptyIcon = Roo.BLANK_IMAGE_URL;
31691 Roo.tree.TreeNodeUI.prototype = {
31692 removeChild : function(node){
31694 this.ctNode.removeChild(node.ui.getEl());
31698 beforeLoad : function(){
31699 this.addClass("x-tree-node-loading");
31702 afterLoad : function(){
31703 this.removeClass("x-tree-node-loading");
31706 onTextChange : function(node, text, oldText){
31708 this.textNode.innerHTML = text;
31712 onDisableChange : function(node, state){
31713 this.disabled = state;
31715 this.addClass("x-tree-node-disabled");
31717 this.removeClass("x-tree-node-disabled");
31721 onSelectedChange : function(state){
31724 this.addClass("x-tree-selected");
31727 this.removeClass("x-tree-selected");
31731 onMove : function(tree, node, oldParent, newParent, index, refNode){
31732 this.childIndent = null;
31734 var targetNode = newParent.ui.getContainer();
31735 if(!targetNode){//target not rendered
31736 this.holder = document.createElement("div");
31737 this.holder.appendChild(this.wrap);
31740 var insertBefore = refNode ? refNode.ui.getEl() : null;
31742 targetNode.insertBefore(this.wrap, insertBefore);
31744 targetNode.appendChild(this.wrap);
31746 this.node.renderIndent(true);
31750 addClass : function(cls){
31752 Roo.fly(this.elNode).addClass(cls);
31756 removeClass : function(cls){
31758 Roo.fly(this.elNode).removeClass(cls);
31762 remove : function(){
31764 this.holder = document.createElement("div");
31765 this.holder.appendChild(this.wrap);
31769 fireEvent : function(){
31770 return this.node.fireEvent.apply(this.node, arguments);
31773 initEvents : function(){
31774 this.node.on("move", this.onMove, this);
31775 var E = Roo.EventManager;
31776 var a = this.anchor;
31778 var el = Roo.fly(a, '_treeui');
31780 if(Roo.isOpera){ // opera render bug ignores the CSS
31781 el.setStyle("text-decoration", "none");
31784 el.on("click", this.onClick, this);
31785 el.on("dblclick", this.onDblClick, this);
31788 Roo.EventManager.on(this.checkbox,
31789 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
31792 el.on("contextmenu", this.onContextMenu, this);
31794 var icon = Roo.fly(this.iconNode);
31795 icon.on("click", this.onClick, this);
31796 icon.on("dblclick", this.onDblClick, this);
31797 icon.on("contextmenu", this.onContextMenu, this);
31798 E.on(this.ecNode, "click", this.ecClick, this, true);
31800 if(this.node.disabled){
31801 this.addClass("x-tree-node-disabled");
31803 if(this.node.hidden){
31804 this.addClass("x-tree-node-disabled");
31806 var ot = this.node.getOwnerTree();
31807 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
31808 if(dd && (!this.node.isRoot || ot.rootVisible)){
31809 Roo.dd.Registry.register(this.elNode, {
31811 handles: this.getDDHandles(),
31817 getDDHandles : function(){
31818 return [this.iconNode, this.textNode];
31823 this.wrap.style.display = "none";
31829 this.wrap.style.display = "";
31833 onContextMenu : function(e){
31834 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
31835 e.preventDefault();
31837 this.fireEvent("contextmenu", this.node, e);
31841 onClick : function(e){
31846 if(this.fireEvent("beforeclick", this.node, e) !== false){
31847 if(!this.disabled && this.node.attributes.href){
31848 this.fireEvent("click", this.node, e);
31851 e.preventDefault();
31856 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
31857 this.node.toggle();
31860 this.fireEvent("click", this.node, e);
31866 onDblClick : function(e){
31867 e.preventDefault();
31872 this.toggleCheck();
31874 if(!this.animating && this.node.hasChildNodes()){
31875 this.node.toggle();
31877 this.fireEvent("dblclick", this.node, e);
31880 onCheckChange : function(){
31881 var checked = this.checkbox.checked;
31882 this.node.attributes.checked = checked;
31883 this.fireEvent('checkchange', this.node, checked);
31886 ecClick : function(e){
31887 if(!this.animating && this.node.hasChildNodes()){
31888 this.node.toggle();
31892 startDrop : function(){
31893 this.dropping = true;
31896 // delayed drop so the click event doesn't get fired on a drop
31897 endDrop : function(){
31898 setTimeout(function(){
31899 this.dropping = false;
31900 }.createDelegate(this), 50);
31903 expand : function(){
31904 this.updateExpandIcon();
31905 this.ctNode.style.display = "";
31908 focus : function(){
31909 if(!this.node.preventHScroll){
31910 try{this.anchor.focus();
31912 }else if(!Roo.isIE){
31914 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
31915 var l = noscroll.scrollLeft;
31916 this.anchor.focus();
31917 noscroll.scrollLeft = l;
31922 toggleCheck : function(value){
31923 var cb = this.checkbox;
31925 cb.checked = (value === undefined ? !cb.checked : value);
31931 this.anchor.blur();
31935 animExpand : function(callback){
31936 var ct = Roo.get(this.ctNode);
31938 if(!this.node.hasChildNodes()){
31939 this.updateExpandIcon();
31940 this.ctNode.style.display = "";
31941 Roo.callback(callback);
31944 this.animating = true;
31945 this.updateExpandIcon();
31948 callback : function(){
31949 this.animating = false;
31950 Roo.callback(callback);
31953 duration: this.node.ownerTree.duration || .25
31957 highlight : function(){
31958 var tree = this.node.getOwnerTree();
31959 Roo.fly(this.wrap).highlight(
31960 tree.hlColor || "C3DAF9",
31961 {endColor: tree.hlBaseColor}
31965 collapse : function(){
31966 this.updateExpandIcon();
31967 this.ctNode.style.display = "none";
31970 animCollapse : function(callback){
31971 var ct = Roo.get(this.ctNode);
31972 ct.enableDisplayMode('block');
31975 this.animating = true;
31976 this.updateExpandIcon();
31979 callback : function(){
31980 this.animating = false;
31981 Roo.callback(callback);
31984 duration: this.node.ownerTree.duration || .25
31988 getContainer : function(){
31989 return this.ctNode;
31992 getEl : function(){
31996 appendDDGhost : function(ghostNode){
31997 ghostNode.appendChild(this.elNode.cloneNode(true));
32000 getDDRepairXY : function(){
32001 return Roo.lib.Dom.getXY(this.iconNode);
32004 onRender : function(){
32008 render : function(bulkRender){
32009 var n = this.node, a = n.attributes;
32010 var targetNode = n.parentNode ?
32011 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32013 if(!this.rendered){
32014 this.rendered = true;
32016 this.renderElements(n, a, targetNode, bulkRender);
32019 if(this.textNode.setAttributeNS){
32020 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32022 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32025 this.textNode.setAttribute("ext:qtip", a.qtip);
32027 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32030 }else if(a.qtipCfg){
32031 a.qtipCfg.target = Roo.id(this.textNode);
32032 Roo.QuickTips.register(a.qtipCfg);
32035 if(!this.node.expanded){
32036 this.updateExpandIcon();
32039 if(bulkRender === true) {
32040 targetNode.appendChild(this.wrap);
32045 renderElements : function(n, a, targetNode, bulkRender){
32046 // add some indent caching, this helps performance when rendering a large tree
32047 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32048 var t = n.getOwnerTree();
32049 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32050 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32051 var cb = typeof a.checked == 'boolean';
32052 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32053 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32054 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32055 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32056 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32057 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32058 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32059 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32060 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32061 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32064 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32065 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32066 n.nextSibling.ui.getEl(), buf.join(""));
32068 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32071 this.elNode = this.wrap.childNodes[0];
32072 this.ctNode = this.wrap.childNodes[1];
32073 var cs = this.elNode.childNodes;
32074 this.indentNode = cs[0];
32075 this.ecNode = cs[1];
32076 this.iconNode = cs[2];
32079 this.checkbox = cs[3];
32082 this.anchor = cs[index];
32083 this.textNode = cs[index].firstChild;
32086 getAnchor : function(){
32087 return this.anchor;
32090 getTextEl : function(){
32091 return this.textNode;
32094 getIconEl : function(){
32095 return this.iconNode;
32098 isChecked : function(){
32099 return this.checkbox ? this.checkbox.checked : false;
32102 updateExpandIcon : function(){
32104 var n = this.node, c1, c2;
32105 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32106 var hasChild = n.hasChildNodes();
32110 c1 = "x-tree-node-collapsed";
32111 c2 = "x-tree-node-expanded";
32114 c1 = "x-tree-node-expanded";
32115 c2 = "x-tree-node-collapsed";
32118 this.removeClass("x-tree-node-leaf");
32119 this.wasLeaf = false;
32121 if(this.c1 != c1 || this.c2 != c2){
32122 Roo.fly(this.elNode).replaceClass(c1, c2);
32123 this.c1 = c1; this.c2 = c2;
32127 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32130 this.wasLeaf = true;
32133 var ecc = "x-tree-ec-icon "+cls;
32134 if(this.ecc != ecc){
32135 this.ecNode.className = ecc;
32141 getChildIndent : function(){
32142 if(!this.childIndent){
32146 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32148 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32150 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32155 this.childIndent = buf.join("");
32157 return this.childIndent;
32160 renderIndent : function(){
32163 var p = this.node.parentNode;
32165 indent = p.ui.getChildIndent();
32167 if(this.indentMarkup != indent){ // don't rerender if not required
32168 this.indentNode.innerHTML = indent;
32169 this.indentMarkup = indent;
32171 this.updateExpandIcon();
32176 Roo.tree.RootTreeNodeUI = function(){
32177 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32179 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32180 render : function(){
32181 if(!this.rendered){
32182 var targetNode = this.node.ownerTree.innerCt.dom;
32183 this.node.expanded = true;
32184 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32185 this.wrap = this.ctNode = targetNode.firstChild;
32188 collapse : function(){
32190 expand : function(){
32194 * Ext JS Library 1.1.1
32195 * Copyright(c) 2006-2007, Ext JS, LLC.
32197 * Originally Released Under LGPL - original licence link has changed is not relivant.
32200 * <script type="text/javascript">
32203 * @class Roo.tree.TreeLoader
32204 * @extends Roo.util.Observable
32205 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32206 * nodes from a specified URL. The response must be a javascript Array definition
32207 * who's elements are node definition objects. eg:
32209 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32210 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32213 * A server request is sent, and child nodes are loaded only when a node is expanded.
32214 * The loading node's id is passed to the server under the parameter name "node" to
32215 * enable the server to produce the correct child nodes.
32217 * To pass extra parameters, an event handler may be attached to the "beforeload"
32218 * event, and the parameters specified in the TreeLoader's baseParams property:
32220 myTreeLoader.on("beforeload", function(treeLoader, node) {
32221 this.baseParams.category = node.attributes.category;
32224 * This would pass an HTTP parameter called "category" to the server containing
32225 * the value of the Node's "category" attribute.
32227 * Creates a new Treeloader.
32228 * @param {Object} config A config object containing config properties.
32230 Roo.tree.TreeLoader = function(config){
32231 this.baseParams = {};
32232 this.requestMethod = "POST";
32233 Roo.apply(this, config);
32237 * @event beforeload
32238 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32239 * @param {Object} This TreeLoader object.
32240 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32241 * @param {Object} callback The callback function specified in the {@link #load} call.
32243 "beforeload" : true,
32246 * Fires when the node has been successfuly loaded.
32247 * @param {Object} This TreeLoader object.
32248 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32249 * @param {Object} response The response object containing the data from the server.
32253 * @event loadexception
32254 * Fires if the network request failed.
32255 * @param {Object} This TreeLoader object.
32256 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32257 * @param {Object} response The response object containing the data from the server.
32259 "loadexception" : true,
32262 * Fires before a node is created, enabling you to return custom Node types
32263 * @param {Object} This TreeLoader object.
32264 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32269 Roo.tree.TreeLoader.superclass.constructor.call(this);
32272 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32274 * @cfg {String} dataUrl The URL from which to request a Json string which
32275 * specifies an array of node definition object representing the child nodes
32279 * @cfg {Object} baseParams (optional) An object containing properties which
32280 * specify HTTP parameters to be passed to each request for child nodes.
32283 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32284 * created by this loader. If the attributes sent by the server have an attribute in this object,
32285 * they take priority.
32288 * @cfg {Object} uiProviders (optional) An object containing properties which
32290 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32291 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32292 * <i>uiProvider</i> attribute of a returned child node is a string rather
32293 * than a reference to a TreeNodeUI implementation, this that string value
32294 * is used as a property name in the uiProviders object. You can define the provider named
32295 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32300 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32301 * child nodes before loading.
32303 clearOnLoad : true,
32306 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32307 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32308 * Grid query { data : [ .....] }
32313 * @cfg {String} queryParam (optional)
32314 * Name of the query as it will be passed on the querystring (defaults to 'node')
32315 * eg. the request will be ?node=[id]
32322 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32323 * This is called automatically when a node is expanded, but may be used to reload
32324 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32325 * @param {Roo.tree.TreeNode} node
32326 * @param {Function} callback
32328 load : function(node, callback){
32329 if(this.clearOnLoad){
32330 while(node.firstChild){
32331 node.removeChild(node.firstChild);
32334 if(node.attributes.children){ // preloaded json children
32335 var cs = node.attributes.children;
32336 for(var i = 0, len = cs.length; i < len; i++){
32337 node.appendChild(this.createNode(cs[i]));
32339 if(typeof callback == "function"){
32342 }else if(this.dataUrl){
32343 this.requestData(node, callback);
32347 getParams: function(node){
32348 var buf = [], bp = this.baseParams;
32349 for(var key in bp){
32350 if(typeof bp[key] != "function"){
32351 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32354 var n = this.queryParam === false ? 'node' : this.queryParam;
32355 buf.push(n + "=", encodeURIComponent(node.id));
32356 return buf.join("");
32359 requestData : function(node, callback){
32360 if(this.fireEvent("beforeload", this, node, callback) !== false){
32361 this.transId = Roo.Ajax.request({
32362 method:this.requestMethod,
32363 url: this.dataUrl||this.url,
32364 success: this.handleResponse,
32365 failure: this.handleFailure,
32367 argument: {callback: callback, node: node},
32368 params: this.getParams(node)
32371 // if the load is cancelled, make sure we notify
32372 // the node that we are done
32373 if(typeof callback == "function"){
32379 isLoading : function(){
32380 return this.transId ? true : false;
32383 abort : function(){
32384 if(this.isLoading()){
32385 Roo.Ajax.abort(this.transId);
32390 * Override this function for custom TreeNode node implementation
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 findRecord : function(prop, value){
37166 if(this.store.getCount() > 0){
37167 this.store.each(function(r){
37168 if(r.data[prop] == value){
37178 onViewMove : function(e, t){
37179 this.inKeyMode = false;
37183 onViewOver : function(e, t){
37184 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37187 var item = this.view.findItemFromChild(t);
37189 var index = this.view.indexOf(item);
37190 this.select(index, false);
37195 onViewClick : function(doFocus){
37196 var index = this.view.getSelectedIndexes()[0];
37197 var r = this.store.getAt(index);
37199 this.onSelect(r, index);
37201 if(doFocus !== false && !this.blockFocus){
37207 restrictHeight : function(){
37208 this.innerList.dom.style.height = '';
37209 var inner = this.innerList.dom;
37210 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37211 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37212 this.list.beginUpdate();
37213 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37214 this.list.alignTo(this.el, this.listAlign);
37215 this.list.endUpdate();
37219 onEmptyResults : function(){
37224 * Returns true if the dropdown list is expanded, else false.
37226 isExpanded : function(){
37227 return this.list.isVisible();
37231 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37232 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37233 * @param {String} value The data value of the item to select
37234 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37235 * selected item if it is not currently in view (defaults to true)
37236 * @return {Boolean} True if the value matched an item in the list, else false
37238 selectByValue : function(v, scrollIntoView){
37239 if(v !== undefined && v !== null){
37240 var r = this.findRecord(this.valueField || this.displayField, v);
37242 this.select(this.store.indexOf(r), scrollIntoView);
37250 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37251 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37252 * @param {Number} index The zero-based index of the list item to select
37253 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37254 * selected item if it is not currently in view (defaults to true)
37256 select : function(index, scrollIntoView){
37257 this.selectedIndex = index;
37258 this.view.select(index);
37259 if(scrollIntoView !== false){
37260 var el = this.view.getNode(index);
37262 this.innerList.scrollChildIntoView(el, false);
37268 selectNext : function(){
37269 var ct = this.store.getCount();
37271 if(this.selectedIndex == -1){
37273 }else if(this.selectedIndex < ct-1){
37274 this.select(this.selectedIndex+1);
37280 selectPrev : function(){
37281 var ct = this.store.getCount();
37283 if(this.selectedIndex == -1){
37285 }else if(this.selectedIndex != 0){
37286 this.select(this.selectedIndex-1);
37292 onKeyUp : function(e){
37293 if(this.editable !== false && !e.isSpecialKey()){
37294 this.lastKey = e.getKey();
37295 this.dqTask.delay(this.queryDelay);
37300 validateBlur : function(){
37301 return !this.list || !this.list.isVisible();
37305 initQuery : function(){
37306 this.doQuery(this.getRawValue());
37310 doForce : function(){
37311 if(this.el.dom.value.length > 0){
37312 this.el.dom.value =
37313 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37314 this.applyEmptyText();
37319 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37320 * query allowing the query action to be canceled if needed.
37321 * @param {String} query The SQL query to execute
37322 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37323 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37324 * saved in the current store (defaults to false)
37326 doQuery : function(q, forceAll){
37327 if(q === undefined || q === null){
37332 forceAll: forceAll,
37336 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37340 forceAll = qe.forceAll;
37341 if(forceAll === true || (q.length >= this.minChars)){
37342 if(this.lastQuery != q){
37343 this.lastQuery = q;
37344 if(this.mode == 'local'){
37345 this.selectedIndex = -1;
37347 this.store.clearFilter();
37349 this.store.filter(this.displayField, q);
37353 this.store.baseParams[this.queryParam] = q;
37355 params: this.getParams(q)
37360 this.selectedIndex = -1;
37367 getParams : function(q){
37369 //p[this.queryParam] = q;
37372 p.limit = this.pageSize;
37378 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37380 collapse : function(){
37381 if(!this.isExpanded()){
37385 Roo.get(document).un('mousedown', this.collapseIf, this);
37386 Roo.get(document).un('mousewheel', this.collapseIf, this);
37387 this.fireEvent('collapse', this);
37391 collapseIf : function(e){
37392 if(!e.within(this.wrap) && !e.within(this.list)){
37398 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37400 expand : function(){
37401 if(this.isExpanded() || !this.hasFocus){
37404 this.list.alignTo(this.el, this.listAlign);
37406 Roo.get(document).on('mousedown', this.collapseIf, this);
37407 Roo.get(document).on('mousewheel', this.collapseIf, this);
37408 this.fireEvent('expand', this);
37412 // Implements the default empty TriggerField.onTriggerClick function
37413 onTriggerClick : function(){
37417 if(this.isExpanded()){
37419 if (!this.blockFocus) {
37424 this.hasFocus = true;
37425 if(this.triggerAction == 'all') {
37426 this.doQuery(this.allQuery, true);
37428 this.doQuery(this.getRawValue());
37430 if (!this.blockFocus) {
37437 * @cfg {Boolean} grow
37441 * @cfg {Number} growMin
37445 * @cfg {Number} growMax
37454 * Ext JS Library 1.1.1
37455 * Copyright(c) 2006-2007, Ext JS, LLC.
37457 * Originally Released Under LGPL - original licence link has changed is not relivant.
37460 * <script type="text/javascript">
37463 * @class Roo.form.Checkbox
37464 * @extends Roo.form.Field
37465 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
37467 * Creates a new Checkbox
37468 * @param {Object} config Configuration options
37470 Roo.form.Checkbox = function(config){
37471 Roo.form.Checkbox.superclass.constructor.call(this, config);
37475 * Fires when the checkbox is checked or unchecked.
37476 * @param {Roo.form.Checkbox} this This checkbox
37477 * @param {Boolean} checked The new checked value
37483 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
37485 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
37487 focusClass : undefined,
37489 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
37491 fieldClass: "x-form-field",
37493 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
37497 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37498 * {tag: "input", type: "checkbox", autocomplete: "off"})
37500 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
37502 * @cfg {String} boxLabel The text that appears beside the checkbox
37506 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
37510 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
37512 valueOff: '0', // value when not checked..
37514 actionMode : 'viewEl',
37517 itemCls : 'x-menu-check-item x-form-item',
37518 groupClass : 'x-menu-group-item',
37519 inputType : 'hidden',
37522 inSetChecked: false, // check that we are not calling self...
37524 inputElement: false, // real input element?
37525 basedOn: false, // ????
37527 isFormField: true, // not sure where this is needed!!!!
37529 onResize : function(){
37530 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
37531 if(!this.boxLabel){
37532 this.el.alignTo(this.wrap, 'c-c');
37536 initEvents : function(){
37537 Roo.form.Checkbox.superclass.initEvents.call(this);
37538 this.el.on("click", this.onClick, this);
37539 this.el.on("change", this.onClick, this);
37543 getResizeEl : function(){
37547 getPositionEl : function(){
37552 onRender : function(ct, position){
37553 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
37555 if(this.inputValue !== undefined){
37556 this.el.dom.value = this.inputValue;
37559 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
37560 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
37561 var viewEl = this.wrap.createChild({
37562 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
37563 this.viewEl = viewEl;
37564 this.wrap.on('click', this.onClick, this);
37566 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
37567 this.el.on('propertychange', this.setFromHidden, this); //ie
37572 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
37573 // viewEl.on('click', this.onClick, this);
37575 //if(this.checked){
37576 this.setChecked(this.checked);
37578 //this.checked = this.el.dom;
37584 initValue : Roo.emptyFn,
37587 * Returns the checked state of the checkbox.
37588 * @return {Boolean} True if checked, else false
37590 getValue : function(){
37592 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
37594 return this.valueOff;
37599 onClick : function(){
37600 this.setChecked(!this.checked);
37602 //if(this.el.dom.checked != this.checked){
37603 // this.setValue(this.el.dom.checked);
37608 * Sets the checked state of the checkbox.
37609 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
37611 setValue : function(v,suppressEvent){
37612 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
37613 //if(this.el && this.el.dom){
37614 // this.el.dom.checked = this.checked;
37615 // this.el.dom.defaultChecked = this.checked;
37617 this.setChecked(v === this.inputValue);
37618 //this.fireEvent("check", this, this.checked);
37621 setChecked : function(state,suppressEvent)
37623 if (this.inSetChecked) {
37624 this.checked = state;
37630 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
37632 this.checked = state;
37633 if(suppressEvent !== true){
37634 this.fireEvent('checkchange', this, state);
37636 this.inSetChecked = true;
37637 this.el.dom.value = state ? this.inputValue : this.valueOff;
37638 this.inSetChecked = false;
37641 // handle setting of hidden value by some other method!!?!?
37642 setFromHidden: function()
37647 //console.log("SET FROM HIDDEN");
37648 //alert('setFrom hidden');
37649 this.setValue(this.el.dom.value);
37652 onDestroy : function()
37655 Roo.get(this.viewEl).remove();
37658 Roo.form.Checkbox.superclass.onDestroy.call(this);
37663 * Ext JS Library 1.1.1
37664 * Copyright(c) 2006-2007, Ext JS, LLC.
37666 * Originally Released Under LGPL - original licence link has changed is not relivant.
37669 * <script type="text/javascript">
37673 * @class Roo.form.Radio
37674 * @extends Roo.form.Checkbox
37675 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
37676 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
37678 * Creates a new Radio
37679 * @param {Object} config Configuration options
37681 Roo.form.Radio = function(){
37682 Roo.form.Radio.superclass.constructor.apply(this, arguments);
37684 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
37685 inputType: 'radio',
37688 * If this radio is part of a group, it will return the selected value
37691 getGroupValue : function(){
37692 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
37694 });//<script type="text/javascript">
37697 * Ext JS Library 1.1.1
37698 * Copyright(c) 2006-2007, Ext JS, LLC.
37699 * licensing@extjs.com
37701 * http://www.extjs.com/license
37707 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
37708 * - IE ? - no idea how much works there.
37716 * @class Ext.form.HtmlEditor
37717 * @extends Ext.form.Field
37718 * Provides a lightweight HTML Editor component.
37719 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
37721 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
37722 * supported by this editor.</b><br/><br/>
37723 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
37724 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
37726 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
37728 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
37732 * @cfg {String} createLinkText The default text for the create link prompt
37734 createLinkText : 'Please enter the URL for the link:',
37736 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
37738 defaultLinkValue : 'http:/'+'/',
37744 // private properties
37745 validationEvent : false,
37747 initialized : false,
37749 sourceEditMode : false,
37750 onFocus : Roo.emptyFn,
37752 hideMode:'offsets',
37753 defaultAutoCreate : {
37755 style:"width:500px;height:300px;",
37756 autocomplete: "off"
37760 initComponent : function(){
37763 * @event initialize
37764 * Fires when the editor is fully initialized (including the iframe)
37765 * @param {HtmlEditor} this
37770 * Fires when the editor is first receives the focus. Any insertion must wait
37771 * until after this event.
37772 * @param {HtmlEditor} this
37776 * @event beforesync
37777 * Fires before the textarea is updated with content from the editor iframe. Return false
37778 * to cancel the sync.
37779 * @param {HtmlEditor} this
37780 * @param {String} html
37784 * @event beforepush
37785 * Fires before the iframe editor is updated with content from the textarea. Return false
37786 * to cancel the push.
37787 * @param {HtmlEditor} this
37788 * @param {String} html
37793 * Fires when the textarea is updated with content from the editor iframe.
37794 * @param {HtmlEditor} this
37795 * @param {String} html
37800 * Fires when the iframe editor is updated with content from the textarea.
37801 * @param {HtmlEditor} this
37802 * @param {String} html
37806 * @event editmodechange
37807 * Fires when the editor switches edit modes
37808 * @param {HtmlEditor} this
37809 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
37811 editmodechange: true,
37813 * @event editorevent
37814 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
37815 * @param {HtmlEditor} this
37822 * Protected method that will not generally be called directly. It
37823 * is called when the editor creates its toolbar. Override this method if you need to
37824 * add custom toolbar buttons.
37825 * @param {HtmlEditor} editor
37827 createToolbar : function(editor){
37828 if (!editor.toolbars || !editor.toolbars.length) {
37829 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
37832 for (var i =0 ; i < editor.toolbars.length;i++) {
37833 editor.toolbars[i].init(editor);
37840 * Protected method that will not generally be called directly. It
37841 * is called when the editor initializes the iframe with HTML contents. Override this method if you
37842 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
37844 getDocMarkup : function(){
37845 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
37849 onRender : function(ct, position){
37850 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
37851 this.el.dom.style.border = '0 none';
37852 this.el.dom.setAttribute('tabIndex', -1);
37853 this.el.addClass('x-hidden');
37854 if(Roo.isIE){ // fix IE 1px bogus margin
37855 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
37857 this.wrap = this.el.wrap({
37858 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
37861 this.frameId = Roo.id();
37862 this.createToolbar(this);
37869 var iframe = this.wrap.createChild({
37872 name: this.frameId,
37873 frameBorder : 'no',
37874 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
37877 // console.log(iframe);
37878 //this.wrap.dom.appendChild(iframe);
37880 this.iframe = iframe.dom;
37882 this.assignDocWin();
37884 this.doc.designMode = 'on';
37887 this.doc.write(this.getDocMarkup());
37891 var task = { // must defer to wait for browser to be ready
37893 //console.log("run task?" + this.doc.readyState);
37894 this.assignDocWin();
37895 if(this.doc.body || this.doc.readyState == 'complete'){
37899 this.doc.designMode="on";
37903 Roo.TaskMgr.stop(task);
37904 this.initEditor.defer(10, this);
37911 Roo.TaskMgr.start(task);
37914 this.setSize(this.el.getSize());
37919 onResize : function(w, h){
37920 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
37921 if(this.el && this.iframe){
37922 if(typeof w == 'number'){
37923 var aw = w - this.wrap.getFrameWidth('lr');
37924 this.el.setWidth(this.adjustWidth('textarea', aw));
37925 this.iframe.style.width = aw + 'px';
37927 if(typeof h == 'number'){
37929 for (var i =0; i < this.toolbars.length;i++) {
37930 // fixme - ask toolbars for heights?
37931 tbh += this.toolbars[i].tb.el.getHeight();
37937 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
37938 this.el.setHeight(this.adjustWidth('textarea', ah));
37939 this.iframe.style.height = ah + 'px';
37941 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
37948 * Toggles the editor between standard and source edit mode.
37949 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
37951 toggleSourceEdit : function(sourceEditMode){
37953 this.sourceEditMode = sourceEditMode === true;
37955 if(this.sourceEditMode){
37958 this.iframe.className = 'x-hidden';
37959 this.el.removeClass('x-hidden');
37960 this.el.dom.removeAttribute('tabIndex');
37965 this.iframe.className = '';
37966 this.el.addClass('x-hidden');
37967 this.el.dom.setAttribute('tabIndex', -1);
37970 this.setSize(this.wrap.getSize());
37971 this.fireEvent('editmodechange', this, this.sourceEditMode);
37974 // private used internally
37975 createLink : function(){
37976 var url = prompt(this.createLinkText, this.defaultLinkValue);
37977 if(url && url != 'http:/'+'/'){
37978 this.relayCmd('createlink', url);
37982 // private (for BoxComponent)
37983 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37985 // private (for BoxComponent)
37986 getResizeEl : function(){
37990 // private (for BoxComponent)
37991 getPositionEl : function(){
37996 initEvents : function(){
37997 this.originalValue = this.getValue();
38001 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38004 markInvalid : Roo.emptyFn,
38006 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38009 clearInvalid : Roo.emptyFn,
38011 setValue : function(v){
38012 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38017 * Protected method that will not generally be called directly. If you need/want
38018 * custom HTML cleanup, this is the method you should override.
38019 * @param {String} html The HTML to be cleaned
38020 * return {String} The cleaned HTML
38022 cleanHtml : function(html){
38023 html = String(html);
38024 if(html.length > 5){
38025 if(Roo.isSafari){ // strip safari nonsense
38026 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38029 if(html == ' '){
38036 * Protected method that will not generally be called directly. Syncs the contents
38037 * of the editor iframe with the textarea.
38039 syncValue : function(){
38040 if(this.initialized){
38041 var bd = (this.doc.body || this.doc.documentElement);
38042 var html = bd.innerHTML;
38044 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38045 var m = bs.match(/text-align:(.*?);/i);
38047 html = '<div style="'+m[0]+'">' + html + '</div>';
38050 html = this.cleanHtml(html);
38051 if(this.fireEvent('beforesync', this, html) !== false){
38052 this.el.dom.value = html;
38053 this.fireEvent('sync', this, html);
38059 * Protected method that will not generally be called directly. Pushes the value of the textarea
38060 * into the iframe editor.
38062 pushValue : function(){
38063 if(this.initialized){
38064 var v = this.el.dom.value;
38068 if(this.fireEvent('beforepush', this, v) !== false){
38069 (this.doc.body || this.doc.documentElement).innerHTML = v;
38070 this.fireEvent('push', this, v);
38076 deferFocus : function(){
38077 this.focus.defer(10, this);
38081 focus : function(){
38082 if(this.win && !this.sourceEditMode){
38089 assignDocWin: function()
38091 var iframe = this.iframe;
38094 this.doc = iframe.contentWindow.document;
38095 this.win = iframe.contentWindow;
38097 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38098 this.win = Roo.get(this.frameId).dom.contentWindow;
38103 initEditor : function(){
38104 //console.log("INIT EDITOR");
38105 this.assignDocWin();
38109 this.doc.designMode="on";
38111 this.doc.write(this.getDocMarkup());
38114 var dbody = (this.doc.body || this.doc.documentElement);
38115 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38116 // this copies styles from the containing element into thsi one..
38117 // not sure why we need all of this..
38118 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38119 ss['background-attachment'] = 'fixed'; // w3c
38120 dbody.bgProperties = 'fixed'; // ie
38121 Roo.DomHelper.applyStyles(dbody, ss);
38122 Roo.EventManager.on(this.doc, {
38123 'mousedown': this.onEditorEvent,
38124 'dblclick': this.onEditorEvent,
38125 'click': this.onEditorEvent,
38126 'keyup': this.onEditorEvent,
38131 Roo.EventManager.on(this.doc, 'keypress', this.applyCommand, this);
38133 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38134 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38136 this.initialized = true;
38138 this.fireEvent('initialize', this);
38143 onDestroy : function(){
38149 for (var i =0; i < this.toolbars.length;i++) {
38150 // fixme - ask toolbars for heights?
38151 this.toolbars[i].onDestroy();
38154 this.wrap.dom.innerHTML = '';
38155 this.wrap.remove();
38160 onFirstFocus : function(){
38162 this.assignDocWin();
38165 this.activated = true;
38166 for (var i =0; i < this.toolbars.length;i++) {
38167 this.toolbars[i].onFirstFocus();
38170 if(Roo.isGecko){ // prevent silly gecko errors
38172 var s = this.win.getSelection();
38173 if(!s.focusNode || s.focusNode.nodeType != 3){
38174 var r = s.getRangeAt(0);
38175 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38180 this.execCmd('useCSS', true);
38181 this.execCmd('styleWithCSS', false);
38184 this.fireEvent('activate', this);
38188 adjustFont: function(btn){
38189 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38190 //if(Roo.isSafari){ // safari
38193 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38194 if(Roo.isSafari){ // safari
38195 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38196 v = (v < 10) ? 10 : v;
38197 v = (v > 48) ? 48 : v;
38198 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38203 v = Math.max(1, v+adjust);
38205 this.execCmd('FontSize', v );
38208 onEditorEvent : function(e){
38209 this.fireEvent('editorevent', this, e);
38210 // this.updateToolbar();
38214 insertTag : function(tg)
38216 // could be a bit smarter... -> wrap the current selected tRoo..
38218 this.execCmd("formatblock", tg);
38222 insertText : function(txt)
38226 range = this.createRange();
38227 range.deleteContents();
38228 //alert(Sender.getAttribute('label'));
38230 range.insertNode(this.doc.createTextNode(txt));
38234 relayBtnCmd : function(btn){
38235 this.relayCmd(btn.cmd);
38239 * Executes a Midas editor command on the editor document and performs necessary focus and
38240 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38241 * @param {String} cmd The Midas command
38242 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38244 relayCmd : function(cmd, value){
38246 this.execCmd(cmd, value);
38247 this.fireEvent('editorevent', this);
38248 //this.updateToolbar();
38253 * Executes a Midas editor command directly on the editor document.
38254 * For visual commands, you should use {@link #relayCmd} instead.
38255 * <b>This should only be called after the editor is initialized.</b>
38256 * @param {String} cmd The Midas command
38257 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38259 execCmd : function(cmd, value){
38260 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38265 applyCommand : function(e){
38267 var c = e.getCharCode(), cmd;
38269 c = String.fromCharCode(c);
38285 e.preventDefault();
38292 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38294 * @param {String} text
38296 insertAtCursor : function(text){
38297 if(!this.activated){
38302 var r = this.doc.selection.createRange();
38309 }else if(Roo.isGecko || Roo.isOpera){
38311 this.execCmd('InsertHTML', text);
38313 }else if(Roo.isSafari){
38314 this.execCmd('InsertText', text);
38320 fixKeys : function(){ // load time branching for fastest keydown performance
38322 return function(e){
38323 var k = e.getKey(), r;
38326 r = this.doc.selection.createRange();
38329 r.pasteHTML('    ');
38332 }else if(k == e.ENTER){
38333 r = this.doc.selection.createRange();
38335 var target = r.parentElement();
38336 if(!target || target.tagName.toLowerCase() != 'li'){
38338 r.pasteHTML('<br />');
38345 }else if(Roo.isOpera){
38346 return function(e){
38347 var k = e.getKey();
38351 this.execCmd('InsertHTML','    ');
38355 }else if(Roo.isSafari){
38356 return function(e){
38357 var k = e.getKey();
38360 this.execCmd('InsertText','\t');
38367 getAllAncestors: function()
38369 var p = this.getSelectedNode();
38372 a.push(p); // push blank onto stack..
38373 p = this.getParentElement();
38377 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38381 a.push(this.doc.body);
38385 lastSelNode : false,
38388 getSelection : function()
38390 this.assignDocWin();
38391 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38394 getSelectedNode: function()
38396 // this may only work on Gecko!!!
38398 // should we cache this!!!!
38403 var range = this.createRange(this.getSelection());
38406 var parent = range.parentElement();
38408 var testRange = range.duplicate();
38409 testRange.moveToElementText(parent);
38410 if (testRange.inRange(range)) {
38413 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
38416 parent = parent.parentElement;
38422 var ar = range.endContainer.childNodes;
38424 ar = range.commonAncestorContainer.childNodes;
38425 //alert(ar.length);
38428 var other_nodes = [];
38429 var has_other_nodes = false;
38430 for (var i=0;i<ar.length;i++) {
38431 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
38434 // fullly contained node.
38436 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
38441 // probably selected..
38442 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
38443 other_nodes.push(ar[i]);
38446 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
38451 has_other_nodes = true;
38453 if (!nodes.length && other_nodes.length) {
38454 nodes= other_nodes;
38456 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
38462 createRange: function(sel)
38464 // this has strange effects when using with
38465 // top toolbar - not sure if it's a great idea.
38466 //this.editor.contentWindow.focus();
38467 if (typeof sel != "undefined") {
38469 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
38471 return this.doc.createRange();
38474 return this.doc.createRange();
38477 getParentElement: function()
38480 this.assignDocWin();
38481 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
38483 var range = this.createRange(sel);
38486 var p = range.commonAncestorContainer;
38487 while (p.nodeType == 3) { // text node
38499 // BC Hacks - cause I cant work out what i was trying to do..
38500 rangeIntersectsNode : function(range, node)
38502 var nodeRange = node.ownerDocument.createRange();
38504 nodeRange.selectNode(node);
38507 nodeRange.selectNodeContents(node);
38510 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
38511 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
38513 rangeCompareNode : function(range, node) {
38514 var nodeRange = node.ownerDocument.createRange();
38516 nodeRange.selectNode(node);
38518 nodeRange.selectNodeContents(node);
38520 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
38521 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
38523 if (nodeIsBefore && !nodeIsAfter)
38525 if (!nodeIsBefore && nodeIsAfter)
38527 if (nodeIsBefore && nodeIsAfter)
38535 // hide stuff that is not compatible
38549 * @event specialkey
38553 * @cfg {String} fieldClass @hide
38556 * @cfg {String} focusClass @hide
38559 * @cfg {String} autoCreate @hide
38562 * @cfg {String} inputType @hide
38565 * @cfg {String} invalidClass @hide
38568 * @cfg {String} invalidText @hide
38571 * @cfg {String} msgFx @hide
38574 * @cfg {String} validateOnBlur @hide
38576 });// <script type="text/javascript">
38579 * Ext JS Library 1.1.1
38580 * Copyright(c) 2006-2007, Ext JS, LLC.
38586 * @class Roo.form.HtmlEditorToolbar1
38591 new Roo.form.HtmlEditor({
38594 new Roo.form.HtmlEditorToolbar1({
38595 disable : { fonts: 1 , format: 1, ..., ... , ...],
38601 * @cfg {Object} disable List of elements to disable..
38602 * @cfg {Array} btns List of additional buttons.
38606 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
38609 Roo.form.HtmlEditor.ToolbarStandard = function(config)
38612 Roo.apply(this, config);
38613 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
38614 // dont call parent... till later.
38617 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
38625 * @cfg {Object} disable List of toolbar elements to disable
38630 * @cfg {Array} fontFamilies An array of available font families
38648 // "á" , ?? a acute?
38653 "°" // , // degrees
38655 // "é" , // e ecute
38656 // "ú" , // u ecute?
38659 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
38660 "input:submit", "input:button", "select", "textarea", "label" ],
38663 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
38665 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
38668 * @cfg {String} defaultFont default font to use.
38670 defaultFont: 'tahoma',
38672 fontSelect : false,
38675 formatCombo : false,
38677 init : function(editor)
38679 this.editor = editor;
38682 var fid = editor.frameId;
38684 function btn(id, toggle, handler){
38685 var xid = fid + '-'+ id ;
38689 cls : 'x-btn-icon x-edit-'+id,
38690 enableToggle:toggle !== false,
38691 scope: editor, // was editor...
38692 handler:handler||editor.relayBtnCmd,
38693 clickEvent:'mousedown',
38694 tooltip: etb.buttonTips[id] || undefined, ///tips ???
38701 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
38703 // stop form submits
38704 tb.el.on('click', function(e){
38705 e.preventDefault(); // what does this do?
38708 if(!this.disable.font && !Roo.isSafari){
38709 /* why no safari for fonts
38710 editor.fontSelect = tb.el.createChild({
38713 cls:'x-font-select',
38714 html: editor.createFontOptions()
38716 editor.fontSelect.on('change', function(){
38717 var font = editor.fontSelect.dom.value;
38718 editor.relayCmd('fontname', font);
38719 editor.deferFocus();
38722 editor.fontSelect.dom,
38727 if(!this.disable.formats){
38728 this.formatCombo = new Roo.form.ComboBox({
38729 store: new Roo.data.SimpleStore({
38732 data : this.formats // from states.js
38735 //autoCreate : {tag: "div", size: "20"},
38736 displayField:'tag',
38740 triggerAction: 'all',
38741 emptyText:'Add tag',
38742 selectOnFocus:true,
38745 'select': function(c, r, i) {
38746 editor.insertTag(r.get('tag'));
38752 tb.addField(this.formatCombo);
38756 if(!this.disable.format){
38763 if(!this.disable.fontSize){
38768 btn('increasefontsize', false, editor.adjustFont),
38769 btn('decreasefontsize', false, editor.adjustFont)
38774 if(this.disable.colors){
38777 id:editor.frameId +'-forecolor',
38778 cls:'x-btn-icon x-edit-forecolor',
38779 clickEvent:'mousedown',
38780 tooltip: this.buttonTips['forecolor'] || undefined,
38782 menu : new Roo.menu.ColorMenu({
38783 allowReselect: true,
38784 focus: Roo.emptyFn,
38787 selectHandler: function(cp, color){
38788 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
38789 editor.deferFocus();
38792 clickEvent:'mousedown'
38795 id:editor.frameId +'backcolor',
38796 cls:'x-btn-icon x-edit-backcolor',
38797 clickEvent:'mousedown',
38798 tooltip: this.buttonTips['backcolor'] || undefined,
38800 menu : new Roo.menu.ColorMenu({
38801 focus: Roo.emptyFn,
38804 allowReselect: true,
38805 selectHandler: function(cp, color){
38807 editor.execCmd('useCSS', false);
38808 editor.execCmd('hilitecolor', color);
38809 editor.execCmd('useCSS', true);
38810 editor.deferFocus();
38812 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
38813 Roo.isSafari || Roo.isIE ? '#'+color : color);
38814 editor.deferFocus();
38818 clickEvent:'mousedown'
38823 // now add all the items...
38826 if(!this.disable.alignments){
38829 btn('justifyleft'),
38830 btn('justifycenter'),
38831 btn('justifyright')
38835 //if(!Roo.isSafari){
38836 if(!this.disable.links){
38839 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
38843 if(!this.disable.lists){
38846 btn('insertorderedlist'),
38847 btn('insertunorderedlist')
38850 if(!this.disable.sourceEdit){
38853 btn('sourceedit', true, function(btn){
38854 this.toggleSourceEdit(btn.pressed);
38861 // special menu.. - needs to be tidied up..
38862 if (!this.disable.special) {
38865 cls: 'x-edit-none',
38870 for (var i =0; i < this.specialChars.length; i++) {
38871 smenu.menu.items.push({
38873 text: this.specialChars[i],
38874 handler: function(a,b) {
38875 editor.insertAtCursor(String.fromCharCode(a.text.replace('&#','').replace(';', '')));
38887 for(var i =0; i< this.btns.length;i++) {
38888 var b = this.btns[i];
38889 b.cls = 'x-edit-none';
38898 // disable everything...
38900 this.tb.items.each(function(item){
38901 if(item.id != editor.frameId+ '-sourceedit'){
38905 this.rendered = true;
38907 // the all the btns;
38908 editor.on('editorevent', this.updateToolbar, this);
38909 // other toolbars need to implement this..
38910 //editor.on('editmodechange', this.updateToolbar, this);
38916 * Protected method that will not generally be called directly. It triggers
38917 * a toolbar update by reading the markup state of the current selection in the editor.
38919 updateToolbar: function(){
38921 if(!this.editor.activated){
38922 this.editor.onFirstFocus();
38926 var btns = this.tb.items.map,
38927 doc = this.editor.doc,
38928 frameId = this.editor.frameId;
38930 if(!this.disable.font && !Roo.isSafari){
38932 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
38933 if(name != this.fontSelect.dom.value){
38934 this.fontSelect.dom.value = name;
38938 if(!this.disable.format){
38939 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
38940 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
38941 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
38943 if(!this.disable.alignments){
38944 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
38945 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
38946 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
38948 if(!Roo.isSafari && !this.disable.lists){
38949 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
38950 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
38953 var ans = this.editor.getAllAncestors();
38954 if (this.formatCombo) {
38957 var store = this.formatCombo.store;
38958 this.formatCombo.setValue("");
38959 for (var i =0; i < ans.length;i++) {
38960 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), true).length) {
38962 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
38970 // hides menus... - so this cant be on a menu...
38971 Roo.menu.MenuMgr.hideAll();
38973 //this.editorsyncValue();
38977 createFontOptions : function(){
38978 var buf = [], fs = this.fontFamilies, ff, lc;
38979 for(var i = 0, len = fs.length; i< len; i++){
38981 lc = ff.toLowerCase();
38983 '<option value="',lc,'" style="font-family:',ff,';"',
38984 (this.defaultFont == lc ? ' selected="true">' : '>'),
38989 return buf.join('');
38992 toggleSourceEdit : function(sourceEditMode){
38993 if(sourceEditMode === undefined){
38994 sourceEditMode = !this.sourceEditMode;
38996 this.sourceEditMode = sourceEditMode === true;
38997 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
38998 // just toggle the button?
38999 if(btn.pressed !== this.editor.sourceEditMode){
39000 btn.toggle(this.editor.sourceEditMode);
39004 if(this.sourceEditMode){
39005 this.tb.items.each(function(item){
39006 if(item.cmd != 'sourceedit'){
39012 if(this.initialized){
39013 this.tb.items.each(function(item){
39019 // tell the editor that it's been pressed..
39020 this.editor.toggleSourceEdit(sourceEditMode);
39024 * Object collection of toolbar tooltips for the buttons in the editor. The key
39025 * is the command id associated with that button and the value is a valid QuickTips object.
39030 title: 'Bold (Ctrl+B)',
39031 text: 'Make the selected text bold.',
39032 cls: 'x-html-editor-tip'
39035 title: 'Italic (Ctrl+I)',
39036 text: 'Make the selected text italic.',
39037 cls: 'x-html-editor-tip'
39045 title: 'Bold (Ctrl+B)',
39046 text: 'Make the selected text bold.',
39047 cls: 'x-html-editor-tip'
39050 title: 'Italic (Ctrl+I)',
39051 text: 'Make the selected text italic.',
39052 cls: 'x-html-editor-tip'
39055 title: 'Underline (Ctrl+U)',
39056 text: 'Underline the selected text.',
39057 cls: 'x-html-editor-tip'
39059 increasefontsize : {
39060 title: 'Grow Text',
39061 text: 'Increase the font size.',
39062 cls: 'x-html-editor-tip'
39064 decreasefontsize : {
39065 title: 'Shrink Text',
39066 text: 'Decrease the font size.',
39067 cls: 'x-html-editor-tip'
39070 title: 'Text Highlight Color',
39071 text: 'Change the background color of the selected text.',
39072 cls: 'x-html-editor-tip'
39075 title: 'Font Color',
39076 text: 'Change the color of the selected text.',
39077 cls: 'x-html-editor-tip'
39080 title: 'Align Text Left',
39081 text: 'Align text to the left.',
39082 cls: 'x-html-editor-tip'
39085 title: 'Center Text',
39086 text: 'Center text in the editor.',
39087 cls: 'x-html-editor-tip'
39090 title: 'Align Text Right',
39091 text: 'Align text to the right.',
39092 cls: 'x-html-editor-tip'
39094 insertunorderedlist : {
39095 title: 'Bullet List',
39096 text: 'Start a bulleted list.',
39097 cls: 'x-html-editor-tip'
39099 insertorderedlist : {
39100 title: 'Numbered List',
39101 text: 'Start a numbered list.',
39102 cls: 'x-html-editor-tip'
39105 title: 'Hyperlink',
39106 text: 'Make the selected text a hyperlink.',
39107 cls: 'x-html-editor-tip'
39110 title: 'Source Edit',
39111 text: 'Switch to source editing mode.',
39112 cls: 'x-html-editor-tip'
39116 onDestroy : function(){
39119 this.tb.items.each(function(item){
39121 item.menu.removeAll();
39123 item.menu.el.destroy();
39131 onFirstFocus: function() {
39132 this.tb.items.each(function(item){
39141 // <script type="text/javascript">
39144 * Ext JS Library 1.1.1
39145 * Copyright(c) 2006-2007, Ext JS, LLC.
39152 * @class Roo.form.HtmlEditor.ToolbarContext
39157 new Roo.form.HtmlEditor({
39160 new Roo.form.HtmlEditor.ToolbarStandard(),
39161 new Roo.form.HtmlEditor.ToolbarContext()
39166 * @config : {Object} disable List of elements to disable.. (not done yet.)
39171 Roo.form.HtmlEditor.ToolbarContext = function(config)
39174 Roo.apply(this, config);
39175 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39176 // dont call parent... till later.
39178 Roo.form.HtmlEditor.ToolbarContext.types = {
39190 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39252 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
39257 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
39321 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
39329 * @cfg {Object} disable List of toolbar elements to disable
39338 init : function(editor)
39340 this.editor = editor;
39343 var fid = editor.frameId;
39345 function btn(id, toggle, handler){
39346 var xid = fid + '-'+ id ;
39350 cls : 'x-btn-icon x-edit-'+id,
39351 enableToggle:toggle !== false,
39352 scope: editor, // was editor...
39353 handler:handler||editor.relayBtnCmd,
39354 clickEvent:'mousedown',
39355 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39359 // create a new element.
39360 var wdiv = editor.wrap.createChild({
39362 }, editor.wrap.dom.firstChild.nextSibling, true);
39364 // can we do this more than once??
39366 // stop form submits
39369 // disable everything...
39370 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39371 this.toolbars = {};
39373 for (var i in ty) {
39374 this.toolbars[i] = this.buildToolbar(ty[i],i);
39376 this.tb = this.toolbars.BODY;
39380 this.rendered = true;
39382 // the all the btns;
39383 editor.on('editorevent', this.updateToolbar, this);
39384 // other toolbars need to implement this..
39385 //editor.on('editmodechange', this.updateToolbar, this);
39391 * Protected method that will not generally be called directly. It triggers
39392 * a toolbar update by reading the markup state of the current selection in the editor.
39394 updateToolbar: function(){
39396 if(!this.editor.activated){
39397 this.editor.onFirstFocus();
39402 var ans = this.editor.getAllAncestors();
39405 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39406 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
39407 sel = sel ? sel : this.editor.doc.body;
39408 sel = sel.tagName.length ? sel : this.editor.doc.body;
39409 var tn = sel.tagName.toUpperCase();
39410 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
39411 tn = sel.tagName.toUpperCase();
39412 if (this.tb.name == tn) {
39413 return; // no change
39416 ///console.log("show: " + tn);
39417 this.tb = this.toolbars[tn];
39419 this.tb.fields.each(function(e) {
39420 e.setValue(sel.getAttribute(e.name));
39422 this.tb.selectedNode = sel;
39425 Roo.menu.MenuMgr.hideAll();
39427 //this.editorsyncValue();
39432 onDestroy : function(){
39435 this.tb.items.each(function(item){
39437 item.menu.removeAll();
39439 item.menu.el.destroy();
39447 onFirstFocus: function() {
39448 // need to do this for all the toolbars..
39449 this.tb.items.each(function(item){
39453 buildToolbar: function(tlist, nm)
39455 var editor = this.editor;
39456 // create a new element.
39457 var wdiv = editor.wrap.createChild({
39459 }, editor.wrap.dom.firstChild.nextSibling, true);
39462 var tb = new Roo.Toolbar(wdiv);
39463 tb.add(nm+ ": ");
39464 for (var i in tlist) {
39465 var item = tlist[i];
39466 tb.add(item.title + ": ");
39471 tb.addField( new Roo.form.ComboBox({
39472 store: new Roo.data.SimpleStore({
39475 data : item.opts // from states.js
39478 displayField:'val',
39482 triggerAction: 'all',
39483 emptyText:'Select',
39484 selectOnFocus:true,
39485 width: item.width ? item.width : 130,
39487 'select': function(c, r, i) {
39488 tb.selectedNode.setAttribute(c.name, r.get('val'));
39499 tb.addField( new Roo.form.TextField({
39502 //allowBlank:false,
39507 tb.addField( new Roo.form.TextField({
39513 'change' : function(f, nv, ov) {
39514 tb.selectedNode.setAttribute(f.name, nv);
39520 tb.el.on('click', function(e){
39521 e.preventDefault(); // what does this do?
39523 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
39526 // dont need to disable them... as they will get hidden
39543 * Ext JS Library 1.1.1
39544 * Copyright(c) 2006-2007, Ext JS, LLC.
39546 * Originally Released Under LGPL - original licence link has changed is not relivant.
39549 * <script type="text/javascript">
39553 * @class Roo.form.BasicForm
39554 * @extends Roo.util.Observable
39555 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
39557 * @param {String/HTMLElement/Roo.Element} el The form element or its id
39558 * @param {Object} config Configuration options
39560 Roo.form.BasicForm = function(el, config){
39561 Roo.apply(this, config);
39563 * The Roo.form.Field items in this form.
39564 * @type MixedCollection
39566 this.items = new Roo.util.MixedCollection(false, function(o){
39567 return o.id || (o.id = Roo.id());
39571 * @event beforeaction
39572 * Fires before any action is performed. Return false to cancel the action.
39573 * @param {Form} this
39574 * @param {Action} action The action to be performed
39576 beforeaction: true,
39578 * @event actionfailed
39579 * Fires when an action fails.
39580 * @param {Form} this
39581 * @param {Action} action The action that failed
39583 actionfailed : true,
39585 * @event actioncomplete
39586 * Fires when an action is completed.
39587 * @param {Form} this
39588 * @param {Action} action The action that completed
39590 actioncomplete : true
39595 Roo.form.BasicForm.superclass.constructor.call(this);
39598 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
39600 * @cfg {String} method
39601 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
39604 * @cfg {DataReader} reader
39605 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
39606 * This is optional as there is built-in support for processing JSON.
39609 * @cfg {DataReader} errorReader
39610 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
39611 * This is completely optional as there is built-in support for processing JSON.
39614 * @cfg {String} url
39615 * The URL to use for form actions if one isn't supplied in the action options.
39618 * @cfg {Boolean} fileUpload
39619 * Set to true if this form is a file upload.
39622 * @cfg {Object} baseParams
39623 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
39626 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
39631 activeAction : null,
39634 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
39635 * or setValues() data instead of when the form was first created.
39637 trackResetOnLoad : false,
39640 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
39641 * element by passing it or its id or mask the form itself by passing in true.
39644 waitMsgTarget : undefined,
39647 initEl : function(el){
39648 this.el = Roo.get(el);
39649 this.id = this.el.id || Roo.id();
39650 this.el.on('submit', this.onSubmit, this);
39651 this.el.addClass('x-form');
39655 onSubmit : function(e){
39660 * Returns true if client-side validation on the form is successful.
39663 isValid : function(){
39665 this.items.each(function(f){
39674 * Returns true if any fields in this form have changed since their original load.
39677 isDirty : function(){
39679 this.items.each(function(f){
39689 * Performs a predefined action (submit or load) or custom actions you define on this form.
39690 * @param {String} actionName The name of the action type
39691 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
39692 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
39693 * accept other config options):
39695 Property Type Description
39696 ---------------- --------------- ----------------------------------------------------------------------------------
39697 url String The url for the action (defaults to the form's url)
39698 method String The form method to use (defaults to the form's method, or POST if not defined)
39699 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
39700 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
39701 validate the form on the client (defaults to false)
39703 * @return {BasicForm} this
39705 doAction : function(action, options){
39706 if(typeof action == 'string'){
39707 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
39709 if(this.fireEvent('beforeaction', this, action) !== false){
39710 this.beforeAction(action);
39711 action.run.defer(100, action);
39717 * Shortcut to do a submit action.
39718 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39719 * @return {BasicForm} this
39721 submit : function(options){
39722 this.doAction('submit', options);
39727 * Shortcut to do a load action.
39728 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39729 * @return {BasicForm} this
39731 load : function(options){
39732 this.doAction('load', options);
39737 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
39738 * @param {Record} record The record to edit
39739 * @return {BasicForm} this
39741 updateRecord : function(record){
39742 record.beginEdit();
39743 var fs = record.fields;
39744 fs.each(function(f){
39745 var field = this.findField(f.name);
39747 record.set(f.name, field.getValue());
39755 * Loads an Roo.data.Record into this form.
39756 * @param {Record} record The record to load
39757 * @return {BasicForm} this
39759 loadRecord : function(record){
39760 this.setValues(record.data);
39765 beforeAction : function(action){
39766 var o = action.options;
39768 if(this.waitMsgTarget === true){
39769 this.el.mask(o.waitMsg, 'x-mask-loading');
39770 }else if(this.waitMsgTarget){
39771 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
39772 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
39774 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
39780 afterAction : function(action, success){
39781 this.activeAction = null;
39782 var o = action.options;
39784 if(this.waitMsgTarget === true){
39786 }else if(this.waitMsgTarget){
39787 this.waitMsgTarget.unmask();
39789 Roo.MessageBox.updateProgress(1);
39790 Roo.MessageBox.hide();
39797 Roo.callback(o.success, o.scope, [this, action]);
39798 this.fireEvent('actioncomplete', this, action);
39800 Roo.callback(o.failure, o.scope, [this, action]);
39801 this.fireEvent('actionfailed', this, action);
39806 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
39807 * @param {String} id The value to search for
39810 findField : function(id){
39811 var field = this.items.get(id);
39813 this.items.each(function(f){
39814 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
39820 return field || null;
39825 * Mark fields in this form invalid in bulk.
39826 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
39827 * @return {BasicForm} this
39829 markInvalid : function(errors){
39830 if(errors instanceof Array){
39831 for(var i = 0, len = errors.length; i < len; i++){
39832 var fieldError = errors[i];
39833 var f = this.findField(fieldError.id);
39835 f.markInvalid(fieldError.msg);
39841 if(typeof errors[id] != 'function' && (field = this.findField(id))){
39842 field.markInvalid(errors[id]);
39850 * Set values for fields in this form in bulk.
39851 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
39852 * @return {BasicForm} this
39854 setValues : function(values){
39855 if(values instanceof Array){ // array of objects
39856 for(var i = 0, len = values.length; i < len; i++){
39858 var f = this.findField(v.id);
39860 f.setValue(v.value);
39861 if(this.trackResetOnLoad){
39862 f.originalValue = f.getValue();
39866 }else{ // object hash
39869 if(typeof values[id] != 'function' && (field = this.findField(id))){
39871 if (field.setFromData &&
39872 field.valueField &&
39873 field.displayField &&
39874 // combos' with local stores can
39875 // be queried via setValue()
39876 // to set their value..
39877 (field.store && !field.store.isLocal)
39881 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
39882 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
39883 field.setFromData(sd);
39886 field.setValue(values[id]);
39890 if(this.trackResetOnLoad){
39891 field.originalValue = field.getValue();
39900 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
39901 * they are returned as an array.
39902 * @param {Boolean} asString
39905 getValues : function(asString){
39906 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
39907 if(asString === true){
39910 return Roo.urlDecode(fs);
39914 * Clears all invalid messages in this form.
39915 * @return {BasicForm} this
39917 clearInvalid : function(){
39918 this.items.each(function(f){
39925 * Resets this form.
39926 * @return {BasicForm} this
39928 reset : function(){
39929 this.items.each(function(f){
39936 * Add Roo.form components to this form.
39937 * @param {Field} field1
39938 * @param {Field} field2 (optional)
39939 * @param {Field} etc (optional)
39940 * @return {BasicForm} this
39943 this.items.addAll(Array.prototype.slice.call(arguments, 0));
39949 * Removes a field from the items collection (does NOT remove its markup).
39950 * @param {Field} field
39951 * @return {BasicForm} this
39953 remove : function(field){
39954 this.items.remove(field);
39959 * Looks at the fields in this form, checks them for an id attribute,
39960 * and calls applyTo on the existing dom element with that id.
39961 * @return {BasicForm} this
39963 render : function(){
39964 this.items.each(function(f){
39965 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
39973 * Calls {@link Ext#apply} for all fields in this form with the passed object.
39974 * @param {Object} values
39975 * @return {BasicForm} this
39977 applyToFields : function(o){
39978 this.items.each(function(f){
39985 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
39986 * @param {Object} values
39987 * @return {BasicForm} this
39989 applyIfToFields : function(o){
39990 this.items.each(function(f){
39998 Roo.BasicForm = Roo.form.BasicForm;/*
40000 * Ext JS Library 1.1.1
40001 * Copyright(c) 2006-2007, Ext JS, LLC.
40003 * Originally Released Under LGPL - original licence link has changed is not relivant.
40006 * <script type="text/javascript">
40010 * @class Roo.form.Form
40011 * @extends Roo.form.BasicForm
40012 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40014 * @param {Object} config Configuration options
40016 Roo.form.Form = function(config){
40018 if (config.items) {
40019 xitems = config.items;
40020 delete config.items;
40024 Roo.form.Form.superclass.constructor.call(this, null, config);
40025 this.url = this.url || this.action;
40027 this.root = new Roo.form.Layout(Roo.applyIf({
40031 this.active = this.root;
40033 * Array of all the buttons that have been added to this form via {@link addButton}
40037 this.allItems = [];
40040 * @event clientvalidation
40041 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40042 * @param {Form} this
40043 * @param {Boolean} valid true if the form has passed client-side validation
40045 clientvalidation: true,
40048 * Fires when the form is rendered
40049 * @param {Roo.form.Form} form
40054 Roo.each(xitems, this.addxtype, this);
40060 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40062 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40065 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40068 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40070 buttonAlign:'center',
40073 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40078 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40079 * This property cascades to child containers if not set.
40084 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40085 * fires a looping event with that state. This is required to bind buttons to the valid
40086 * state using the config value formBind:true on the button.
40088 monitorValid : false,
40091 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40096 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40097 * fields are added and the column is closed. If no fields are passed the column remains open
40098 * until end() is called.
40099 * @param {Object} config The config to pass to the column
40100 * @param {Field} field1 (optional)
40101 * @param {Field} field2 (optional)
40102 * @param {Field} etc (optional)
40103 * @return Column The column container object
40105 column : function(c){
40106 var col = new Roo.form.Column(c);
40108 if(arguments.length > 1){ // duplicate code required because of Opera
40109 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40116 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40117 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40118 * until end() is called.
40119 * @param {Object} config The config to pass to the fieldset
40120 * @param {Field} field1 (optional)
40121 * @param {Field} field2 (optional)
40122 * @param {Field} etc (optional)
40123 * @return FieldSet The fieldset container object
40125 fieldset : function(c){
40126 var fs = new Roo.form.FieldSet(c);
40128 if(arguments.length > 1){ // duplicate code required because of Opera
40129 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40136 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
40137 * fields are added and the container is closed. If no fields are passed the container remains open
40138 * until end() is called.
40139 * @param {Object} config The config to pass to the Layout
40140 * @param {Field} field1 (optional)
40141 * @param {Field} field2 (optional)
40142 * @param {Field} etc (optional)
40143 * @return Layout The container object
40145 container : function(c){
40146 var l = new Roo.form.Layout(c);
40148 if(arguments.length > 1){ // duplicate code required because of Opera
40149 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40156 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
40157 * @param {Object} container A Roo.form.Layout or subclass of Layout
40158 * @return {Form} this
40160 start : function(c){
40161 // cascade label info
40162 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
40163 this.active.stack.push(c);
40164 c.ownerCt = this.active;
40170 * Closes the current open container
40171 * @return {Form} this
40174 if(this.active == this.root){
40177 this.active = this.active.ownerCt;
40182 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
40183 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
40184 * as the label of the field.
40185 * @param {Field} field1
40186 * @param {Field} field2 (optional)
40187 * @param {Field} etc. (optional)
40188 * @return {Form} this
40191 this.active.stack.push.apply(this.active.stack, arguments);
40192 this.allItems.push.apply(this.allItems,arguments);
40194 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
40195 if(a[i].isFormField){
40200 Roo.form.Form.superclass.add.apply(this, r);
40205 * Find any element that has been added to a form, using it's ID or name
40206 * This can include framesets, columns etc. along with regular fields..
40207 * @param {String} id - id or name to find.
40209 * @return {Element} e - or false if nothing found.
40211 findbyId : function(id)
40217 Ext.each(this.allItems, function(f){
40218 if (f.id == id || f.name == id ){
40229 * Render this form into the passed container. This should only be called once!
40230 * @param {String/HTMLElement/Element} container The element this component should be rendered into
40231 * @return {Form} this
40233 render : function(ct){
40235 var o = this.autoCreate || {
40237 method : this.method || 'POST',
40238 id : this.id || Roo.id()
40240 this.initEl(ct.createChild(o));
40242 this.root.render(this.el);
40244 this.items.each(function(f){
40245 f.render('x-form-el-'+f.id);
40248 if(this.buttons.length > 0){
40249 // tables are required to maintain order and for correct IE layout
40250 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
40251 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
40252 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
40254 var tr = tb.getElementsByTagName('tr')[0];
40255 for(var i = 0, len = this.buttons.length; i < len; i++) {
40256 var b = this.buttons[i];
40257 var td = document.createElement('td');
40258 td.className = 'x-form-btn-td';
40259 b.render(tr.appendChild(td));
40262 if(this.monitorValid){ // initialize after render
40263 this.startMonitoring();
40265 this.fireEvent('rendered', this);
40270 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
40271 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
40272 * object or a valid Roo.DomHelper element config
40273 * @param {Function} handler The function called when the button is clicked
40274 * @param {Object} scope (optional) The scope of the handler function
40275 * @return {Roo.Button}
40277 addButton : function(config, handler, scope){
40281 minWidth: this.minButtonWidth,
40284 if(typeof config == "string"){
40287 Roo.apply(bc, config);
40289 var btn = new Roo.Button(null, bc);
40290 this.buttons.push(btn);
40295 * Adds a series of form elements (using the xtype property as the factory method.
40296 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
40297 * @param {Object} config
40300 addxtype : function()
40302 var ar = Array.prototype.slice.call(arguments, 0);
40304 for(var i = 0; i < ar.length; i++) {
40306 continue; // skip -- if this happends something invalid got sent, we
40307 // should ignore it, as basically that interface element will not show up
40308 // and that should be pretty obvious!!
40311 if (Roo.form[ar[i].xtype]) {
40313 var fe = Roo.factory(ar[i], Roo.form);
40319 fe.store.form = this;
40324 this.allItems.push(fe);
40325 if (fe.items && fe.addxtype) {
40326 fe.addxtype.apply(fe, fe.items);
40336 // console.log('adding ' + ar[i].xtype);
40338 if (ar[i].xtype == 'Button') {
40339 //console.log('adding button');
40340 //console.log(ar[i]);
40341 this.addButton(ar[i]);
40342 this.allItems.push(fe);
40346 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
40347 alert('end is not supported on xtype any more, use items');
40349 // //console.log('adding end');
40357 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
40358 * option "monitorValid"
40360 startMonitoring : function(){
40363 Roo.TaskMgr.start({
40364 run : this.bindHandler,
40365 interval : this.monitorPoll || 200,
40372 * Stops monitoring of the valid state of this form
40374 stopMonitoring : function(){
40375 this.bound = false;
40379 bindHandler : function(){
40381 return false; // stops binding
40384 this.items.each(function(f){
40385 if(!f.isValid(true)){
40390 for(var i = 0, len = this.buttons.length; i < len; i++){
40391 var btn = this.buttons[i];
40392 if(btn.formBind === true && btn.disabled === valid){
40393 btn.setDisabled(!valid);
40396 this.fireEvent('clientvalidation', this, valid);
40410 Roo.Form = Roo.form.Form;
40413 * Ext JS Library 1.1.1
40414 * Copyright(c) 2006-2007, Ext JS, LLC.
40416 * Originally Released Under LGPL - original licence link has changed is not relivant.
40419 * <script type="text/javascript">
40423 * @class Roo.form.Action
40424 * Internal Class used to handle form actions
40426 * @param {Roo.form.BasicForm} el The form element or its id
40427 * @param {Object} config Configuration options
40431 // define the action interface
40432 Roo.form.Action = function(form, options){
40434 this.options = options || {};
40437 * Client Validation Failed
40440 Roo.form.Action.CLIENT_INVALID = 'client';
40442 * Server Validation Failed
40445 Roo.form.Action.SERVER_INVALID = 'server';
40447 * Connect to Server Failed
40450 Roo.form.Action.CONNECT_FAILURE = 'connect';
40452 * Reading Data from Server Failed
40455 Roo.form.Action.LOAD_FAILURE = 'load';
40457 Roo.form.Action.prototype = {
40459 failureType : undefined,
40460 response : undefined,
40461 result : undefined,
40463 // interface method
40464 run : function(options){
40468 // interface method
40469 success : function(response){
40473 // interface method
40474 handleResponse : function(response){
40478 // default connection failure
40479 failure : function(response){
40480 this.response = response;
40481 this.failureType = Roo.form.Action.CONNECT_FAILURE;
40482 this.form.afterAction(this, false);
40485 processResponse : function(response){
40486 this.response = response;
40487 if(!response.responseText){
40490 this.result = this.handleResponse(response);
40491 return this.result;
40494 // utility functions used internally
40495 getUrl : function(appendParams){
40496 var url = this.options.url || this.form.url || this.form.el.dom.action;
40498 var p = this.getParams();
40500 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
40506 getMethod : function(){
40507 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
40510 getParams : function(){
40511 var bp = this.form.baseParams;
40512 var p = this.options.params;
40514 if(typeof p == "object"){
40515 p = Roo.urlEncode(Roo.applyIf(p, bp));
40516 }else if(typeof p == 'string' && bp){
40517 p += '&' + Roo.urlEncode(bp);
40520 p = Roo.urlEncode(bp);
40525 createCallback : function(){
40527 success: this.success,
40528 failure: this.failure,
40530 timeout: (this.form.timeout*1000),
40531 upload: this.form.fileUpload ? this.success : undefined
40536 Roo.form.Action.Submit = function(form, options){
40537 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
40540 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
40544 var o = this.options;
40545 var method = this.getMethod();
40546 var isPost = method == 'POST';
40547 if(o.clientValidation === false || this.form.isValid()){
40548 Roo.Ajax.request(Roo.apply(this.createCallback(), {
40549 form:this.form.el.dom,
40550 url:this.getUrl(!isPost),
40552 params:isPost ? this.getParams() : null,
40553 isUpload: this.form.fileUpload
40556 }else if (o.clientValidation !== false){ // client validation failed
40557 this.failureType = Roo.form.Action.CLIENT_INVALID;
40558 this.form.afterAction(this, false);
40562 success : function(response){
40563 var result = this.processResponse(response);
40564 if(result === true || result.success){
40565 this.form.afterAction(this, true);
40569 this.form.markInvalid(result.errors);
40570 this.failureType = Roo.form.Action.SERVER_INVALID;
40572 this.form.afterAction(this, false);
40575 handleResponse : function(response){
40576 if(this.form.errorReader){
40577 var rs = this.form.errorReader.read(response);
40580 for(var i = 0, len = rs.records.length; i < len; i++) {
40581 var r = rs.records[i];
40582 errors[i] = r.data;
40585 if(errors.length < 1){
40589 success : rs.success,
40595 ret = Roo.decode(response.responseText);
40599 errorMsg: "Failed to read server message: " + response.responseText,
40609 Roo.form.Action.Load = function(form, options){
40610 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
40611 this.reader = this.form.reader;
40614 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
40618 Roo.Ajax.request(Roo.apply(
40619 this.createCallback(), {
40620 method:this.getMethod(),
40621 url:this.getUrl(false),
40622 params:this.getParams()
40626 success : function(response){
40627 var result = this.processResponse(response);
40628 if(result === true || !result.success || !result.data){
40629 this.failureType = Roo.form.Action.LOAD_FAILURE;
40630 this.form.afterAction(this, false);
40633 this.form.clearInvalid();
40634 this.form.setValues(result.data);
40635 this.form.afterAction(this, true);
40638 handleResponse : function(response){
40639 if(this.form.reader){
40640 var rs = this.form.reader.read(response);
40641 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
40643 success : rs.success,
40647 return Roo.decode(response.responseText);
40651 Roo.form.Action.ACTION_TYPES = {
40652 'load' : Roo.form.Action.Load,
40653 'submit' : Roo.form.Action.Submit
40656 * Ext JS Library 1.1.1
40657 * Copyright(c) 2006-2007, Ext JS, LLC.
40659 * Originally Released Under LGPL - original licence link has changed is not relivant.
40662 * <script type="text/javascript">
40666 * @class Roo.form.Layout
40667 * @extends Roo.Component
40668 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
40670 * @param {Object} config Configuration options
40672 Roo.form.Layout = function(config){
40674 if (config.items) {
40675 xitems = config.items;
40676 delete config.items;
40678 Roo.form.Layout.superclass.constructor.call(this, config);
40680 Roo.each(xitems, this.addxtype, this);
40684 Roo.extend(Roo.form.Layout, Roo.Component, {
40686 * @cfg {String/Object} autoCreate
40687 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
40690 * @cfg {String/Object/Function} style
40691 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
40692 * a function which returns such a specification.
40695 * @cfg {String} labelAlign
40696 * Valid values are "left," "top" and "right" (defaults to "left")
40699 * @cfg {Number} labelWidth
40700 * Fixed width in pixels of all field labels (defaults to undefined)
40703 * @cfg {Boolean} clear
40704 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
40708 * @cfg {String} labelSeparator
40709 * The separator to use after field labels (defaults to ':')
40711 labelSeparator : ':',
40713 * @cfg {Boolean} hideLabels
40714 * True to suppress the display of field labels in this layout (defaults to false)
40716 hideLabels : false,
40719 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
40724 onRender : function(ct, position){
40725 if(this.el){ // from markup
40726 this.el = Roo.get(this.el);
40727 }else { // generate
40728 var cfg = this.getAutoCreate();
40729 this.el = ct.createChild(cfg, position);
40732 this.el.applyStyles(this.style);
40734 if(this.labelAlign){
40735 this.el.addClass('x-form-label-'+this.labelAlign);
40737 if(this.hideLabels){
40738 this.labelStyle = "display:none";
40739 this.elementStyle = "padding-left:0;";
40741 if(typeof this.labelWidth == 'number'){
40742 this.labelStyle = "width:"+this.labelWidth+"px;";
40743 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
40745 if(this.labelAlign == 'top'){
40746 this.labelStyle = "width:auto;";
40747 this.elementStyle = "padding-left:0;";
40750 var stack = this.stack;
40751 var slen = stack.length;
40753 if(!this.fieldTpl){
40754 var t = new Roo.Template(
40755 '<div class="x-form-item {5}">',
40756 '<label for="{0}" style="{2}">{1}{4}</label>',
40757 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
40759 '</div><div class="x-form-clear-left"></div>'
40761 t.disableFormats = true;
40763 Roo.form.Layout.prototype.fieldTpl = t;
40765 for(var i = 0; i < slen; i++) {
40766 if(stack[i].isFormField){
40767 this.renderField(stack[i]);
40769 this.renderComponent(stack[i]);
40774 this.el.createChild({cls:'x-form-clear'});
40779 renderField : function(f){
40780 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
40783 f.labelStyle||this.labelStyle||'', //2
40784 this.elementStyle||'', //3
40785 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
40786 f.itemCls||this.itemCls||'' //5
40787 ], true).getPrevSibling());
40791 renderComponent : function(c){
40792 c.render(c.isLayout ? this.el : this.el.createChild());
40795 * Adds a object form elements (using the xtype property as the factory method.)
40796 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
40797 * @param {Object} config
40799 addxtype : function(o)
40801 // create the lement.
40802 o.form = this.form;
40803 var fe = Roo.factory(o, Roo.form);
40804 this.form.allItems.push(fe);
40805 this.stack.push(fe);
40807 if (fe.isFormField) {
40808 this.form.items.add(fe);
40816 * @class Roo.form.Column
40817 * @extends Roo.form.Layout
40818 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
40820 * @param {Object} config Configuration options
40822 Roo.form.Column = function(config){
40823 Roo.form.Column.superclass.constructor.call(this, config);
40826 Roo.extend(Roo.form.Column, Roo.form.Layout, {
40828 * @cfg {Number/String} width
40829 * The fixed width of the column in pixels or CSS value (defaults to "auto")
40832 * @cfg {String/Object} autoCreate
40833 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
40837 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
40840 onRender : function(ct, position){
40841 Roo.form.Column.superclass.onRender.call(this, ct, position);
40843 this.el.setWidth(this.width);
40850 * @class Roo.form.Row
40851 * @extends Roo.form.Layout
40852 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
40854 * @param {Object} config Configuration options
40858 Roo.form.Row = function(config){
40859 Roo.form.Row.superclass.constructor.call(this, config);
40862 Roo.extend(Roo.form.Row, Roo.form.Layout, {
40864 * @cfg {Number/String} width
40865 * The fixed width of the column in pixels or CSS value (defaults to "auto")
40868 * @cfg {Number/String} height
40869 * The fixed height of the column in pixels or CSS value (defaults to "auto")
40871 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
40875 onRender : function(ct, position){
40876 //console.log('row render');
40878 var t = new Roo.Template(
40879 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
40880 '<label for="{0}" style="{2}">{1}{4}</label>',
40881 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
40885 t.disableFormats = true;
40887 Roo.form.Layout.prototype.rowTpl = t;
40889 this.fieldTpl = this.rowTpl;
40891 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
40892 var labelWidth = 100;
40894 if ((this.labelAlign != 'top')) {
40895 if (typeof this.labelWidth == 'number') {
40896 labelWidth = this.labelWidth
40898 this.padWidth = 20 + labelWidth;
40902 Roo.form.Column.superclass.onRender.call(this, ct, position);
40904 this.el.setWidth(this.width);
40907 this.el.setHeight(this.height);
40912 renderField : function(f){
40913 f.fieldEl = this.fieldTpl.append(this.el, [
40914 f.id, f.fieldLabel,
40915 f.labelStyle||this.labelStyle||'',
40916 this.elementStyle||'',
40917 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
40918 f.itemCls||this.itemCls||'',
40919 f.width ? f.width + this.padWidth : 160 + this.padWidth
40926 * @class Roo.form.FieldSet
40927 * @extends Roo.form.Layout
40928 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
40930 * @param {Object} config Configuration options
40932 Roo.form.FieldSet = function(config){
40933 Roo.form.FieldSet.superclass.constructor.call(this, config);
40936 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
40938 * @cfg {String} legend
40939 * The text to display as the legend for the FieldSet (defaults to '')
40942 * @cfg {String/Object} autoCreate
40943 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
40947 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
40950 onRender : function(ct, position){
40951 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
40953 this.setLegend(this.legend);
40958 setLegend : function(text){
40960 this.el.child('legend').update(text);
40965 * Ext JS Library 1.1.1
40966 * Copyright(c) 2006-2007, Ext JS, LLC.
40968 * Originally Released Under LGPL - original licence link has changed is not relivant.
40971 * <script type="text/javascript">
40974 * @class Roo.form.VTypes
40975 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
40978 Roo.form.VTypes = function(){
40979 // closure these in so they are only created once.
40980 var alpha = /^[a-zA-Z_]+$/;
40981 var alphanum = /^[a-zA-Z0-9_]+$/;
40982 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
40983 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
40985 // All these messages and functions are configurable
40988 * The function used to validate email addresses
40989 * @param {String} value The email address
40991 'email' : function(v){
40992 return email.test(v);
40995 * The error text to display when the email validation function returns false
40998 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
41000 * The keystroke filter mask to be applied on email input
41003 'emailMask' : /[a-z0-9_\.\-@]/i,
41006 * The function used to validate URLs
41007 * @param {String} value The URL
41009 'url' : function(v){
41010 return url.test(v);
41013 * The error text to display when the url validation function returns false
41016 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
41019 * The function used to validate alpha values
41020 * @param {String} value The value
41022 'alpha' : function(v){
41023 return alpha.test(v);
41026 * The error text to display when the alpha validation function returns false
41029 'alphaText' : 'This field should only contain letters and _',
41031 * The keystroke filter mask to be applied on alpha input
41034 'alphaMask' : /[a-z_]/i,
41037 * The function used to validate alphanumeric values
41038 * @param {String} value The value
41040 'alphanum' : function(v){
41041 return alphanum.test(v);
41044 * The error text to display when the alphanumeric validation function returns false
41047 'alphanumText' : 'This field should only contain letters, numbers and _',
41049 * The keystroke filter mask to be applied on alphanumeric input
41052 'alphanumMask' : /[a-z0-9_]/i
41054 }();//<script type="text/javascript">
41057 * @class Roo.form.FCKeditor
41058 * @extends Roo.form.TextArea
41059 * Wrapper around the FCKEditor http://www.fckeditor.net
41061 * Creates a new FCKeditor
41062 * @param {Object} config Configuration options
41064 Roo.form.FCKeditor = function(config){
41065 Roo.form.FCKeditor.superclass.constructor.call(this, config);
41068 * @event editorinit
41069 * Fired when the editor is initialized - you can add extra handlers here..
41070 * @param {FCKeditor} this
41071 * @param {Object} the FCK object.
41078 Roo.form.FCKeditor.editors = { };
41079 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
41081 //defaultAutoCreate : {
41082 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
41086 * @cfg {Object} fck options - see fck manual for details.
41091 * @cfg {Object} fck toolbar set (Basic or Default)
41093 toolbarSet : 'Basic',
41095 * @cfg {Object} fck BasePath
41097 basePath : '/fckeditor/',
41105 onRender : function(ct, position)
41108 this.defaultAutoCreate = {
41110 style:"width:300px;height:60px;",
41111 autocomplete: "off"
41114 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
41117 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
41118 if(this.preventScrollbars){
41119 this.el.setStyle("overflow", "hidden");
41121 this.el.setHeight(this.growMin);
41124 //console.log('onrender' + this.getId() );
41125 Roo.form.FCKeditor.editors[this.getId()] = this;
41128 this.replaceTextarea() ;
41132 getEditor : function() {
41133 return this.fckEditor;
41136 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
41137 * @param {Mixed} value The value to set
41141 setValue : function(value)
41143 //console.log('setValue: ' + value);
41145 if(typeof(value) == 'undefined') { // not sure why this is happending...
41148 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41150 //if(!this.el || !this.getEditor()) {
41151 // this.value = value;
41152 //this.setValue.defer(100,this,[value]);
41156 if(!this.getEditor()) {
41160 this.getEditor().SetData(value);
41167 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
41168 * @return {Mixed} value The field value
41170 getValue : function()
41173 if (this.frame && this.frame.dom.style.display == 'none') {
41174 return Roo.form.FCKeditor.superclass.getValue.call(this);
41177 if(!this.el || !this.getEditor()) {
41179 // this.getValue.defer(100,this);
41184 var value=this.getEditor().GetData();
41185 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41186 return Roo.form.FCKeditor.superclass.getValue.call(this);
41192 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
41193 * @return {Mixed} value The field value
41195 getRawValue : function()
41197 if (this.frame && this.frame.dom.style.display == 'none') {
41198 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41201 if(!this.el || !this.getEditor()) {
41202 //this.getRawValue.defer(100,this);
41209 var value=this.getEditor().GetData();
41210 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
41211 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41215 setSize : function(w,h) {
41219 //if (this.frame && this.frame.dom.style.display == 'none') {
41220 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41223 //if(!this.el || !this.getEditor()) {
41224 // this.setSize.defer(100,this, [w,h]);
41230 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41232 this.frame.dom.setAttribute('width', w);
41233 this.frame.dom.setAttribute('height', h);
41234 this.frame.setSize(w,h);
41238 toggleSourceEdit : function(value) {
41242 this.el.dom.style.display = value ? '' : 'none';
41243 this.frame.dom.style.display = value ? 'none' : '';
41248 focus: function(tag)
41250 if (this.frame.dom.style.display == 'none') {
41251 return Roo.form.FCKeditor.superclass.focus.call(this);
41253 if(!this.el || !this.getEditor()) {
41254 this.focus.defer(100,this, [tag]);
41261 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
41262 this.getEditor().Focus();
41264 if (!this.getEditor().Selection.GetSelection()) {
41265 this.focus.defer(100,this, [tag]);
41270 var r = this.getEditor().EditorDocument.createRange();
41271 r.setStart(tgs[0],0);
41272 r.setEnd(tgs[0],0);
41273 this.getEditor().Selection.GetSelection().removeAllRanges();
41274 this.getEditor().Selection.GetSelection().addRange(r);
41275 this.getEditor().Focus();
41282 replaceTextarea : function()
41284 if ( document.getElementById( this.getId() + '___Frame' ) )
41286 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
41288 // We must check the elements firstly using the Id and then the name.
41289 var oTextarea = document.getElementById( this.getId() );
41291 var colElementsByName = document.getElementsByName( this.getId() ) ;
41293 oTextarea.style.display = 'none' ;
41295 if ( oTextarea.tabIndex ) {
41296 this.TabIndex = oTextarea.tabIndex ;
41299 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
41300 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
41301 this.frame = Roo.get(this.getId() + '___Frame')
41304 _getConfigHtml : function()
41308 for ( var o in this.fckconfig ) {
41309 sConfig += sConfig.length > 0 ? '&' : '';
41310 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
41313 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
41317 _getIFrameHtml : function()
41319 var sFile = 'fckeditor.html' ;
41320 /* no idea what this is about..
41323 if ( (/fcksource=true/i).test( window.top.location.search ) )
41324 sFile = 'fckeditor.original.html' ;
41329 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
41330 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
41333 var html = '<iframe id="' + this.getId() +
41334 '___Frame" src="' + sLink +
41335 '" width="' + this.width +
41336 '" height="' + this.height + '"' +
41337 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
41338 ' frameborder="0" scrolling="no"></iframe>' ;
41343 _insertHtmlBefore : function( html, element )
41345 if ( element.insertAdjacentHTML ) {
41347 element.insertAdjacentHTML( 'beforeBegin', html ) ;
41349 var oRange = document.createRange() ;
41350 oRange.setStartBefore( element ) ;
41351 var oFragment = oRange.createContextualFragment( html );
41352 element.parentNode.insertBefore( oFragment, element ) ;
41365 //Roo.reg('fckeditor', Roo.form.FCKeditor);
41367 function FCKeditor_OnComplete(editorInstance){
41368 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
41369 f.fckEditor = editorInstance;
41370 //console.log("loaded");
41371 f.fireEvent('editorinit', f, editorInstance);
41391 //<script type="text/javascript">
41393 * @class Roo.form.GridField
41394 * @extends Roo.form.Field
41395 * Embed a grid (or editable grid into a form)
41398 * Creates a new GridField
41399 * @param {Object} config Configuration options
41401 Roo.form.GridField = function(config){
41402 Roo.form.GridField.superclass.constructor.call(this, config);
41406 Roo.extend(Roo.form.GridField, Roo.form.Field, {
41408 * @cfg {Number} width - used to restrict width of grid..
41412 * @cfg {Number} height - used to restrict height of grid..
41416 * @cfg {Object} xgrid (xtype'd description of grid) Grid or EditorGrid
41420 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41421 * {tag: "input", type: "checkbox", autocomplete: "off"})
41423 // defaultAutoCreate : { tag: 'div' },
41424 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
41426 * @cfg {String} addTitle Text to include for adding a title.
41430 onResize : function(){
41431 Roo.form.Field.superclass.onResize.apply(this, arguments);
41434 initEvents : function(){
41435 // Roo.form.Checkbox.superclass.initEvents.call(this);
41436 // has no events...
41441 getResizeEl : function(){
41445 getPositionEl : function(){
41450 onRender : function(ct, position){
41452 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
41453 var style = this.style;
41456 Roo.form.DisplayImage.superclass.onRender.call(this, ct, position);
41457 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
41458 this.viewEl = this.wrap.createChild({ tag: 'div' });
41460 this.viewEl.applyStyles(style);
41463 this.viewEl.setWidth(this.width);
41466 this.viewEl.setHeight(this.height);
41468 //if(this.inputValue !== undefined){
41469 //this.setValue(this.value);
41472 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
41475 this.grid.render();
41476 this.grid.getDataSource().on('remove', this.refreshValue, this);
41477 this.grid.getDataSource().on('update', this.refreshValue, this);
41478 this.grid.on('afteredit', this.refreshValue, this);
41484 * Sets the value of the item.
41485 * @param {String} either an object or a string..
41487 setValue : function(v){
41489 v = v || []; // empty set..
41490 // this does not seem smart - it really only affects memoryproxy grids..
41491 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
41492 var ds = this.grid.getDataSource();
41493 // assumes a json reader..
41495 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
41496 ds.loadData( data);
41498 Roo.form.GridField.superclass.setValue.call(this, v);
41499 this.refreshValue();
41500 // should load data in the grid really....
41504 refreshValue: function() {
41506 this.grid.getDataSource().each(function(r) {
41509 this.el.dom.value = Roo.encode(val);
41515 });//<script type="text/javasscript">
41519 * @class Roo.DDView
41520 * A DnD enabled version of Roo.View.
41521 * @param {Element/String} container The Element in which to create the View.
41522 * @param {String} tpl The template string used to create the markup for each element of the View
41523 * @param {Object} config The configuration properties. These include all the config options of
41524 * {@link Roo.View} plus some specific to this class.<br>
41526 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
41527 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
41529 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
41530 .x-view-drag-insert-above {
41531 border-top:1px dotted #3366cc;
41533 .x-view-drag-insert-below {
41534 border-bottom:1px dotted #3366cc;
41540 Roo.DDView = function(container, tpl, config) {
41541 Roo.DDView.superclass.constructor.apply(this, arguments);
41542 this.getEl().setStyle("outline", "0px none");
41543 this.getEl().unselectable();
41544 if (this.dragGroup) {
41545 this.setDraggable(this.dragGroup.split(","));
41547 if (this.dropGroup) {
41548 this.setDroppable(this.dropGroup.split(","));
41550 if (this.deletable) {
41551 this.setDeletable();
41553 this.isDirtyFlag = false;
41559 Roo.extend(Roo.DDView, Roo.View, {
41560 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
41561 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
41562 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
41563 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
41567 reset: Roo.emptyFn,
41569 clearInvalid: Roo.form.Field.prototype.clearInvalid,
41571 validate: function() {
41575 destroy: function() {
41576 this.purgeListeners();
41577 this.getEl.removeAllListeners();
41578 this.getEl().remove();
41579 if (this.dragZone) {
41580 if (this.dragZone.destroy) {
41581 this.dragZone.destroy();
41584 if (this.dropZone) {
41585 if (this.dropZone.destroy) {
41586 this.dropZone.destroy();
41591 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
41592 getName: function() {
41596 /** Loads the View from a JSON string representing the Records to put into the Store. */
41597 setValue: function(v) {
41599 throw "DDView.setValue(). DDView must be constructed with a valid Store";
41602 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
41603 this.store.proxy = new Roo.data.MemoryProxy(data);
41607 /** @return {String} a parenthesised list of the ids of the Records in the View. */
41608 getValue: function() {
41610 this.store.each(function(rec) {
41611 result += rec.id + ',';
41613 return result.substr(0, result.length - 1) + ')';
41616 getIds: function() {
41617 var i = 0, result = new Array(this.store.getCount());
41618 this.store.each(function(rec) {
41619 result[i++] = rec.id;
41624 isDirty: function() {
41625 return this.isDirtyFlag;
41629 * Part of the Roo.dd.DropZone interface. If no target node is found, the
41630 * whole Element becomes the target, and this causes the drop gesture to append.
41632 getTargetFromEvent : function(e) {
41633 var target = e.getTarget();
41634 while ((target !== null) && (target.parentNode != this.el.dom)) {
41635 target = target.parentNode;
41638 target = this.el.dom.lastChild || this.el.dom;
41644 * Create the drag data which consists of an object which has the property "ddel" as
41645 * the drag proxy element.
41647 getDragData : function(e) {
41648 var target = this.findItemFromChild(e.getTarget());
41650 this.handleSelection(e);
41651 var selNodes = this.getSelectedNodes();
41654 copy: this.copy || (this.allowCopy && e.ctrlKey),
41658 var selectedIndices = this.getSelectedIndexes();
41659 for (var i = 0; i < selectedIndices.length; i++) {
41660 dragData.records.push(this.store.getAt(selectedIndices[i]));
41662 if (selNodes.length == 1) {
41663 dragData.ddel = target.cloneNode(true); // the div element
41665 var div = document.createElement('div'); // create the multi element drag "ghost"
41666 div.className = 'multi-proxy';
41667 for (var i = 0, len = selNodes.length; i < len; i++) {
41668 div.appendChild(selNodes[i].cloneNode(true));
41670 dragData.ddel = div;
41672 //console.log(dragData)
41673 //console.log(dragData.ddel.innerHTML)
41676 //console.log('nodragData')
41680 /** Specify to which ddGroup items in this DDView may be dragged. */
41681 setDraggable: function(ddGroup) {
41682 if (ddGroup instanceof Array) {
41683 Roo.each(ddGroup, this.setDraggable, this);
41686 if (this.dragZone) {
41687 this.dragZone.addToGroup(ddGroup);
41689 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
41690 containerScroll: true,
41694 // Draggability implies selection. DragZone's mousedown selects the element.
41695 if (!this.multiSelect) { this.singleSelect = true; }
41697 // Wire the DragZone's handlers up to methods in *this*
41698 this.dragZone.getDragData = this.getDragData.createDelegate(this);
41702 /** Specify from which ddGroup this DDView accepts drops. */
41703 setDroppable: function(ddGroup) {
41704 if (ddGroup instanceof Array) {
41705 Roo.each(ddGroup, this.setDroppable, this);
41708 if (this.dropZone) {
41709 this.dropZone.addToGroup(ddGroup);
41711 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
41712 containerScroll: true,
41716 // Wire the DropZone's handlers up to methods in *this*
41717 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
41718 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
41719 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
41720 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
41721 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
41725 /** Decide whether to drop above or below a View node. */
41726 getDropPoint : function(e, n, dd){
41727 if (n == this.el.dom) { return "above"; }
41728 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
41729 var c = t + (b - t) / 2;
41730 var y = Roo.lib.Event.getPageY(e);
41738 onNodeEnter : function(n, dd, e, data){
41742 onNodeOver : function(n, dd, e, data){
41743 var pt = this.getDropPoint(e, n, dd);
41744 // set the insert point style on the target node
41745 var dragElClass = this.dropNotAllowed;
41748 if (pt == "above"){
41749 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
41750 targetElClass = "x-view-drag-insert-above";
41752 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
41753 targetElClass = "x-view-drag-insert-below";
41755 if (this.lastInsertClass != targetElClass){
41756 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
41757 this.lastInsertClass = targetElClass;
41760 return dragElClass;
41763 onNodeOut : function(n, dd, e, data){
41764 this.removeDropIndicators(n);
41767 onNodeDrop : function(n, dd, e, data){
41768 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
41771 var pt = this.getDropPoint(e, n, dd);
41772 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
41773 if (pt == "below") { insertAt++; }
41774 for (var i = 0; i < data.records.length; i++) {
41775 var r = data.records[i];
41776 var dup = this.store.getById(r.id);
41777 if (dup && (dd != this.dragZone)) {
41778 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
41781 this.store.insert(insertAt++, r.copy());
41783 data.source.isDirtyFlag = true;
41785 this.store.insert(insertAt++, r);
41787 this.isDirtyFlag = true;
41790 this.dragZone.cachedTarget = null;
41794 removeDropIndicators : function(n){
41796 Roo.fly(n).removeClass([
41797 "x-view-drag-insert-above",
41798 "x-view-drag-insert-below"]);
41799 this.lastInsertClass = "_noclass";
41804 * Utility method. Add a delete option to the DDView's context menu.
41805 * @param {String} imageUrl The URL of the "delete" icon image.
41807 setDeletable: function(imageUrl) {
41808 if (!this.singleSelect && !this.multiSelect) {
41809 this.singleSelect = true;
41811 var c = this.getContextMenu();
41812 this.contextMenu.on("itemclick", function(item) {
41815 this.remove(this.getSelectedIndexes());
41819 this.contextMenu.add({
41826 /** Return the context menu for this DDView. */
41827 getContextMenu: function() {
41828 if (!this.contextMenu) {
41829 // Create the View's context menu
41830 this.contextMenu = new Roo.menu.Menu({
41831 id: this.id + "-contextmenu"
41833 this.el.on("contextmenu", this.showContextMenu, this);
41835 return this.contextMenu;
41838 disableContextMenu: function() {
41839 if (this.contextMenu) {
41840 this.el.un("contextmenu", this.showContextMenu, this);
41844 showContextMenu: function(e, item) {
41845 item = this.findItemFromChild(e.getTarget());
41848 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
41849 this.contextMenu.showAt(e.getXY());
41854 * Remove {@link Roo.data.Record}s at the specified indices.
41855 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
41857 remove: function(selectedIndices) {
41858 selectedIndices = [].concat(selectedIndices);
41859 for (var i = 0; i < selectedIndices.length; i++) {
41860 var rec = this.store.getAt(selectedIndices[i]);
41861 this.store.remove(rec);
41866 * Double click fires the event, but also, if this is draggable, and there is only one other
41867 * related DropZone, it transfers the selected node.
41869 onDblClick : function(e){
41870 var item = this.findItemFromChild(e.getTarget());
41872 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
41875 if (this.dragGroup) {
41876 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
41877 while (targets.indexOf(this.dropZone) > -1) {
41878 targets.remove(this.dropZone);
41880 if (targets.length == 1) {
41881 this.dragZone.cachedTarget = null;
41882 var el = Roo.get(targets[0].getEl());
41883 var box = el.getBox(true);
41884 targets[0].onNodeDrop(el.dom, {
41886 xy: [box.x, box.y + box.height - 1]
41887 }, null, this.getDragData(e));
41893 handleSelection: function(e) {
41894 this.dragZone.cachedTarget = null;
41895 var item = this.findItemFromChild(e.getTarget());
41897 this.clearSelections(true);
41900 if (item && (this.multiSelect || this.singleSelect)){
41901 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
41902 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
41903 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
41904 this.unselect(item);
41906 this.select(item, this.multiSelect && e.ctrlKey);
41907 this.lastSelection = item;
41912 onItemClick : function(item, index, e){
41913 if(this.fireEvent("beforeclick", this, index, item, e) === false){
41919 unselect : function(nodeInfo, suppressEvent){
41920 var node = this.getNode(nodeInfo);
41921 if(node && this.isSelected(node)){
41922 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
41923 Roo.fly(node).removeClass(this.selectedClass);
41924 this.selections.remove(node);
41925 if(!suppressEvent){
41926 this.fireEvent("selectionchange", this, this.selections);
41934 * Ext JS Library 1.1.1
41935 * Copyright(c) 2006-2007, Ext JS, LLC.
41937 * Originally Released Under LGPL - original licence link has changed is not relivant.
41940 * <script type="text/javascript">
41944 * @class Roo.LayoutManager
41945 * @extends Roo.util.Observable
41946 * Base class for layout managers.
41948 Roo.LayoutManager = function(container, config){
41949 Roo.LayoutManager.superclass.constructor.call(this);
41950 this.el = Roo.get(container);
41951 // ie scrollbar fix
41952 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
41953 document.body.scroll = "no";
41954 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
41955 this.el.position('relative');
41957 this.id = this.el.id;
41958 this.el.addClass("x-layout-container");
41959 /** false to disable window resize monitoring @type Boolean */
41960 this.monitorWindowResize = true;
41965 * Fires when a layout is performed.
41966 * @param {Roo.LayoutManager} this
41970 * @event regionresized
41971 * Fires when the user resizes a region.
41972 * @param {Roo.LayoutRegion} region The resized region
41973 * @param {Number} newSize The new size (width for east/west, height for north/south)
41975 "regionresized" : true,
41977 * @event regioncollapsed
41978 * Fires when a region is collapsed.
41979 * @param {Roo.LayoutRegion} region The collapsed region
41981 "regioncollapsed" : true,
41983 * @event regionexpanded
41984 * Fires when a region is expanded.
41985 * @param {Roo.LayoutRegion} region The expanded region
41987 "regionexpanded" : true
41989 this.updating = false;
41990 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
41993 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
41995 * Returns true if this layout is currently being updated
41996 * @return {Boolean}
41998 isUpdating : function(){
41999 return this.updating;
42003 * Suspend the LayoutManager from doing auto-layouts while
42004 * making multiple add or remove calls
42006 beginUpdate : function(){
42007 this.updating = true;
42011 * Restore auto-layouts and optionally disable the manager from performing a layout
42012 * @param {Boolean} noLayout true to disable a layout update
42014 endUpdate : function(noLayout){
42015 this.updating = false;
42021 layout: function(){
42025 onRegionResized : function(region, newSize){
42026 this.fireEvent("regionresized", region, newSize);
42030 onRegionCollapsed : function(region){
42031 this.fireEvent("regioncollapsed", region);
42034 onRegionExpanded : function(region){
42035 this.fireEvent("regionexpanded", region);
42039 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
42040 * performs box-model adjustments.
42041 * @return {Object} The size as an object {width: (the width), height: (the height)}
42043 getViewSize : function(){
42045 if(this.el.dom != document.body){
42046 size = this.el.getSize();
42048 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
42050 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
42051 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
42056 * Returns the Element this layout is bound to.
42057 * @return {Roo.Element}
42059 getEl : function(){
42064 * Returns the specified region.
42065 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
42066 * @return {Roo.LayoutRegion}
42068 getRegion : function(target){
42069 return this.regions[target.toLowerCase()];
42072 onWindowResize : function(){
42073 if(this.monitorWindowResize){
42079 * Ext JS Library 1.1.1
42080 * Copyright(c) 2006-2007, Ext JS, LLC.
42082 * Originally Released Under LGPL - original licence link has changed is not relivant.
42085 * <script type="text/javascript">
42088 * @class Roo.BorderLayout
42089 * @extends Roo.LayoutManager
42090 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
42091 * please see: <br><br>
42092 * <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>
42093 * <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>
42096 var layout = new Roo.BorderLayout(document.body, {
42130 preferredTabWidth: 150
42135 var CP = Roo.ContentPanel;
42137 layout.beginUpdate();
42138 layout.add("north", new CP("north", "North"));
42139 layout.add("south", new CP("south", {title: "South", closable: true}));
42140 layout.add("west", new CP("west", {title: "West"}));
42141 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
42142 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
42143 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
42144 layout.getRegion("center").showPanel("center1");
42145 layout.endUpdate();
42148 <b>The container the layout is rendered into can be either the body element or any other element.
42149 If it is not the body element, the container needs to either be an absolute positioned element,
42150 or you will need to add "position:relative" to the css of the container. You will also need to specify
42151 the container size if it is not the body element.</b>
42154 * Create a new BorderLayout
42155 * @param {String/HTMLElement/Element} container The container this layout is bound to
42156 * @param {Object} config Configuration options
42158 Roo.BorderLayout = function(container, config){
42159 config = config || {};
42160 Roo.BorderLayout.superclass.constructor.call(this, container, config);
42161 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
42162 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
42163 var target = this.factory.validRegions[i];
42164 if(config[target]){
42165 this.addRegion(target, config[target]);
42170 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
42172 * Creates and adds a new region if it doesn't already exist.
42173 * @param {String} target The target region key (north, south, east, west or center).
42174 * @param {Object} config The regions config object
42175 * @return {BorderLayoutRegion} The new region
42177 addRegion : function(target, config){
42178 if(!this.regions[target]){
42179 var r = this.factory.create(target, this, config);
42180 this.bindRegion(target, r);
42182 return this.regions[target];
42186 bindRegion : function(name, r){
42187 this.regions[name] = r;
42188 r.on("visibilitychange", this.layout, this);
42189 r.on("paneladded", this.layout, this);
42190 r.on("panelremoved", this.layout, this);
42191 r.on("invalidated", this.layout, this);
42192 r.on("resized", this.onRegionResized, this);
42193 r.on("collapsed", this.onRegionCollapsed, this);
42194 r.on("expanded", this.onRegionExpanded, this);
42198 * Performs a layout update.
42200 layout : function(){
42201 if(this.updating) return;
42202 var size = this.getViewSize();
42203 var w = size.width;
42204 var h = size.height;
42209 //var x = 0, y = 0;
42211 var rs = this.regions;
42212 var north = rs["north"];
42213 var south = rs["south"];
42214 var west = rs["west"];
42215 var east = rs["east"];
42216 var center = rs["center"];
42217 //if(this.hideOnLayout){ // not supported anymore
42218 //c.el.setStyle("display", "none");
42220 if(north && north.isVisible()){
42221 var b = north.getBox();
42222 var m = north.getMargins();
42223 b.width = w - (m.left+m.right);
42226 centerY = b.height + b.y + m.bottom;
42227 centerH -= centerY;
42228 north.updateBox(this.safeBox(b));
42230 if(south && south.isVisible()){
42231 var b = south.getBox();
42232 var m = south.getMargins();
42233 b.width = w - (m.left+m.right);
42235 var totalHeight = (b.height + m.top + m.bottom);
42236 b.y = h - totalHeight + m.top;
42237 centerH -= totalHeight;
42238 south.updateBox(this.safeBox(b));
42240 if(west && west.isVisible()){
42241 var b = west.getBox();
42242 var m = west.getMargins();
42243 b.height = centerH - (m.top+m.bottom);
42245 b.y = centerY + m.top;
42246 var totalWidth = (b.width + m.left + m.right);
42247 centerX += totalWidth;
42248 centerW -= totalWidth;
42249 west.updateBox(this.safeBox(b));
42251 if(east && east.isVisible()){
42252 var b = east.getBox();
42253 var m = east.getMargins();
42254 b.height = centerH - (m.top+m.bottom);
42255 var totalWidth = (b.width + m.left + m.right);
42256 b.x = w - totalWidth + m.left;
42257 b.y = centerY + m.top;
42258 centerW -= totalWidth;
42259 east.updateBox(this.safeBox(b));
42262 var m = center.getMargins();
42264 x: centerX + m.left,
42265 y: centerY + m.top,
42266 width: centerW - (m.left+m.right),
42267 height: centerH - (m.top+m.bottom)
42269 //if(this.hideOnLayout){
42270 //center.el.setStyle("display", "block");
42272 center.updateBox(this.safeBox(centerBox));
42275 this.fireEvent("layout", this);
42279 safeBox : function(box){
42280 box.width = Math.max(0, box.width);
42281 box.height = Math.max(0, box.height);
42286 * Adds a ContentPanel (or subclass) to this layout.
42287 * @param {String} target The target region key (north, south, east, west or center).
42288 * @param {Roo.ContentPanel} panel The panel to add
42289 * @return {Roo.ContentPanel} The added panel
42291 add : function(target, panel){
42293 target = target.toLowerCase();
42294 return this.regions[target].add(panel);
42298 * Remove a ContentPanel (or subclass) to this layout.
42299 * @param {String} target The target region key (north, south, east, west or center).
42300 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
42301 * @return {Roo.ContentPanel} The removed panel
42303 remove : function(target, panel){
42304 target = target.toLowerCase();
42305 return this.regions[target].remove(panel);
42309 * Searches all regions for a panel with the specified id
42310 * @param {String} panelId
42311 * @return {Roo.ContentPanel} The panel or null if it wasn't found
42313 findPanel : function(panelId){
42314 var rs = this.regions;
42315 for(var target in rs){
42316 if(typeof rs[target] != "function"){
42317 var p = rs[target].getPanel(panelId);
42327 * Searches all regions for a panel with the specified id and activates (shows) it.
42328 * @param {String/ContentPanel} panelId The panels id or the panel itself
42329 * @return {Roo.ContentPanel} The shown panel or null
42331 showPanel : function(panelId) {
42332 var rs = this.regions;
42333 for(var target in rs){
42334 var r = rs[target];
42335 if(typeof r != "function"){
42336 if(r.hasPanel(panelId)){
42337 return r.showPanel(panelId);
42345 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
42346 * @param {Roo.state.Provider} provider (optional) An alternate state provider
42348 restoreState : function(provider){
42350 provider = Roo.state.Manager;
42352 var sm = new Roo.LayoutStateManager();
42353 sm.init(this, provider);
42357 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
42358 * object should contain properties for each region to add ContentPanels to, and each property's value should be
42359 * a valid ContentPanel config object. Example:
42361 // Create the main layout
42362 var layout = new Roo.BorderLayout('main-ct', {
42373 // Create and add multiple ContentPanels at once via configs
42376 id: 'source-files',
42378 title:'Ext Source Files',
42391 * @param {Object} regions An object containing ContentPanel configs by region name
42393 batchAdd : function(regions){
42394 this.beginUpdate();
42395 for(var rname in regions){
42396 var lr = this.regions[rname];
42398 this.addTypedPanels(lr, regions[rname]);
42405 addTypedPanels : function(lr, ps){
42406 if(typeof ps == 'string'){
42407 lr.add(new Roo.ContentPanel(ps));
42409 else if(ps instanceof Array){
42410 for(var i =0, len = ps.length; i < len; i++){
42411 this.addTypedPanels(lr, ps[i]);
42414 else if(!ps.events){ // raw config?
42416 delete ps.el; // prevent conflict
42417 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
42419 else { // panel object assumed!
42424 * Adds a xtype elements to the layout.
42428 xtype : 'ContentPanel',
42435 xtype : 'NestedLayoutPanel',
42441 items : [ ... list of content panels or nested layout panels.. ]
42445 * @param {Object} cfg Xtype definition of item to add.
42447 addxtype : function(cfg)
42449 // basically accepts a pannel...
42450 // can accept a layout region..!?!?
42451 // console.log('BorderLayout add ' + cfg.xtype)
42453 if (!cfg.xtype.match(/Panel$/)) {
42457 var region = cfg.region;
42463 xitems = cfg.items;
42470 case 'ContentPanel': // ContentPanel (el, cfg)
42471 if(cfg.autoCreate) {
42472 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42474 var el = this.el.createChild();
42475 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
42478 this.add(region, ret);
42482 case 'TreePanel': // our new panel!
42483 cfg.el = this.el.createChild();
42484 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42485 this.add(region, ret);
42488 case 'NestedLayoutPanel':
42489 // create a new Layout (which is a Border Layout...
42490 var el = this.el.createChild();
42491 var clayout = cfg.layout;
42493 clayout.items = clayout.items || [];
42494 // replace this exitems with the clayout ones..
42495 xitems = clayout.items;
42498 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
42499 cfg.background = false;
42501 var layout = new Roo.BorderLayout(el, clayout);
42503 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
42504 //console.log('adding nested layout panel ' + cfg.toSource());
42505 this.add(region, ret);
42511 // needs grid and region
42513 //var el = this.getRegion(region).el.createChild();
42514 var el = this.el.createChild();
42515 // create the grid first...
42517 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
42519 if (region == 'center' && this.active ) {
42520 cfg.background = false;
42522 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
42524 this.add(region, ret);
42525 if (cfg.background) {
42526 ret.on('activate', function(gp) {
42527 if (!gp.grid.rendered) {
42540 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
42542 // GridPanel (grid, cfg)
42545 this.beginUpdate();
42547 Roo.each(xitems, function(i) {
42557 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
42558 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
42559 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
42560 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
42563 var CP = Roo.ContentPanel;
42565 var layout = Roo.BorderLayout.create({
42569 panels: [new CP("north", "North")]
42578 panels: [new CP("west", {title: "West"})]
42587 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
42596 panels: [new CP("south", {title: "South", closable: true})]
42603 preferredTabWidth: 150,
42605 new CP("center1", {title: "Close Me", closable: true}),
42606 new CP("center2", {title: "Center Panel", closable: false})
42611 layout.getRegion("center").showPanel("center1");
42616 Roo.BorderLayout.create = function(config, targetEl){
42617 var layout = new Roo.BorderLayout(targetEl || document.body, config);
42618 layout.beginUpdate();
42619 var regions = Roo.BorderLayout.RegionFactory.validRegions;
42620 for(var j = 0, jlen = regions.length; j < jlen; j++){
42621 var lr = regions[j];
42622 if(layout.regions[lr] && config[lr].panels){
42623 var r = layout.regions[lr];
42624 var ps = config[lr].panels;
42625 layout.addTypedPanels(r, ps);
42628 layout.endUpdate();
42633 Roo.BorderLayout.RegionFactory = {
42635 validRegions : ["north","south","east","west","center"],
42638 create : function(target, mgr, config){
42639 target = target.toLowerCase();
42640 if(config.lightweight || config.basic){
42641 return new Roo.BasicLayoutRegion(mgr, config, target);
42645 return new Roo.NorthLayoutRegion(mgr, config);
42647 return new Roo.SouthLayoutRegion(mgr, config);
42649 return new Roo.EastLayoutRegion(mgr, config);
42651 return new Roo.WestLayoutRegion(mgr, config);
42653 return new Roo.CenterLayoutRegion(mgr, config);
42655 throw 'Layout region "'+target+'" not supported.';
42659 * Ext JS Library 1.1.1
42660 * Copyright(c) 2006-2007, Ext JS, LLC.
42662 * Originally Released Under LGPL - original licence link has changed is not relivant.
42665 * <script type="text/javascript">
42669 * @class Roo.BasicLayoutRegion
42670 * @extends Roo.util.Observable
42671 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
42672 * and does not have a titlebar, tabs or any other features. All it does is size and position
42673 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
42675 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
42677 this.position = pos;
42680 * @scope Roo.BasicLayoutRegion
42684 * @event beforeremove
42685 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
42686 * @param {Roo.LayoutRegion} this
42687 * @param {Roo.ContentPanel} panel The panel
42688 * @param {Object} e The cancel event object
42690 "beforeremove" : true,
42692 * @event invalidated
42693 * Fires when the layout for this region is changed.
42694 * @param {Roo.LayoutRegion} this
42696 "invalidated" : true,
42698 * @event visibilitychange
42699 * Fires when this region is shown or hidden
42700 * @param {Roo.LayoutRegion} this
42701 * @param {Boolean} visibility true or false
42703 "visibilitychange" : true,
42705 * @event paneladded
42706 * Fires when a panel is added.
42707 * @param {Roo.LayoutRegion} this
42708 * @param {Roo.ContentPanel} panel The panel
42710 "paneladded" : true,
42712 * @event panelremoved
42713 * Fires when a panel is removed.
42714 * @param {Roo.LayoutRegion} this
42715 * @param {Roo.ContentPanel} panel The panel
42717 "panelremoved" : true,
42720 * Fires when this region is collapsed.
42721 * @param {Roo.LayoutRegion} this
42723 "collapsed" : true,
42726 * Fires when this region is expanded.
42727 * @param {Roo.LayoutRegion} this
42732 * Fires when this region is slid into view.
42733 * @param {Roo.LayoutRegion} this
42735 "slideshow" : true,
42738 * Fires when this region slides out of view.
42739 * @param {Roo.LayoutRegion} this
42741 "slidehide" : true,
42743 * @event panelactivated
42744 * Fires when a panel is activated.
42745 * @param {Roo.LayoutRegion} this
42746 * @param {Roo.ContentPanel} panel The activated panel
42748 "panelactivated" : true,
42751 * Fires when the user resizes this region.
42752 * @param {Roo.LayoutRegion} this
42753 * @param {Number} newSize The new size (width for east/west, height for north/south)
42757 /** A collection of panels in this region. @type Roo.util.MixedCollection */
42758 this.panels = new Roo.util.MixedCollection();
42759 this.panels.getKey = this.getPanelId.createDelegate(this);
42761 this.activePanel = null;
42762 // ensure listeners are added...
42764 if (config.listeners || config.events) {
42765 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
42766 listeners : config.listeners || {},
42767 events : config.events || {}
42771 if(skipConfig !== true){
42772 this.applyConfig(config);
42776 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
42777 getPanelId : function(p){
42781 applyConfig : function(config){
42782 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
42783 this.config = config;
42788 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
42789 * the width, for horizontal (north, south) the height.
42790 * @param {Number} newSize The new width or height
42792 resizeTo : function(newSize){
42793 var el = this.el ? this.el :
42794 (this.activePanel ? this.activePanel.getEl() : null);
42796 switch(this.position){
42799 el.setWidth(newSize);
42800 this.fireEvent("resized", this, newSize);
42804 el.setHeight(newSize);
42805 this.fireEvent("resized", this, newSize);
42811 getBox : function(){
42812 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
42815 getMargins : function(){
42816 return this.margins;
42819 updateBox : function(box){
42821 var el = this.activePanel.getEl();
42822 el.dom.style.left = box.x + "px";
42823 el.dom.style.top = box.y + "px";
42824 this.activePanel.setSize(box.width, box.height);
42828 * Returns the container element for this region.
42829 * @return {Roo.Element}
42831 getEl : function(){
42832 return this.activePanel;
42836 * Returns true if this region is currently visible.
42837 * @return {Boolean}
42839 isVisible : function(){
42840 return this.activePanel ? true : false;
42843 setActivePanel : function(panel){
42844 panel = this.getPanel(panel);
42845 if(this.activePanel && this.activePanel != panel){
42846 this.activePanel.setActiveState(false);
42847 this.activePanel.getEl().setLeftTop(-10000,-10000);
42849 this.activePanel = panel;
42850 panel.setActiveState(true);
42852 panel.setSize(this.box.width, this.box.height);
42854 this.fireEvent("panelactivated", this, panel);
42855 this.fireEvent("invalidated");
42859 * Show the specified panel.
42860 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
42861 * @return {Roo.ContentPanel} The shown panel or null
42863 showPanel : function(panel){
42864 if(panel = this.getPanel(panel)){
42865 this.setActivePanel(panel);
42871 * Get the active panel for this region.
42872 * @return {Roo.ContentPanel} The active panel or null
42874 getActivePanel : function(){
42875 return this.activePanel;
42879 * Add the passed ContentPanel(s)
42880 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
42881 * @return {Roo.ContentPanel} The panel added (if only one was added)
42883 add : function(panel){
42884 if(arguments.length > 1){
42885 for(var i = 0, len = arguments.length; i < len; i++) {
42886 this.add(arguments[i]);
42890 if(this.hasPanel(panel)){
42891 this.showPanel(panel);
42894 var el = panel.getEl();
42895 if(el.dom.parentNode != this.mgr.el.dom){
42896 this.mgr.el.dom.appendChild(el.dom);
42898 if(panel.setRegion){
42899 panel.setRegion(this);
42901 this.panels.add(panel);
42902 el.setStyle("position", "absolute");
42903 if(!panel.background){
42904 this.setActivePanel(panel);
42905 if(this.config.initialSize && this.panels.getCount()==1){
42906 this.resizeTo(this.config.initialSize);
42909 this.fireEvent("paneladded", this, panel);
42914 * Returns true if the panel is in this region.
42915 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
42916 * @return {Boolean}
42918 hasPanel : function(panel){
42919 if(typeof panel == "object"){ // must be panel obj
42920 panel = panel.getId();
42922 return this.getPanel(panel) ? true : false;
42926 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
42927 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
42928 * @param {Boolean} preservePanel Overrides the config preservePanel option
42929 * @return {Roo.ContentPanel} The panel that was removed
42931 remove : function(panel, preservePanel){
42932 panel = this.getPanel(panel);
42937 this.fireEvent("beforeremove", this, panel, e);
42938 if(e.cancel === true){
42941 var panelId = panel.getId();
42942 this.panels.removeKey(panelId);
42947 * Returns the panel specified or null if it's not in this region.
42948 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
42949 * @return {Roo.ContentPanel}
42951 getPanel : function(id){
42952 if(typeof id == "object"){ // must be panel obj
42955 return this.panels.get(id);
42959 * Returns this regions position (north/south/east/west/center).
42962 getPosition: function(){
42963 return this.position;
42967 * Ext JS Library 1.1.1
42968 * Copyright(c) 2006-2007, Ext JS, LLC.
42970 * Originally Released Under LGPL - original licence link has changed is not relivant.
42973 * <script type="text/javascript">
42977 * @class Roo.LayoutRegion
42978 * @extends Roo.BasicLayoutRegion
42979 * This class represents a region in a layout manager.
42980 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
42981 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
42982 * @cfg {Boolean} floatable False to disable floating (defaults to true)
42983 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
42984 * @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})
42985 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
42986 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
42987 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
42988 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
42989 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
42990 * @cfg {String} title The title for the region (overrides panel titles)
42991 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
42992 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
42993 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
42994 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
42995 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
42996 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
42997 * the space available, similar to FireFox 1.5 tabs (defaults to false)
42998 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
42999 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
43000 * @cfg {Boolean} showPin True to show a pin button
43001 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
43002 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
43003 * @cfg {Boolean} disableTabTips True to disable tab tooltips
43004 * @cfg {Number} width For East/West panels
43005 * @cfg {Number} height For North/South panels
43006 * @cfg {Boolean} split To show the splitter
43008 Roo.LayoutRegion = function(mgr, config, pos){
43009 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
43010 var dh = Roo.DomHelper;
43011 /** This region's container element
43012 * @type Roo.Element */
43013 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
43014 /** This region's title element
43015 * @type Roo.Element */
43017 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
43018 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
43019 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
43021 this.titleEl.enableDisplayMode();
43022 /** This region's title text element
43023 * @type HTMLElement */
43024 this.titleTextEl = this.titleEl.dom.firstChild;
43025 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
43026 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
43027 this.closeBtn.enableDisplayMode();
43028 this.closeBtn.on("click", this.closeClicked, this);
43029 this.closeBtn.hide();
43031 this.createBody(config);
43032 this.visible = true;
43033 this.collapsed = false;
43035 if(config.hideWhenEmpty){
43037 this.on("paneladded", this.validateVisibility, this);
43038 this.on("panelremoved", this.validateVisibility, this);
43040 this.applyConfig(config);
43043 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
43045 createBody : function(){
43046 /** This region's body element
43047 * @type Roo.Element */
43048 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
43051 applyConfig : function(c){
43052 if(c.collapsible && this.position != "center" && !this.collapsedEl){
43053 var dh = Roo.DomHelper;
43054 if(c.titlebar !== false){
43055 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
43056 this.collapseBtn.on("click", this.collapse, this);
43057 this.collapseBtn.enableDisplayMode();
43059 if(c.showPin === true || this.showPin){
43060 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
43061 this.stickBtn.enableDisplayMode();
43062 this.stickBtn.on("click", this.expand, this);
43063 this.stickBtn.hide();
43066 /** This region's collapsed element
43067 * @type Roo.Element */
43068 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
43069 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
43071 if(c.floatable !== false){
43072 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
43073 this.collapsedEl.on("click", this.collapseClick, this);
43076 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
43077 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
43078 id: "message", unselectable: "on", style:{"float":"left"}});
43079 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
43081 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
43082 this.expandBtn.on("click", this.expand, this);
43084 if(this.collapseBtn){
43085 this.collapseBtn.setVisible(c.collapsible == true);
43087 this.cmargins = c.cmargins || this.cmargins ||
43088 (this.position == "west" || this.position == "east" ?
43089 {top: 0, left: 2, right:2, bottom: 0} :
43090 {top: 2, left: 0, right:0, bottom: 2});
43091 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43092 this.bottomTabs = c.tabPosition != "top";
43093 this.autoScroll = c.autoScroll || false;
43094 if(this.autoScroll){
43095 this.bodyEl.setStyle("overflow", "auto");
43097 this.bodyEl.setStyle("overflow", "hidden");
43099 //if(c.titlebar !== false){
43100 if((!c.titlebar && !c.title) || c.titlebar === false){
43101 this.titleEl.hide();
43103 this.titleEl.show();
43105 this.titleTextEl.innerHTML = c.title;
43109 this.duration = c.duration || .30;
43110 this.slideDuration = c.slideDuration || .45;
43113 this.collapse(true);
43120 * Returns true if this region is currently visible.
43121 * @return {Boolean}
43123 isVisible : function(){
43124 return this.visible;
43128 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
43129 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
43131 setCollapsedTitle : function(title){
43132 title = title || " ";
43133 if(this.collapsedTitleTextEl){
43134 this.collapsedTitleTextEl.innerHTML = title;
43138 getBox : function(){
43140 if(!this.collapsed){
43141 b = this.el.getBox(false, true);
43143 b = this.collapsedEl.getBox(false, true);
43148 getMargins : function(){
43149 return this.collapsed ? this.cmargins : this.margins;
43152 highlight : function(){
43153 this.el.addClass("x-layout-panel-dragover");
43156 unhighlight : function(){
43157 this.el.removeClass("x-layout-panel-dragover");
43160 updateBox : function(box){
43162 if(!this.collapsed){
43163 this.el.dom.style.left = box.x + "px";
43164 this.el.dom.style.top = box.y + "px";
43165 this.updateBody(box.width, box.height);
43167 this.collapsedEl.dom.style.left = box.x + "px";
43168 this.collapsedEl.dom.style.top = box.y + "px";
43169 this.collapsedEl.setSize(box.width, box.height);
43172 this.tabs.autoSizeTabs();
43176 updateBody : function(w, h){
43178 this.el.setWidth(w);
43179 w -= this.el.getBorderWidth("rl");
43180 if(this.config.adjustments){
43181 w += this.config.adjustments[0];
43185 this.el.setHeight(h);
43186 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
43187 h -= this.el.getBorderWidth("tb");
43188 if(this.config.adjustments){
43189 h += this.config.adjustments[1];
43191 this.bodyEl.setHeight(h);
43193 h = this.tabs.syncHeight(h);
43196 if(this.panelSize){
43197 w = w !== null ? w : this.panelSize.width;
43198 h = h !== null ? h : this.panelSize.height;
43200 if(this.activePanel){
43201 var el = this.activePanel.getEl();
43202 w = w !== null ? w : el.getWidth();
43203 h = h !== null ? h : el.getHeight();
43204 this.panelSize = {width: w, height: h};
43205 this.activePanel.setSize(w, h);
43207 if(Roo.isIE && this.tabs){
43208 this.tabs.el.repaint();
43213 * Returns the container element for this region.
43214 * @return {Roo.Element}
43216 getEl : function(){
43221 * Hides this region.
43224 if(!this.collapsed){
43225 this.el.dom.style.left = "-2000px";
43228 this.collapsedEl.dom.style.left = "-2000px";
43229 this.collapsedEl.hide();
43231 this.visible = false;
43232 this.fireEvent("visibilitychange", this, false);
43236 * Shows this region if it was previously hidden.
43239 if(!this.collapsed){
43242 this.collapsedEl.show();
43244 this.visible = true;
43245 this.fireEvent("visibilitychange", this, true);
43248 closeClicked : function(){
43249 if(this.activePanel){
43250 this.remove(this.activePanel);
43254 collapseClick : function(e){
43256 e.stopPropagation();
43259 e.stopPropagation();
43265 * Collapses this region.
43266 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
43268 collapse : function(skipAnim){
43269 if(this.collapsed) return;
43270 this.collapsed = true;
43272 this.split.el.hide();
43274 if(this.config.animate && skipAnim !== true){
43275 this.fireEvent("invalidated", this);
43276 this.animateCollapse();
43278 this.el.setLocation(-20000,-20000);
43280 this.collapsedEl.show();
43281 this.fireEvent("collapsed", this);
43282 this.fireEvent("invalidated", this);
43286 animateCollapse : function(){
43291 * Expands this region if it was previously collapsed.
43292 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
43293 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
43295 expand : function(e, skipAnim){
43296 if(e) e.stopPropagation();
43297 if(!this.collapsed || this.el.hasActiveFx()) return;
43299 this.afterSlideIn();
43302 this.collapsed = false;
43303 if(this.config.animate && skipAnim !== true){
43304 this.animateExpand();
43308 this.split.el.show();
43310 this.collapsedEl.setLocation(-2000,-2000);
43311 this.collapsedEl.hide();
43312 this.fireEvent("invalidated", this);
43313 this.fireEvent("expanded", this);
43317 animateExpand : function(){
43321 initTabs : function(){
43322 this.bodyEl.setStyle("overflow", "hidden");
43323 var ts = new Roo.TabPanel(this.bodyEl.dom, {
43324 tabPosition: this.bottomTabs ? 'bottom' : 'top',
43325 disableTooltips: this.config.disableTabTips
43327 if(this.config.hideTabs){
43328 ts.stripWrap.setDisplayed(false);
43331 ts.resizeTabs = this.config.resizeTabs === true;
43332 ts.minTabWidth = this.config.minTabWidth || 40;
43333 ts.maxTabWidth = this.config.maxTabWidth || 250;
43334 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
43335 ts.monitorResize = false;
43336 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43337 ts.bodyEl.addClass('x-layout-tabs-body');
43338 this.panels.each(this.initPanelAsTab, this);
43341 initPanelAsTab : function(panel){
43342 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
43343 this.config.closeOnTab && panel.isClosable());
43344 if(panel.tabTip !== undefined){
43345 ti.setTooltip(panel.tabTip);
43347 ti.on("activate", function(){
43348 this.setActivePanel(panel);
43350 if(this.config.closeOnTab){
43351 ti.on("beforeclose", function(t, e){
43353 this.remove(panel);
43359 updatePanelTitle : function(panel, title){
43360 if(this.activePanel == panel){
43361 this.updateTitle(title);
43364 var ti = this.tabs.getTab(panel.getEl().id);
43366 if(panel.tabTip !== undefined){
43367 ti.setTooltip(panel.tabTip);
43372 updateTitle : function(title){
43373 if(this.titleTextEl && !this.config.title){
43374 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
43378 setActivePanel : function(panel){
43379 panel = this.getPanel(panel);
43380 if(this.activePanel && this.activePanel != panel){
43381 this.activePanel.setActiveState(false);
43383 this.activePanel = panel;
43384 panel.setActiveState(true);
43385 if(this.panelSize){
43386 panel.setSize(this.panelSize.width, this.panelSize.height);
43389 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
43391 this.updateTitle(panel.getTitle());
43393 this.fireEvent("invalidated", this);
43395 this.fireEvent("panelactivated", this, panel);
43399 * Shows the specified panel.
43400 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
43401 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
43403 showPanel : function(panel){
43404 if(panel = this.getPanel(panel)){
43406 var tab = this.tabs.getTab(panel.getEl().id);
43407 if(tab.isHidden()){
43408 this.tabs.unhideTab(tab.id);
43412 this.setActivePanel(panel);
43419 * Get the active panel for this region.
43420 * @return {Roo.ContentPanel} The active panel or null
43422 getActivePanel : function(){
43423 return this.activePanel;
43426 validateVisibility : function(){
43427 if(this.panels.getCount() < 1){
43428 this.updateTitle(" ");
43429 this.closeBtn.hide();
43432 if(!this.isVisible()){
43439 * Adds the passed ContentPanel(s) to this region.
43440 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43441 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
43443 add : function(panel){
43444 if(arguments.length > 1){
43445 for(var i = 0, len = arguments.length; i < len; i++) {
43446 this.add(arguments[i]);
43450 if(this.hasPanel(panel)){
43451 this.showPanel(panel);
43454 panel.setRegion(this);
43455 this.panels.add(panel);
43456 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
43457 this.bodyEl.dom.appendChild(panel.getEl().dom);
43458 if(panel.background !== true){
43459 this.setActivePanel(panel);
43461 this.fireEvent("paneladded", this, panel);
43467 this.initPanelAsTab(panel);
43469 if(panel.background !== true){
43470 this.tabs.activate(panel.getEl().id);
43472 this.fireEvent("paneladded", this, panel);
43477 * Hides the tab for the specified panel.
43478 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43480 hidePanel : function(panel){
43481 if(this.tabs && (panel = this.getPanel(panel))){
43482 this.tabs.hideTab(panel.getEl().id);
43487 * Unhides the tab for a previously hidden panel.
43488 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43490 unhidePanel : function(panel){
43491 if(this.tabs && (panel = this.getPanel(panel))){
43492 this.tabs.unhideTab(panel.getEl().id);
43496 clearPanels : function(){
43497 while(this.panels.getCount() > 0){
43498 this.remove(this.panels.first());
43503 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
43504 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43505 * @param {Boolean} preservePanel Overrides the config preservePanel option
43506 * @return {Roo.ContentPanel} The panel that was removed
43508 remove : function(panel, preservePanel){
43509 panel = this.getPanel(panel);
43514 this.fireEvent("beforeremove", this, panel, e);
43515 if(e.cancel === true){
43518 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
43519 var panelId = panel.getId();
43520 this.panels.removeKey(panelId);
43522 document.body.appendChild(panel.getEl().dom);
43525 this.tabs.removeTab(panel.getEl().id);
43526 }else if (!preservePanel){
43527 this.bodyEl.dom.removeChild(panel.getEl().dom);
43529 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
43530 var p = this.panels.first();
43531 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
43532 tempEl.appendChild(p.getEl().dom);
43533 this.bodyEl.update("");
43534 this.bodyEl.dom.appendChild(p.getEl().dom);
43536 this.updateTitle(p.getTitle());
43538 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43539 this.setActivePanel(p);
43541 panel.setRegion(null);
43542 if(this.activePanel == panel){
43543 this.activePanel = null;
43545 if(this.config.autoDestroy !== false && preservePanel !== true){
43546 try{panel.destroy();}catch(e){}
43548 this.fireEvent("panelremoved", this, panel);
43553 * Returns the TabPanel component used by this region
43554 * @return {Roo.TabPanel}
43556 getTabs : function(){
43560 createTool : function(parentEl, className){
43561 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
43562 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
43563 btn.addClassOnOver("x-layout-tools-button-over");
43568 * Ext JS Library 1.1.1
43569 * Copyright(c) 2006-2007, Ext JS, LLC.
43571 * Originally Released Under LGPL - original licence link has changed is not relivant.
43574 * <script type="text/javascript">
43580 * @class Roo.SplitLayoutRegion
43581 * @extends Roo.LayoutRegion
43582 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
43584 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
43585 this.cursor = cursor;
43586 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
43589 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
43590 splitTip : "Drag to resize.",
43591 collapsibleSplitTip : "Drag to resize. Double click to hide.",
43592 useSplitTips : false,
43594 applyConfig : function(config){
43595 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
43598 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
43599 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
43600 /** The SplitBar for this region
43601 * @type Roo.SplitBar */
43602 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
43603 this.split.on("moved", this.onSplitMove, this);
43604 this.split.useShim = config.useShim === true;
43605 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
43606 if(this.useSplitTips){
43607 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
43609 if(config.collapsible){
43610 this.split.el.on("dblclick", this.collapse, this);
43613 if(typeof config.minSize != "undefined"){
43614 this.split.minSize = config.minSize;
43616 if(typeof config.maxSize != "undefined"){
43617 this.split.maxSize = config.maxSize;
43619 if(config.hideWhenEmpty || config.hidden || config.collapsed){
43620 this.hideSplitter();
43625 getHMaxSize : function(){
43626 var cmax = this.config.maxSize || 10000;
43627 var center = this.mgr.getRegion("center");
43628 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
43631 getVMaxSize : function(){
43632 var cmax = this.config.maxSize || 10000;
43633 var center = this.mgr.getRegion("center");
43634 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
43637 onSplitMove : function(split, newSize){
43638 this.fireEvent("resized", this, newSize);
43642 * Returns the {@link Roo.SplitBar} for this region.
43643 * @return {Roo.SplitBar}
43645 getSplitBar : function(){
43650 this.hideSplitter();
43651 Roo.SplitLayoutRegion.superclass.hide.call(this);
43654 hideSplitter : function(){
43656 this.split.el.setLocation(-2000,-2000);
43657 this.split.el.hide();
43663 this.split.el.show();
43665 Roo.SplitLayoutRegion.superclass.show.call(this);
43668 beforeSlide: function(){
43669 if(Roo.isGecko){// firefox overflow auto bug workaround
43670 this.bodyEl.clip();
43671 if(this.tabs) this.tabs.bodyEl.clip();
43672 if(this.activePanel){
43673 this.activePanel.getEl().clip();
43675 if(this.activePanel.beforeSlide){
43676 this.activePanel.beforeSlide();
43682 afterSlide : function(){
43683 if(Roo.isGecko){// firefox overflow auto bug workaround
43684 this.bodyEl.unclip();
43685 if(this.tabs) this.tabs.bodyEl.unclip();
43686 if(this.activePanel){
43687 this.activePanel.getEl().unclip();
43688 if(this.activePanel.afterSlide){
43689 this.activePanel.afterSlide();
43695 initAutoHide : function(){
43696 if(this.autoHide !== false){
43697 if(!this.autoHideHd){
43698 var st = new Roo.util.DelayedTask(this.slideIn, this);
43699 this.autoHideHd = {
43700 "mouseout": function(e){
43701 if(!e.within(this.el, true)){
43705 "mouseover" : function(e){
43711 this.el.on(this.autoHideHd);
43715 clearAutoHide : function(){
43716 if(this.autoHide !== false){
43717 this.el.un("mouseout", this.autoHideHd.mouseout);
43718 this.el.un("mouseover", this.autoHideHd.mouseover);
43722 clearMonitor : function(){
43723 Roo.get(document).un("click", this.slideInIf, this);
43726 // these names are backwards but not changed for compat
43727 slideOut : function(){
43728 if(this.isSlid || this.el.hasActiveFx()){
43731 this.isSlid = true;
43732 if(this.collapseBtn){
43733 this.collapseBtn.hide();
43735 this.closeBtnState = this.closeBtn.getStyle('display');
43736 this.closeBtn.hide();
43738 this.stickBtn.show();
43741 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
43742 this.beforeSlide();
43743 this.el.setStyle("z-index", 10001);
43744 this.el.slideIn(this.getSlideAnchor(), {
43745 callback: function(){
43747 this.initAutoHide();
43748 Roo.get(document).on("click", this.slideInIf, this);
43749 this.fireEvent("slideshow", this);
43756 afterSlideIn : function(){
43757 this.clearAutoHide();
43758 this.isSlid = false;
43759 this.clearMonitor();
43760 this.el.setStyle("z-index", "");
43761 if(this.collapseBtn){
43762 this.collapseBtn.show();
43764 this.closeBtn.setStyle('display', this.closeBtnState);
43766 this.stickBtn.hide();
43768 this.fireEvent("slidehide", this);
43771 slideIn : function(cb){
43772 if(!this.isSlid || this.el.hasActiveFx()){
43776 this.isSlid = false;
43777 this.beforeSlide();
43778 this.el.slideOut(this.getSlideAnchor(), {
43779 callback: function(){
43780 this.el.setLeftTop(-10000, -10000);
43782 this.afterSlideIn();
43790 slideInIf : function(e){
43791 if(!e.within(this.el)){
43796 animateCollapse : function(){
43797 this.beforeSlide();
43798 this.el.setStyle("z-index", 20000);
43799 var anchor = this.getSlideAnchor();
43800 this.el.slideOut(anchor, {
43801 callback : function(){
43802 this.el.setStyle("z-index", "");
43803 this.collapsedEl.slideIn(anchor, {duration:.3});
43805 this.el.setLocation(-10000,-10000);
43807 this.fireEvent("collapsed", this);
43814 animateExpand : function(){
43815 this.beforeSlide();
43816 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
43817 this.el.setStyle("z-index", 20000);
43818 this.collapsedEl.hide({
43821 this.el.slideIn(this.getSlideAnchor(), {
43822 callback : function(){
43823 this.el.setStyle("z-index", "");
43826 this.split.el.show();
43828 this.fireEvent("invalidated", this);
43829 this.fireEvent("expanded", this);
43857 getAnchor : function(){
43858 return this.anchors[this.position];
43861 getCollapseAnchor : function(){
43862 return this.canchors[this.position];
43865 getSlideAnchor : function(){
43866 return this.sanchors[this.position];
43869 getAlignAdj : function(){
43870 var cm = this.cmargins;
43871 switch(this.position){
43887 getExpandAdj : function(){
43888 var c = this.collapsedEl, cm = this.cmargins;
43889 switch(this.position){
43891 return [-(cm.right+c.getWidth()+cm.left), 0];
43894 return [cm.right+c.getWidth()+cm.left, 0];
43897 return [0, -(cm.top+cm.bottom+c.getHeight())];
43900 return [0, cm.top+cm.bottom+c.getHeight()];
43906 * Ext JS Library 1.1.1
43907 * Copyright(c) 2006-2007, Ext JS, LLC.
43909 * Originally Released Under LGPL - original licence link has changed is not relivant.
43912 * <script type="text/javascript">
43915 * These classes are private internal classes
43917 Roo.CenterLayoutRegion = function(mgr, config){
43918 Roo.LayoutRegion.call(this, mgr, config, "center");
43919 this.visible = true;
43920 this.minWidth = config.minWidth || 20;
43921 this.minHeight = config.minHeight || 20;
43924 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
43926 // center panel can't be hidden
43930 // center panel can't be hidden
43933 getMinWidth: function(){
43934 return this.minWidth;
43937 getMinHeight: function(){
43938 return this.minHeight;
43943 Roo.NorthLayoutRegion = function(mgr, config){
43944 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
43946 this.split.placement = Roo.SplitBar.TOP;
43947 this.split.orientation = Roo.SplitBar.VERTICAL;
43948 this.split.el.addClass("x-layout-split-v");
43950 var size = config.initialSize || config.height;
43951 if(typeof size != "undefined"){
43952 this.el.setHeight(size);
43955 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
43956 orientation: Roo.SplitBar.VERTICAL,
43957 getBox : function(){
43958 if(this.collapsed){
43959 return this.collapsedEl.getBox();
43961 var box = this.el.getBox();
43963 box.height += this.split.el.getHeight();
43968 updateBox : function(box){
43969 if(this.split && !this.collapsed){
43970 box.height -= this.split.el.getHeight();
43971 this.split.el.setLeft(box.x);
43972 this.split.el.setTop(box.y+box.height);
43973 this.split.el.setWidth(box.width);
43975 if(this.collapsed){
43976 this.updateBody(box.width, null);
43978 Roo.LayoutRegion.prototype.updateBox.call(this, box);
43982 Roo.SouthLayoutRegion = function(mgr, config){
43983 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
43985 this.split.placement = Roo.SplitBar.BOTTOM;
43986 this.split.orientation = Roo.SplitBar.VERTICAL;
43987 this.split.el.addClass("x-layout-split-v");
43989 var size = config.initialSize || config.height;
43990 if(typeof size != "undefined"){
43991 this.el.setHeight(size);
43994 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
43995 orientation: Roo.SplitBar.VERTICAL,
43996 getBox : function(){
43997 if(this.collapsed){
43998 return this.collapsedEl.getBox();
44000 var box = this.el.getBox();
44002 var sh = this.split.el.getHeight();
44009 updateBox : function(box){
44010 if(this.split && !this.collapsed){
44011 var sh = this.split.el.getHeight();
44014 this.split.el.setLeft(box.x);
44015 this.split.el.setTop(box.y-sh);
44016 this.split.el.setWidth(box.width);
44018 if(this.collapsed){
44019 this.updateBody(box.width, null);
44021 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44025 Roo.EastLayoutRegion = function(mgr, config){
44026 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
44028 this.split.placement = Roo.SplitBar.RIGHT;
44029 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44030 this.split.el.addClass("x-layout-split-h");
44032 var size = config.initialSize || config.width;
44033 if(typeof size != "undefined"){
44034 this.el.setWidth(size);
44037 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
44038 orientation: Roo.SplitBar.HORIZONTAL,
44039 getBox : function(){
44040 if(this.collapsed){
44041 return this.collapsedEl.getBox();
44043 var box = this.el.getBox();
44045 var sw = this.split.el.getWidth();
44052 updateBox : function(box){
44053 if(this.split && !this.collapsed){
44054 var sw = this.split.el.getWidth();
44056 this.split.el.setLeft(box.x);
44057 this.split.el.setTop(box.y);
44058 this.split.el.setHeight(box.height);
44061 if(this.collapsed){
44062 this.updateBody(null, box.height);
44064 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44068 Roo.WestLayoutRegion = function(mgr, config){
44069 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
44071 this.split.placement = Roo.SplitBar.LEFT;
44072 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44073 this.split.el.addClass("x-layout-split-h");
44075 var size = config.initialSize || config.width;
44076 if(typeof size != "undefined"){
44077 this.el.setWidth(size);
44080 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
44081 orientation: Roo.SplitBar.HORIZONTAL,
44082 getBox : function(){
44083 if(this.collapsed){
44084 return this.collapsedEl.getBox();
44086 var box = this.el.getBox();
44088 box.width += this.split.el.getWidth();
44093 updateBox : function(box){
44094 if(this.split && !this.collapsed){
44095 var sw = this.split.el.getWidth();
44097 this.split.el.setLeft(box.x+box.width);
44098 this.split.el.setTop(box.y);
44099 this.split.el.setHeight(box.height);
44101 if(this.collapsed){
44102 this.updateBody(null, box.height);
44104 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44109 * Ext JS Library 1.1.1
44110 * Copyright(c) 2006-2007, Ext JS, LLC.
44112 * Originally Released Under LGPL - original licence link has changed is not relivant.
44115 * <script type="text/javascript">
44120 * Private internal class for reading and applying state
44122 Roo.LayoutStateManager = function(layout){
44123 // default empty state
44132 Roo.LayoutStateManager.prototype = {
44133 init : function(layout, provider){
44134 this.provider = provider;
44135 var state = provider.get(layout.id+"-layout-state");
44137 var wasUpdating = layout.isUpdating();
44139 layout.beginUpdate();
44141 for(var key in state){
44142 if(typeof state[key] != "function"){
44143 var rstate = state[key];
44144 var r = layout.getRegion(key);
44147 r.resizeTo(rstate.size);
44149 if(rstate.collapsed == true){
44152 r.expand(null, true);
44158 layout.endUpdate();
44160 this.state = state;
44162 this.layout = layout;
44163 layout.on("regionresized", this.onRegionResized, this);
44164 layout.on("regioncollapsed", this.onRegionCollapsed, this);
44165 layout.on("regionexpanded", this.onRegionExpanded, this);
44168 storeState : function(){
44169 this.provider.set(this.layout.id+"-layout-state", this.state);
44172 onRegionResized : function(region, newSize){
44173 this.state[region.getPosition()].size = newSize;
44177 onRegionCollapsed : function(region){
44178 this.state[region.getPosition()].collapsed = true;
44182 onRegionExpanded : function(region){
44183 this.state[region.getPosition()].collapsed = false;
44188 * Ext JS Library 1.1.1
44189 * Copyright(c) 2006-2007, Ext JS, LLC.
44191 * Originally Released Under LGPL - original licence link has changed is not relivant.
44194 * <script type="text/javascript">
44197 * @class Roo.ContentPanel
44198 * @extends Roo.util.Observable
44199 * A basic ContentPanel element.
44200 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
44201 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
44202 * @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
44203 * @cfg {Boolean} closable True if the panel can be closed/removed
44204 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
44205 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
44206 * @cfg {Toolbar} toolbar A toolbar for this panel
44207 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
44208 * @cfg {String} title The title for this panel
44209 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
44210 * @cfg {String} url Calls {@link #setUrl} with this value
44211 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
44212 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
44214 * Create a new ContentPanel.
44215 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
44216 * @param {String/Object} config A string to set only the title or a config object
44217 * @param {String} content (optional) Set the HTML content for this panel
44218 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
44220 Roo.ContentPanel = function(el, config, content){
44224 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
44228 if (config && config.parentLayout) {
44229 el = config.parentLayout.el.createChild();
44232 if(el.autoCreate){ // xtype is available if this is called from factory
44236 this.el = Roo.get(el);
44237 if(!this.el && config && config.autoCreate){
44238 if(typeof config.autoCreate == "object"){
44239 if(!config.autoCreate.id){
44240 config.autoCreate.id = config.id||el;
44242 this.el = Roo.DomHelper.append(document.body,
44243 config.autoCreate, true);
44245 this.el = Roo.DomHelper.append(document.body,
44246 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
44249 this.closable = false;
44250 this.loaded = false;
44251 this.active = false;
44252 if(typeof config == "string"){
44253 this.title = config;
44255 Roo.apply(this, config);
44258 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
44259 this.wrapEl = this.el.wrap();
44260 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
44267 this.resizeEl = Roo.get(this.resizeEl, true);
44269 this.resizeEl = this.el;
44274 * Fires when this panel is activated.
44275 * @param {Roo.ContentPanel} this
44279 * @event deactivate
44280 * Fires when this panel is activated.
44281 * @param {Roo.ContentPanel} this
44283 "deactivate" : true,
44287 * Fires when this panel is resized if fitToFrame is true.
44288 * @param {Roo.ContentPanel} this
44289 * @param {Number} width The width after any component adjustments
44290 * @param {Number} height The height after any component adjustments
44294 if(this.autoScroll){
44295 this.resizeEl.setStyle("overflow", "auto");
44297 content = content || this.content;
44299 this.setContent(content);
44301 if(config && config.url){
44302 this.setUrl(this.url, this.params, this.loadOnce);
44307 Roo.ContentPanel.superclass.constructor.call(this);
44310 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
44312 setRegion : function(region){
44313 this.region = region;
44315 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
44317 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
44322 * Returns the toolbar for this Panel if one was configured.
44323 * @return {Roo.Toolbar}
44325 getToolbar : function(){
44326 return this.toolbar;
44329 setActiveState : function(active){
44330 this.active = active;
44332 this.fireEvent("deactivate", this);
44334 this.fireEvent("activate", this);
44338 * Updates this panel's element
44339 * @param {String} content The new content
44340 * @param {Boolean} loadScripts (optional) true to look for and process scripts
44342 setContent : function(content, loadScripts){
44343 this.el.update(content, loadScripts);
44346 ignoreResize : function(w, h){
44347 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
44350 this.lastSize = {width: w, height: h};
44355 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
44356 * @return {Roo.UpdateManager} The UpdateManager
44358 getUpdateManager : function(){
44359 return this.el.getUpdateManager();
44362 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
44363 * @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:
44366 url: "your-url.php",
44367 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
44368 callback: yourFunction,
44369 scope: yourObject, //(optional scope)
44372 text: "Loading...",
44377 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
44378 * 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.
44379 * @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}
44380 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
44381 * @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.
44382 * @return {Roo.ContentPanel} this
44385 var um = this.el.getUpdateManager();
44386 um.update.apply(um, arguments);
44392 * 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.
44393 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
44394 * @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)
44395 * @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)
44396 * @return {Roo.UpdateManager} The UpdateManager
44398 setUrl : function(url, params, loadOnce){
44399 if(this.refreshDelegate){
44400 this.removeListener("activate", this.refreshDelegate);
44402 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
44403 this.on("activate", this.refreshDelegate);
44404 return this.el.getUpdateManager();
44407 _handleRefresh : function(url, params, loadOnce){
44408 if(!loadOnce || !this.loaded){
44409 var updater = this.el.getUpdateManager();
44410 updater.update(url, params, this._setLoaded.createDelegate(this));
44414 _setLoaded : function(){
44415 this.loaded = true;
44419 * Returns this panel's id
44422 getId : function(){
44427 * Returns this panel's element - used by regiosn to add.
44428 * @return {Roo.Element}
44430 getEl : function(){
44431 return this.wrapEl || this.el;
44434 adjustForComponents : function(width, height){
44435 if(this.resizeEl != this.el){
44436 width -= this.el.getFrameWidth('lr');
44437 height -= this.el.getFrameWidth('tb');
44440 var te = this.toolbar.getEl();
44441 height -= te.getHeight();
44442 te.setWidth(width);
44444 if(this.adjustments){
44445 width += this.adjustments[0];
44446 height += this.adjustments[1];
44448 return {"width": width, "height": height};
44451 setSize : function(width, height){
44452 if(this.fitToFrame && !this.ignoreResize(width, height)){
44453 if(this.fitContainer && this.resizeEl != this.el){
44454 this.el.setSize(width, height);
44456 var size = this.adjustForComponents(width, height);
44457 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
44458 this.fireEvent('resize', this, size.width, size.height);
44463 * Returns this panel's title
44466 getTitle : function(){
44471 * Set this panel's title
44472 * @param {String} title
44474 setTitle : function(title){
44475 this.title = title;
44477 this.region.updatePanelTitle(this, title);
44482 * Returns true is this panel was configured to be closable
44483 * @return {Boolean}
44485 isClosable : function(){
44486 return this.closable;
44489 beforeSlide : function(){
44491 this.resizeEl.clip();
44494 afterSlide : function(){
44496 this.resizeEl.unclip();
44500 * Force a content refresh from the URL specified in the {@link #setUrl} method.
44501 * Will fail silently if the {@link #setUrl} method has not been called.
44502 * This does not activate the panel, just updates its content.
44504 refresh : function(){
44505 if(this.refreshDelegate){
44506 this.loaded = false;
44507 this.refreshDelegate();
44512 * Destroys this panel
44514 destroy : function(){
44515 this.el.removeAllListeners();
44516 var tempEl = document.createElement("span");
44517 tempEl.appendChild(this.el.dom);
44518 tempEl.innerHTML = "";
44524 * Adds a xtype elements to the panel - currently only supports Forms.
44534 * @param {Object} cfg Xtype definition of item to add.
44537 addxtype : function(cfg) {
44539 if (!cfg.xtype.match(/^Form$/)) {
44542 var el = this.el.createChild();
44544 this.form = new Roo.form.Form(cfg);
44547 if ( this.form.allItems.length) this.form.render(el.dom);
44554 * @class Roo.GridPanel
44555 * @extends Roo.ContentPanel
44557 * Create a new GridPanel.
44558 * @param {Roo.grid.Grid} grid The grid for this panel
44559 * @param {String/Object} config A string to set only the panel's title, or a config object
44561 Roo.GridPanel = function(grid, config){
44564 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
44565 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
44567 this.wrapper.dom.appendChild(grid.getGridEl().dom);
44569 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
44572 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
44574 // xtype created footer. - not sure if will work as we normally have to render first..
44575 if (this.footer && !this.footer.el && this.footer.xtype) {
44577 this.footer.container = this.grid.getView().getFooterPanel(true);
44578 this.footer.dataSource = this.grid.dataSource;
44579 this.footer = Roo.factory(this.footer, Roo);
44583 grid.monitorWindowResize = false; // turn off autosizing
44584 grid.autoHeight = false;
44585 grid.autoWidth = false;
44587 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
44590 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
44591 getId : function(){
44592 return this.grid.id;
44596 * Returns the grid for this panel
44597 * @return {Roo.grid.Grid}
44599 getGrid : function(){
44603 setSize : function(width, height){
44604 if(!this.ignoreResize(width, height)){
44605 var grid = this.grid;
44606 var size = this.adjustForComponents(width, height);
44607 grid.getGridEl().setSize(size.width, size.height);
44612 beforeSlide : function(){
44613 this.grid.getView().scroller.clip();
44616 afterSlide : function(){
44617 this.grid.getView().scroller.unclip();
44620 destroy : function(){
44621 this.grid.destroy();
44623 Roo.GridPanel.superclass.destroy.call(this);
44629 * @class Roo.NestedLayoutPanel
44630 * @extends Roo.ContentPanel
44632 * Create a new NestedLayoutPanel.
44635 * @param {Roo.BorderLayout} layout The layout for this panel
44636 * @param {String/Object} config A string to set only the title or a config object
44638 Roo.NestedLayoutPanel = function(layout, config)
44640 // construct with only one argument..
44641 /* FIXME - implement nicer consturctors
44642 if (layout.layout) {
44644 layout = config.layout;
44645 delete config.layout;
44647 if (layout.xtype && !layout.getEl) {
44648 // then layout needs constructing..
44649 layout = Roo.factory(layout, Roo);
44653 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
44655 layout.monitorWindowResize = false; // turn off autosizing
44656 this.layout = layout;
44657 this.layout.getEl().addClass("x-layout-nested-layout");
44663 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
44665 setSize : function(width, height){
44666 if(!this.ignoreResize(width, height)){
44667 var size = this.adjustForComponents(width, height);
44668 var el = this.layout.getEl();
44669 el.setSize(size.width, size.height);
44670 var touch = el.dom.offsetWidth;
44671 this.layout.layout();
44672 // ie requires a double layout on the first pass
44673 if(Roo.isIE && !this.initialized){
44674 this.initialized = true;
44675 this.layout.layout();
44680 // activate all subpanels if not currently active..
44682 setActiveState : function(active){
44683 this.active = active;
44685 this.fireEvent("deactivate", this);
44689 this.fireEvent("activate", this);
44690 // not sure if this should happen before or after..
44691 if (!this.layout) {
44692 return; // should not happen..
44695 for (var r in this.layout.regions) {
44696 reg = this.layout.getRegion(r);
44697 if (reg.getActivePanel()) {
44698 //reg.showPanel(reg.getActivePanel()); // force it to activate..
44699 reg.setActivePanel(reg.getActivePanel());
44702 if (!reg.panels.length) {
44705 reg.showPanel(reg.getPanel(0));
44714 * Returns the nested BorderLayout for this panel
44715 * @return {Roo.BorderLayout}
44717 getLayout : function(){
44718 return this.layout;
44722 * Adds a xtype elements to the layout of the nested panel
44726 xtype : 'ContentPanel',
44733 xtype : 'NestedLayoutPanel',
44739 items : [ ... list of content panels or nested layout panels.. ]
44743 * @param {Object} cfg Xtype definition of item to add.
44745 addxtype : function(cfg) {
44746 return this.layout.addxtype(cfg);
44751 Roo.ScrollPanel = function(el, config, content){
44752 config = config || {};
44753 config.fitToFrame = true;
44754 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
44756 this.el.dom.style.overflow = "hidden";
44757 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
44758 this.el.removeClass("x-layout-inactive-content");
44759 this.el.on("mousewheel", this.onWheel, this);
44761 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
44762 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
44763 up.unselectable(); down.unselectable();
44764 up.on("click", this.scrollUp, this);
44765 down.on("click", this.scrollDown, this);
44766 up.addClassOnOver("x-scroller-btn-over");
44767 down.addClassOnOver("x-scroller-btn-over");
44768 up.addClassOnClick("x-scroller-btn-click");
44769 down.addClassOnClick("x-scroller-btn-click");
44770 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
44772 this.resizeEl = this.el;
44773 this.el = wrap; this.up = up; this.down = down;
44776 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
44778 wheelIncrement : 5,
44779 scrollUp : function(){
44780 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
44783 scrollDown : function(){
44784 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
44787 afterScroll : function(){
44788 var el = this.resizeEl;
44789 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
44790 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44791 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44794 setSize : function(){
44795 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
44796 this.afterScroll();
44799 onWheel : function(e){
44800 var d = e.getWheelDelta();
44801 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
44802 this.afterScroll();
44806 setContent : function(content, loadScripts){
44807 this.resizeEl.update(content, loadScripts);
44821 * @class Roo.TreePanel
44822 * @extends Roo.ContentPanel
44824 * Create a new TreePanel.
44825 * @param {String/Object} config A string to set only the panel's title, or a config object
44826 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
44828 Roo.TreePanel = function(config){
44829 var el = config.el;
44830 var tree = config.tree;
44831 delete config.tree;
44832 delete config.el; // hopefull!
44833 Roo.TreePanel.superclass.constructor.call(this, el, config);
44834 var treeEl = el.createChild();
44835 this.tree = new Roo.tree.TreePanel(treeEl , tree);
44836 //console.log(tree);
44837 this.on('activate', function()
44839 if (this.tree.rendered) {
44842 //console.log('render tree');
44843 this.tree.render();
44846 this.on('resize', function (cp, w, h) {
44847 this.tree.innerCt.setWidth(w);
44848 this.tree.innerCt.setHeight(h);
44849 this.tree.innerCt.setStyle('overflow-y', 'auto');
44856 Roo.extend(Roo.TreePanel, Roo.ContentPanel);
44870 * Ext JS Library 1.1.1
44871 * Copyright(c) 2006-2007, Ext JS, LLC.
44873 * Originally Released Under LGPL - original licence link has changed is not relivant.
44876 * <script type="text/javascript">
44881 * @class Roo.ReaderLayout
44882 * @extends Roo.BorderLayout
44883 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
44884 * center region containing two nested regions (a top one for a list view and one for item preview below),
44885 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
44886 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
44887 * expedites the setup of the overall layout and regions for this common application style.
44890 var reader = new Roo.ReaderLayout();
44891 var CP = Roo.ContentPanel; // shortcut for adding
44893 reader.beginUpdate();
44894 reader.add("north", new CP("north", "North"));
44895 reader.add("west", new CP("west", {title: "West"}));
44896 reader.add("east", new CP("east", {title: "East"}));
44898 reader.regions.listView.add(new CP("listView", "List"));
44899 reader.regions.preview.add(new CP("preview", "Preview"));
44900 reader.endUpdate();
44903 * Create a new ReaderLayout
44904 * @param {Object} config Configuration options
44905 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
44906 * document.body if omitted)
44908 Roo.ReaderLayout = function(config, renderTo){
44909 var c = config || {size:{}};
44910 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
44911 north: c.north !== false ? Roo.apply({
44915 }, c.north) : false,
44916 west: c.west !== false ? Roo.apply({
44924 margins:{left:5,right:0,bottom:5,top:5},
44925 cmargins:{left:5,right:5,bottom:5,top:5}
44926 }, c.west) : false,
44927 east: c.east !== false ? Roo.apply({
44935 margins:{left:0,right:5,bottom:5,top:5},
44936 cmargins:{left:5,right:5,bottom:5,top:5}
44937 }, c.east) : false,
44938 center: Roo.apply({
44939 tabPosition: 'top',
44943 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
44947 this.el.addClass('x-reader');
44949 this.beginUpdate();
44951 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
44952 south: c.preview !== false ? Roo.apply({
44959 cmargins:{top:5,left:0, right:0, bottom:0}
44960 }, c.preview) : false,
44961 center: Roo.apply({
44967 this.add('center', new Roo.NestedLayoutPanel(inner,
44968 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
44972 this.regions.preview = inner.getRegion('south');
44973 this.regions.listView = inner.getRegion('center');
44976 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
44978 * Ext JS Library 1.1.1
44979 * Copyright(c) 2006-2007, Ext JS, LLC.
44981 * Originally Released Under LGPL - original licence link has changed is not relivant.
44984 * <script type="text/javascript">
44988 * @class Roo.grid.Grid
44989 * @extends Roo.util.Observable
44990 * This class represents the primary interface of a component based grid control.
44991 * <br><br>Usage:<pre><code>
44992 var grid = new Roo.grid.Grid("my-container-id", {
44995 selModel: mySelectionModel,
44996 autoSizeColumns: true,
44997 monitorWindowResize: false,
44998 trackMouseOver: true
45003 * <b>Common Problems:</b><br/>
45004 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
45005 * element will correct this<br/>
45006 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
45007 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
45008 * are unpredictable.<br/>
45009 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
45010 * grid to calculate dimensions/offsets.<br/>
45012 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
45013 * The container MUST have some type of size defined for the grid to fill. The container will be
45014 * automatically set to position relative if it isn't already.
45015 * @param {Object} config A config object that sets properties on this grid.
45017 Roo.grid.Grid = function(container, config){
45018 // initialize the container
45019 this.container = Roo.get(container);
45020 this.container.update("");
45021 this.container.setStyle("overflow", "hidden");
45022 this.container.addClass('x-grid-container');
45024 this.id = this.container.id;
45026 Roo.apply(this, config);
45027 // check and correct shorthanded configs
45029 this.dataSource = this.ds;
45033 this.colModel = this.cm;
45037 this.selModel = this.sm;
45041 if (this.selModel) {
45042 this.selModel = Roo.factory(this.selModel, Roo.grid);
45043 this.sm = this.selModel;
45044 this.sm.xmodule = this.xmodule || false;
45046 if (typeof(this.colModel.config) == 'undefined') {
45047 this.colModel = new Roo.grid.ColumnModel(this.colModel);
45048 this.cm = this.colModel;
45049 this.cm.xmodule = this.xmodule || false;
45051 if (this.dataSource) {
45052 this.dataSource= Roo.factory(this.dataSource, Roo.data);
45053 this.ds = this.dataSource;
45054 this.ds.xmodule = this.xmodule || false;
45061 this.container.setWidth(this.width);
45065 this.container.setHeight(this.height);
45072 * The raw click event for the entire grid.
45073 * @param {Roo.EventObject} e
45078 * The raw dblclick event for the entire grid.
45079 * @param {Roo.EventObject} e
45083 * @event contextmenu
45084 * The raw contextmenu event for the entire grid.
45085 * @param {Roo.EventObject} e
45087 "contextmenu" : true,
45090 * The raw mousedown event for the entire grid.
45091 * @param {Roo.EventObject} e
45093 "mousedown" : true,
45096 * The raw mouseup event for the entire grid.
45097 * @param {Roo.EventObject} e
45102 * The raw mouseover event for the entire grid.
45103 * @param {Roo.EventObject} e
45105 "mouseover" : true,
45108 * The raw mouseout event for the entire grid.
45109 * @param {Roo.EventObject} e
45114 * The raw keypress event for the entire grid.
45115 * @param {Roo.EventObject} e
45120 * The raw keydown event for the entire grid.
45121 * @param {Roo.EventObject} e
45129 * Fires when a cell is clicked
45130 * @param {Grid} this
45131 * @param {Number} rowIndex
45132 * @param {Number} columnIndex
45133 * @param {Roo.EventObject} e
45135 "cellclick" : true,
45137 * @event celldblclick
45138 * Fires when a cell is double clicked
45139 * @param {Grid} this
45140 * @param {Number} rowIndex
45141 * @param {Number} columnIndex
45142 * @param {Roo.EventObject} e
45144 "celldblclick" : true,
45147 * Fires when a row is clicked
45148 * @param {Grid} this
45149 * @param {Number} rowIndex
45150 * @param {Roo.EventObject} e
45154 * @event rowdblclick
45155 * Fires when a row is double clicked
45156 * @param {Grid} this
45157 * @param {Number} rowIndex
45158 * @param {Roo.EventObject} e
45160 "rowdblclick" : true,
45162 * @event headerclick
45163 * Fires when a header is clicked
45164 * @param {Grid} this
45165 * @param {Number} columnIndex
45166 * @param {Roo.EventObject} e
45168 "headerclick" : true,
45170 * @event headerdblclick
45171 * Fires when a header cell is double clicked
45172 * @param {Grid} this
45173 * @param {Number} columnIndex
45174 * @param {Roo.EventObject} e
45176 "headerdblclick" : true,
45178 * @event rowcontextmenu
45179 * Fires when a row is right clicked
45180 * @param {Grid} this
45181 * @param {Number} rowIndex
45182 * @param {Roo.EventObject} e
45184 "rowcontextmenu" : true,
45186 * @event cellcontextmenu
45187 * Fires when a cell is right clicked
45188 * @param {Grid} this
45189 * @param {Number} rowIndex
45190 * @param {Number} cellIndex
45191 * @param {Roo.EventObject} e
45193 "cellcontextmenu" : true,
45195 * @event headercontextmenu
45196 * Fires when a header is right clicked
45197 * @param {Grid} this
45198 * @param {Number} columnIndex
45199 * @param {Roo.EventObject} e
45201 "headercontextmenu" : true,
45203 * @event bodyscroll
45204 * Fires when the body element is scrolled
45205 * @param {Number} scrollLeft
45206 * @param {Number} scrollTop
45208 "bodyscroll" : true,
45210 * @event columnresize
45211 * Fires when the user resizes a column
45212 * @param {Number} columnIndex
45213 * @param {Number} newSize
45215 "columnresize" : true,
45217 * @event columnmove
45218 * Fires when the user moves a column
45219 * @param {Number} oldIndex
45220 * @param {Number} newIndex
45222 "columnmove" : true,
45225 * Fires when row(s) start being dragged
45226 * @param {Grid} this
45227 * @param {Roo.GridDD} dd The drag drop object
45228 * @param {event} e The raw browser event
45230 "startdrag" : true,
45233 * Fires when a drag operation is complete
45234 * @param {Grid} this
45235 * @param {Roo.GridDD} dd The drag drop object
45236 * @param {event} e The raw browser event
45241 * Fires when dragged row(s) are dropped on a valid DD target
45242 * @param {Grid} this
45243 * @param {Roo.GridDD} dd The drag drop object
45244 * @param {String} targetId The target drag drop object
45245 * @param {event} e The raw browser event
45250 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
45251 * @param {Grid} this
45252 * @param {Roo.GridDD} dd The drag drop object
45253 * @param {String} targetId The target drag drop object
45254 * @param {event} e The raw browser event
45259 * Fires when the dragged row(s) first cross another DD target while being dragged
45260 * @param {Grid} this
45261 * @param {Roo.GridDD} dd The drag drop object
45262 * @param {String} targetId The target drag drop object
45263 * @param {event} e The raw browser event
45265 "dragenter" : true,
45268 * Fires when the dragged row(s) leave another DD target while being dragged
45269 * @param {Grid} this
45270 * @param {Roo.GridDD} dd The drag drop object
45271 * @param {String} targetId The target drag drop object
45272 * @param {event} e The raw browser event
45277 * Fires when the grid is rendered
45278 * @param {Grid} grid
45283 Roo.grid.Grid.superclass.constructor.call(this);
45285 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
45287 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
45289 minColumnWidth : 25,
45292 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
45293 * <b>on initial render.</b> It is more efficient to explicitly size the columns
45294 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
45296 autoSizeColumns : false,
45299 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
45301 autoSizeHeaders : true,
45304 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
45306 monitorWindowResize : true,
45309 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
45310 * rows measured to get a columns size. Default is 0 (all rows).
45312 maxRowsToMeasure : 0,
45315 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
45317 trackMouseOver : true,
45320 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
45322 enableDragDrop : false,
45325 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
45327 enableColumnMove : true,
45330 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
45332 enableColumnHide : true,
45335 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
45337 enableRowHeightSync : false,
45340 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
45345 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
45347 autoHeight : false,
45350 * @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.
45352 autoExpandColumn : false,
45355 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
45358 autoExpandMin : 50,
45361 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
45363 autoExpandMax : 1000,
45366 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
45371 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
45379 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
45380 * of a fixed width. Default is false.
45383 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
45386 * Called once after all setup has been completed and the grid is ready to be rendered.
45387 * @return {Roo.grid.Grid} this
45389 render : function(){
45390 var c = this.container;
45391 // try to detect autoHeight/width mode
45392 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
45393 this.autoHeight = true;
45395 var view = this.getView();
45398 c.on("click", this.onClick, this);
45399 c.on("dblclick", this.onDblClick, this);
45400 c.on("contextmenu", this.onContextMenu, this);
45401 c.on("keydown", this.onKeyDown, this);
45403 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
45405 this.getSelectionModel().init(this);
45410 this.loadMask = new Roo.LoadMask(this.container,
45411 Roo.apply({store:this.dataSource}, this.loadMask));
45415 if (this.toolbar && this.toolbar.xtype) {
45416 this.toolbar.container = this.getView().getHeaderPanel(true);
45417 this.toolbar = new Ext.Toolbar(this.toolbar);
45419 if (this.footer && this.footer.xtype) {
45420 this.footer.dataSource = this.getDataSource();
45421 this.footer.container = this.getView().getFooterPanel(true);
45422 this.footer = Roo.factory(this.footer, Roo);
45424 this.rendered = true;
45425 this.fireEvent('render', this);
45430 * Reconfigures the grid to use a different Store and Column Model.
45431 * The View will be bound to the new objects and refreshed.
45432 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
45433 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
45435 reconfigure : function(dataSource, colModel){
45437 this.loadMask.destroy();
45438 this.loadMask = new Roo.LoadMask(this.container,
45439 Roo.apply({store:dataSource}, this.loadMask));
45441 this.view.bind(dataSource, colModel);
45442 this.dataSource = dataSource;
45443 this.colModel = colModel;
45444 this.view.refresh(true);
45448 onKeyDown : function(e){
45449 this.fireEvent("keydown", e);
45453 * Destroy this grid.
45454 * @param {Boolean} removeEl True to remove the element
45456 destroy : function(removeEl, keepListeners){
45458 this.loadMask.destroy();
45460 var c = this.container;
45461 c.removeAllListeners();
45462 this.view.destroy();
45463 this.colModel.purgeListeners();
45464 if(!keepListeners){
45465 this.purgeListeners();
45468 if(removeEl === true){
45474 processEvent : function(name, e){
45475 this.fireEvent(name, e);
45476 var t = e.getTarget();
45478 var header = v.findHeaderIndex(t);
45479 if(header !== false){
45480 this.fireEvent("header" + name, this, header, e);
45482 var row = v.findRowIndex(t);
45483 var cell = v.findCellIndex(t);
45485 this.fireEvent("row" + name, this, row, e);
45486 if(cell !== false){
45487 this.fireEvent("cell" + name, this, row, cell, e);
45494 onClick : function(e){
45495 this.processEvent("click", e);
45499 onContextMenu : function(e, t){
45500 this.processEvent("contextmenu", e);
45504 onDblClick : function(e){
45505 this.processEvent("dblclick", e);
45509 walkCells : function(row, col, step, fn, scope){
45510 var cm = this.colModel, clen = cm.getColumnCount();
45511 var ds = this.dataSource, rlen = ds.getCount(), first = true;
45523 if(fn.call(scope || this, row, col, cm) === true){
45541 if(fn.call(scope || this, row, col, cm) === true){
45553 getSelections : function(){
45554 return this.selModel.getSelections();
45558 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
45559 * but if manual update is required this method will initiate it.
45561 autoSize : function(){
45563 this.view.layout();
45564 if(this.view.adjustForScroll){
45565 this.view.adjustForScroll();
45571 * Returns the grid's underlying element.
45572 * @return {Element} The element
45574 getGridEl : function(){
45575 return this.container;
45578 // private for compatibility, overridden by editor grid
45579 stopEditing : function(){},
45582 * Returns the grid's SelectionModel.
45583 * @return {SelectionModel}
45585 getSelectionModel : function(){
45586 if(!this.selModel){
45587 this.selModel = new Roo.grid.RowSelectionModel();
45589 return this.selModel;
45593 * Returns the grid's DataSource.
45594 * @return {DataSource}
45596 getDataSource : function(){
45597 return this.dataSource;
45601 * Returns the grid's ColumnModel.
45602 * @return {ColumnModel}
45604 getColumnModel : function(){
45605 return this.colModel;
45609 * Returns the grid's GridView object.
45610 * @return {GridView}
45612 getView : function(){
45614 this.view = new Roo.grid.GridView(this.viewConfig);
45619 * Called to get grid's drag proxy text, by default returns this.ddText.
45622 getDragDropText : function(){
45623 var count = this.selModel.getCount();
45624 return String.format(this.ddText, count, count == 1 ? '' : 's');
45628 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
45629 * %0 is replaced with the number of selected rows.
45632 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
45634 * Ext JS Library 1.1.1
45635 * Copyright(c) 2006-2007, Ext JS, LLC.
45637 * Originally Released Under LGPL - original licence link has changed is not relivant.
45640 * <script type="text/javascript">
45643 Roo.grid.AbstractGridView = function(){
45647 "beforerowremoved" : true,
45648 "beforerowsinserted" : true,
45649 "beforerefresh" : true,
45650 "rowremoved" : true,
45651 "rowsinserted" : true,
45652 "rowupdated" : true,
45655 Roo.grid.AbstractGridView.superclass.constructor.call(this);
45658 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
45659 rowClass : "x-grid-row",
45660 cellClass : "x-grid-cell",
45661 tdClass : "x-grid-td",
45662 hdClass : "x-grid-hd",
45663 splitClass : "x-grid-hd-split",
45665 init: function(grid){
45667 var cid = this.grid.getGridEl().id;
45668 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
45669 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
45670 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
45671 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
45674 getColumnRenderers : function(){
45675 var renderers = [];
45676 var cm = this.grid.colModel;
45677 var colCount = cm.getColumnCount();
45678 for(var i = 0; i < colCount; i++){
45679 renderers[i] = cm.getRenderer(i);
45684 getColumnIds : function(){
45686 var cm = this.grid.colModel;
45687 var colCount = cm.getColumnCount();
45688 for(var i = 0; i < colCount; i++){
45689 ids[i] = cm.getColumnId(i);
45694 getDataIndexes : function(){
45695 if(!this.indexMap){
45696 this.indexMap = this.buildIndexMap();
45698 return this.indexMap.colToData;
45701 getColumnIndexByDataIndex : function(dataIndex){
45702 if(!this.indexMap){
45703 this.indexMap = this.buildIndexMap();
45705 return this.indexMap.dataToCol[dataIndex];
45709 * Set a css style for a column dynamically.
45710 * @param {Number} colIndex The index of the column
45711 * @param {String} name The css property name
45712 * @param {String} value The css value
45714 setCSSStyle : function(colIndex, name, value){
45715 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
45716 Roo.util.CSS.updateRule(selector, name, value);
45719 generateRules : function(cm){
45720 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
45721 Roo.util.CSS.removeStyleSheet(rulesId);
45722 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
45723 var cid = cm.getColumnId(i);
45724 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
45725 this.tdSelector, cid, " {\n}\n",
45726 this.hdSelector, cid, " {\n}\n",
45727 this.splitSelector, cid, " {\n}\n");
45729 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
45733 * Ext JS Library 1.1.1
45734 * Copyright(c) 2006-2007, Ext JS, LLC.
45736 * Originally Released Under LGPL - original licence link has changed is not relivant.
45739 * <script type="text/javascript">
45743 // This is a support class used internally by the Grid components
45744 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
45746 this.view = grid.getView();
45747 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45748 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
45750 this.setHandleElId(Roo.id(hd));
45751 this.setOuterHandleElId(Roo.id(hd2));
45753 this.scroll = false;
45755 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
45757 getDragData : function(e){
45758 var t = Roo.lib.Event.getTarget(e);
45759 var h = this.view.findHeaderCell(t);
45761 return {ddel: h.firstChild, header:h};
45766 onInitDrag : function(e){
45767 this.view.headersDisabled = true;
45768 var clone = this.dragData.ddel.cloneNode(true);
45769 clone.id = Roo.id();
45770 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
45771 this.proxy.update(clone);
45775 afterValidDrop : function(){
45777 setTimeout(function(){
45778 v.headersDisabled = false;
45782 afterInvalidDrop : function(){
45784 setTimeout(function(){
45785 v.headersDisabled = false;
45791 * Ext JS Library 1.1.1
45792 * Copyright(c) 2006-2007, Ext JS, LLC.
45794 * Originally Released Under LGPL - original licence link has changed is not relivant.
45797 * <script type="text/javascript">
45800 // This is a support class used internally by the Grid components
45801 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
45803 this.view = grid.getView();
45804 // split the proxies so they don't interfere with mouse events
45805 this.proxyTop = Roo.DomHelper.append(document.body, {
45806 cls:"col-move-top", html:" "
45808 this.proxyBottom = Roo.DomHelper.append(document.body, {
45809 cls:"col-move-bottom", html:" "
45811 this.proxyTop.hide = this.proxyBottom.hide = function(){
45812 this.setLeftTop(-100,-100);
45813 this.setStyle("visibility", "hidden");
45815 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45816 // temporarily disabled
45817 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
45818 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
45820 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
45821 proxyOffsets : [-4, -9],
45822 fly: Roo.Element.fly,
45824 getTargetFromEvent : function(e){
45825 var t = Roo.lib.Event.getTarget(e);
45826 var cindex = this.view.findCellIndex(t);
45827 if(cindex !== false){
45828 return this.view.getHeaderCell(cindex);
45832 nextVisible : function(h){
45833 var v = this.view, cm = this.grid.colModel;
45836 if(!cm.isHidden(v.getCellIndex(h))){
45844 prevVisible : function(h){
45845 var v = this.view, cm = this.grid.colModel;
45848 if(!cm.isHidden(v.getCellIndex(h))){
45856 positionIndicator : function(h, n, e){
45857 var x = Roo.lib.Event.getPageX(e);
45858 var r = Roo.lib.Dom.getRegion(n.firstChild);
45859 var px, pt, py = r.top + this.proxyOffsets[1];
45860 if((r.right - x) <= (r.right-r.left)/2){
45861 px = r.right+this.view.borderWidth;
45867 var oldIndex = this.view.getCellIndex(h);
45868 var newIndex = this.view.getCellIndex(n);
45870 if(this.grid.colModel.isFixed(newIndex)){
45874 var locked = this.grid.colModel.isLocked(newIndex);
45879 if(oldIndex < newIndex){
45882 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
45885 px += this.proxyOffsets[0];
45886 this.proxyTop.setLeftTop(px, py);
45887 this.proxyTop.show();
45888 if(!this.bottomOffset){
45889 this.bottomOffset = this.view.mainHd.getHeight();
45891 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
45892 this.proxyBottom.show();
45896 onNodeEnter : function(n, dd, e, data){
45897 if(data.header != n){
45898 this.positionIndicator(data.header, n, e);
45902 onNodeOver : function(n, dd, e, data){
45903 var result = false;
45904 if(data.header != n){
45905 result = this.positionIndicator(data.header, n, e);
45908 this.proxyTop.hide();
45909 this.proxyBottom.hide();
45911 return result ? this.dropAllowed : this.dropNotAllowed;
45914 onNodeOut : function(n, dd, e, data){
45915 this.proxyTop.hide();
45916 this.proxyBottom.hide();
45919 onNodeDrop : function(n, dd, e, data){
45920 var h = data.header;
45922 var cm = this.grid.colModel;
45923 var x = Roo.lib.Event.getPageX(e);
45924 var r = Roo.lib.Dom.getRegion(n.firstChild);
45925 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
45926 var oldIndex = this.view.getCellIndex(h);
45927 var newIndex = this.view.getCellIndex(n);
45928 var locked = cm.isLocked(newIndex);
45932 if(oldIndex < newIndex){
45935 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
45938 cm.setLocked(oldIndex, locked, true);
45939 cm.moveColumn(oldIndex, newIndex);
45940 this.grid.fireEvent("columnmove", oldIndex, newIndex);
45948 * Ext JS Library 1.1.1
45949 * Copyright(c) 2006-2007, Ext JS, LLC.
45951 * Originally Released Under LGPL - original licence link has changed is not relivant.
45954 * <script type="text/javascript">
45958 * @class Roo.grid.GridView
45959 * @extends Roo.util.Observable
45962 * @param {Object} config
45964 Roo.grid.GridView = function(config){
45965 Roo.grid.GridView.superclass.constructor.call(this);
45968 Roo.apply(this, config);
45971 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
45974 * Override this function to apply custom css classes to rows during rendering
45975 * @param {Record} record The record
45976 * @param {Number} index
45977 * @method getRowClass
45979 rowClass : "x-grid-row",
45981 cellClass : "x-grid-col",
45983 tdClass : "x-grid-td",
45985 hdClass : "x-grid-hd",
45987 splitClass : "x-grid-split",
45989 sortClasses : ["sort-asc", "sort-desc"],
45991 enableMoveAnim : false,
45995 dh : Roo.DomHelper,
45997 fly : Roo.Element.fly,
45999 css : Roo.util.CSS,
46005 scrollIncrement : 22,
46007 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
46009 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
46011 bind : function(ds, cm){
46013 this.ds.un("load", this.onLoad, this);
46014 this.ds.un("datachanged", this.onDataChange, this);
46015 this.ds.un("add", this.onAdd, this);
46016 this.ds.un("remove", this.onRemove, this);
46017 this.ds.un("update", this.onUpdate, this);
46018 this.ds.un("clear", this.onClear, this);
46021 ds.on("load", this.onLoad, this);
46022 ds.on("datachanged", this.onDataChange, this);
46023 ds.on("add", this.onAdd, this);
46024 ds.on("remove", this.onRemove, this);
46025 ds.on("update", this.onUpdate, this);
46026 ds.on("clear", this.onClear, this);
46031 this.cm.un("widthchange", this.onColWidthChange, this);
46032 this.cm.un("headerchange", this.onHeaderChange, this);
46033 this.cm.un("hiddenchange", this.onHiddenChange, this);
46034 this.cm.un("columnmoved", this.onColumnMove, this);
46035 this.cm.un("columnlockchange", this.onColumnLock, this);
46038 this.generateRules(cm);
46039 cm.on("widthchange", this.onColWidthChange, this);
46040 cm.on("headerchange", this.onHeaderChange, this);
46041 cm.on("hiddenchange", this.onHiddenChange, this);
46042 cm.on("columnmoved", this.onColumnMove, this);
46043 cm.on("columnlockchange", this.onColumnLock, this);
46048 init: function(grid){
46049 Roo.grid.GridView.superclass.init.call(this, grid);
46051 this.bind(grid.dataSource, grid.colModel);
46053 grid.on("headerclick", this.handleHeaderClick, this);
46055 if(grid.trackMouseOver){
46056 grid.on("mouseover", this.onRowOver, this);
46057 grid.on("mouseout", this.onRowOut, this);
46059 grid.cancelTextSelection = function(){};
46060 this.gridId = grid.id;
46062 var tpls = this.templates || {};
46065 tpls.master = new Roo.Template(
46066 '<div class="x-grid" hidefocus="true">',
46067 '<div class="x-grid-topbar"></div>',
46068 '<div class="x-grid-scroller"><div></div></div>',
46069 '<div class="x-grid-locked">',
46070 '<div class="x-grid-header">{lockedHeader}</div>',
46071 '<div class="x-grid-body">{lockedBody}</div>',
46073 '<div class="x-grid-viewport">',
46074 '<div class="x-grid-header">{header}</div>',
46075 '<div class="x-grid-body">{body}</div>',
46077 '<div class="x-grid-bottombar"></div>',
46078 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
46079 '<div class="x-grid-resize-proxy"> </div>',
46082 tpls.master.disableformats = true;
46086 tpls.header = new Roo.Template(
46087 '<table border="0" cellspacing="0" cellpadding="0">',
46088 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
46091 tpls.header.disableformats = true;
46093 tpls.header.compile();
46096 tpls.hcell = new Roo.Template(
46097 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
46098 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
46101 tpls.hcell.disableFormats = true;
46103 tpls.hcell.compile();
46106 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
46107 tpls.hsplit.disableFormats = true;
46109 tpls.hsplit.compile();
46112 tpls.body = new Roo.Template(
46113 '<table border="0" cellspacing="0" cellpadding="0">',
46114 "<tbody>{rows}</tbody>",
46117 tpls.body.disableFormats = true;
46119 tpls.body.compile();
46122 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
46123 tpls.row.disableFormats = true;
46125 tpls.row.compile();
46128 tpls.cell = new Roo.Template(
46129 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
46130 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
46133 tpls.cell.disableFormats = true;
46135 tpls.cell.compile();
46137 this.templates = tpls;
46140 // remap these for backwards compat
46141 onColWidthChange : function(){
46142 this.updateColumns.apply(this, arguments);
46144 onHeaderChange : function(){
46145 this.updateHeaders.apply(this, arguments);
46147 onHiddenChange : function(){
46148 this.handleHiddenChange.apply(this, arguments);
46150 onColumnMove : function(){
46151 this.handleColumnMove.apply(this, arguments);
46153 onColumnLock : function(){
46154 this.handleLockChange.apply(this, arguments);
46157 onDataChange : function(){
46159 this.updateHeaderSortState();
46162 onClear : function(){
46166 onUpdate : function(ds, record){
46167 this.refreshRow(record);
46170 refreshRow : function(record){
46171 var ds = this.ds, index;
46172 if(typeof record == 'number'){
46174 record = ds.getAt(index);
46176 index = ds.indexOf(record);
46178 this.insertRows(ds, index, index, true);
46179 this.onRemove(ds, record, index+1, true);
46180 this.syncRowHeights(index, index);
46182 this.fireEvent("rowupdated", this, index, record);
46185 onAdd : function(ds, records, index){
46186 this.insertRows(ds, index, index + (records.length-1));
46189 onRemove : function(ds, record, index, isUpdate){
46190 if(isUpdate !== true){
46191 this.fireEvent("beforerowremoved", this, index, record);
46193 var bt = this.getBodyTable(), lt = this.getLockedTable();
46194 if(bt.rows[index]){
46195 bt.firstChild.removeChild(bt.rows[index]);
46197 if(lt.rows[index]){
46198 lt.firstChild.removeChild(lt.rows[index]);
46200 if(isUpdate !== true){
46201 this.stripeRows(index);
46202 this.syncRowHeights(index, index);
46204 this.fireEvent("rowremoved", this, index, record);
46208 onLoad : function(){
46209 this.scrollToTop();
46213 * Scrolls the grid to the top
46215 scrollToTop : function(){
46217 this.scroller.dom.scrollTop = 0;
46223 * Gets a panel in the header of the grid that can be used for toolbars etc.
46224 * After modifying the contents of this panel a call to grid.autoSize() may be
46225 * required to register any changes in size.
46226 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
46227 * @return Roo.Element
46229 getHeaderPanel : function(doShow){
46231 this.headerPanel.show();
46233 return this.headerPanel;
46237 * Gets a panel in the footer of the grid that can be used for toolbars etc.
46238 * After modifying the contents of this panel a call to grid.autoSize() may be
46239 * required to register any changes in size.
46240 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
46241 * @return Roo.Element
46243 getFooterPanel : function(doShow){
46245 this.footerPanel.show();
46247 return this.footerPanel;
46250 initElements : function(){
46251 var E = Roo.Element;
46252 var el = this.grid.getGridEl().dom.firstChild;
46253 var cs = el.childNodes;
46255 this.el = new E(el);
46256 this.headerPanel = new E(el.firstChild);
46257 this.headerPanel.enableDisplayMode("block");
46259 this.scroller = new E(cs[1]);
46260 this.scrollSizer = new E(this.scroller.dom.firstChild);
46262 this.lockedWrap = new E(cs[2]);
46263 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
46264 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
46266 this.mainWrap = new E(cs[3]);
46267 this.mainHd = new E(this.mainWrap.dom.firstChild);
46268 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
46270 this.footerPanel = new E(cs[4]);
46271 this.footerPanel.enableDisplayMode("block");
46273 this.focusEl = new E(cs[5]);
46274 this.focusEl.swallowEvent("click", true);
46275 this.resizeProxy = new E(cs[6]);
46277 this.headerSelector = String.format(
46278 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
46279 this.lockedHd.id, this.mainHd.id
46282 this.splitterSelector = String.format(
46283 '#{0} div.x-grid-split, #{1} div.x-grid-split',
46284 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
46287 idToCssName : function(s)
46289 return s.replace(/[^a-z0-9]+/ig, '-');
46292 getHeaderCell : function(index){
46293 return Roo.DomQuery.select(this.headerSelector)[index];
46296 getHeaderCellMeasure : function(index){
46297 return this.getHeaderCell(index).firstChild;
46300 getHeaderCellText : function(index){
46301 return this.getHeaderCell(index).firstChild.firstChild;
46304 getLockedTable : function(){
46305 return this.lockedBody.dom.firstChild;
46308 getBodyTable : function(){
46309 return this.mainBody.dom.firstChild;
46312 getLockedRow : function(index){
46313 return this.getLockedTable().rows[index];
46316 getRow : function(index){
46317 return this.getBodyTable().rows[index];
46320 getRowComposite : function(index){
46322 this.rowEl = new Roo.CompositeElementLite();
46324 var els = [], lrow, mrow;
46325 if(lrow = this.getLockedRow(index)){
46328 if(mrow = this.getRow(index)){
46331 this.rowEl.elements = els;
46335 getCell : function(rowIndex, colIndex){
46336 var locked = this.cm.getLockedCount();
46338 if(colIndex < locked){
46339 source = this.lockedBody.dom.firstChild;
46341 source = this.mainBody.dom.firstChild;
46342 colIndex -= locked;
46344 return source.rows[rowIndex].childNodes[colIndex];
46347 getCellText : function(rowIndex, colIndex){
46348 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
46351 getCellBox : function(cell){
46352 var b = this.fly(cell).getBox();
46353 if(Roo.isOpera){ // opera fails to report the Y
46354 b.y = cell.offsetTop + this.mainBody.getY();
46359 getCellIndex : function(cell){
46360 var id = String(cell.className).match(this.cellRE);
46362 return parseInt(id[1], 10);
46367 findHeaderIndex : function(n){
46368 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46369 return r ? this.getCellIndex(r) : false;
46372 findHeaderCell : function(n){
46373 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46374 return r ? r : false;
46377 findRowIndex : function(n){
46381 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
46382 return r ? r.rowIndex : false;
46385 findCellIndex : function(node){
46386 var stop = this.el.dom;
46387 while(node && node != stop){
46388 if(this.findRE.test(node.className)){
46389 return this.getCellIndex(node);
46391 node = node.parentNode;
46396 getColumnId : function(index){
46397 return this.cm.getColumnId(index);
46400 getSplitters : function(){
46401 if(this.splitterSelector){
46402 return Roo.DomQuery.select(this.splitterSelector);
46408 getSplitter : function(index){
46409 return this.getSplitters()[index];
46412 onRowOver : function(e, t){
46414 if((row = this.findRowIndex(t)) !== false){
46415 this.getRowComposite(row).addClass("x-grid-row-over");
46419 onRowOut : function(e, t){
46421 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
46422 this.getRowComposite(row).removeClass("x-grid-row-over");
46426 renderHeaders : function(){
46428 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
46429 var cb = [], lb = [], sb = [], lsb = [], p = {};
46430 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46431 p.cellId = "x-grid-hd-0-" + i;
46432 p.splitId = "x-grid-csplit-0-" + i;
46433 p.id = cm.getColumnId(i);
46434 p.title = cm.getColumnTooltip(i) || "";
46435 p.value = cm.getColumnHeader(i) || "";
46436 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
46437 if(!cm.isLocked(i)){
46438 cb[cb.length] = ct.apply(p);
46439 sb[sb.length] = st.apply(p);
46441 lb[lb.length] = ct.apply(p);
46442 lsb[lsb.length] = st.apply(p);
46445 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
46446 ht.apply({cells: cb.join(""), splits:sb.join("")})];
46449 updateHeaders : function(){
46450 var html = this.renderHeaders();
46451 this.lockedHd.update(html[0]);
46452 this.mainHd.update(html[1]);
46456 * Focuses the specified row.
46457 * @param {Number} row The row index
46459 focusRow : function(row){
46460 var x = this.scroller.dom.scrollLeft;
46461 this.focusCell(row, 0, false);
46462 this.scroller.dom.scrollLeft = x;
46466 * Focuses the specified cell.
46467 * @param {Number} row The row index
46468 * @param {Number} col The column index
46469 * @param {Boolean} hscroll false to disable horizontal scrolling
46471 focusCell : function(row, col, hscroll){
46472 var el = this.ensureVisible(row, col, hscroll);
46473 this.focusEl.alignTo(el, "tl-tl");
46475 this.focusEl.focus();
46477 this.focusEl.focus.defer(1, this.focusEl);
46482 * Scrolls the specified cell into view
46483 * @param {Number} row The row index
46484 * @param {Number} col The column index
46485 * @param {Boolean} hscroll false to disable horizontal scrolling
46487 ensureVisible : function(row, col, hscroll){
46488 if(typeof row != "number"){
46489 row = row.rowIndex;
46491 if(row < 0 && row >= this.ds.getCount()){
46494 col = (col !== undefined ? col : 0);
46495 var cm = this.grid.colModel;
46496 while(cm.isHidden(col)){
46500 var el = this.getCell(row, col);
46504 var c = this.scroller.dom;
46506 var ctop = parseInt(el.offsetTop, 10);
46507 var cleft = parseInt(el.offsetLeft, 10);
46508 var cbot = ctop + el.offsetHeight;
46509 var cright = cleft + el.offsetWidth;
46511 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
46512 var stop = parseInt(c.scrollTop, 10);
46513 var sleft = parseInt(c.scrollLeft, 10);
46514 var sbot = stop + ch;
46515 var sright = sleft + c.clientWidth;
46518 c.scrollTop = ctop;
46519 }else if(cbot > sbot){
46520 c.scrollTop = cbot-ch;
46523 if(hscroll !== false){
46525 c.scrollLeft = cleft;
46526 }else if(cright > sright){
46527 c.scrollLeft = cright-c.clientWidth;
46533 updateColumns : function(){
46534 this.grid.stopEditing();
46535 var cm = this.grid.colModel, colIds = this.getColumnIds();
46536 //var totalWidth = cm.getTotalWidth();
46538 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46539 //if(cm.isHidden(i)) continue;
46540 var w = cm.getColumnWidth(i);
46541 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46542 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46544 this.updateSplitters();
46547 generateRules : function(cm){
46548 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
46549 Roo.util.CSS.removeStyleSheet(rulesId);
46550 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46551 var cid = cm.getColumnId(i);
46553 if(cm.config[i].align){
46554 align = 'text-align:'+cm.config[i].align+';';
46557 if(cm.isHidden(i)){
46558 hidden = 'display:none;';
46560 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
46562 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
46563 this.hdSelector, cid, " {\n", align, width, "}\n",
46564 this.tdSelector, cid, " {\n",hidden,"\n}\n",
46565 this.splitSelector, cid, " {\n", hidden , "\n}\n");
46567 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46570 updateSplitters : function(){
46571 var cm = this.cm, s = this.getSplitters();
46572 if(s){ // splitters not created yet
46573 var pos = 0, locked = true;
46574 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46575 if(cm.isHidden(i)) continue;
46576 var w = cm.getColumnWidth(i);
46577 if(!cm.isLocked(i) && locked){
46582 s[i].style.left = (pos-this.splitOffset) + "px";
46587 handleHiddenChange : function(colModel, colIndex, hidden){
46589 this.hideColumn(colIndex);
46591 this.unhideColumn(colIndex);
46595 hideColumn : function(colIndex){
46596 var cid = this.getColumnId(colIndex);
46597 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
46598 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
46600 this.updateHeaders();
46602 this.updateSplitters();
46606 unhideColumn : function(colIndex){
46607 var cid = this.getColumnId(colIndex);
46608 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
46609 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
46612 this.updateHeaders();
46614 this.updateSplitters();
46618 insertRows : function(dm, firstRow, lastRow, isUpdate){
46619 if(firstRow == 0 && lastRow == dm.getCount()-1){
46623 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
46625 var s = this.getScrollState();
46626 var markup = this.renderRows(firstRow, lastRow);
46627 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
46628 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
46629 this.restoreScroll(s);
46631 this.fireEvent("rowsinserted", this, firstRow, lastRow);
46632 this.syncRowHeights(firstRow, lastRow);
46633 this.stripeRows(firstRow);
46639 bufferRows : function(markup, target, index){
46640 var before = null, trows = target.rows, tbody = target.tBodies[0];
46641 if(index < trows.length){
46642 before = trows[index];
46644 var b = document.createElement("div");
46645 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
46646 var rows = b.firstChild.rows;
46647 for(var i = 0, len = rows.length; i < len; i++){
46649 tbody.insertBefore(rows[0], before);
46651 tbody.appendChild(rows[0]);
46658 deleteRows : function(dm, firstRow, lastRow){
46659 if(dm.getRowCount()<1){
46660 this.fireEvent("beforerefresh", this);
46661 this.mainBody.update("");
46662 this.lockedBody.update("");
46663 this.fireEvent("refresh", this);
46665 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
46666 var bt = this.getBodyTable();
46667 var tbody = bt.firstChild;
46668 var rows = bt.rows;
46669 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
46670 tbody.removeChild(rows[firstRow]);
46672 this.stripeRows(firstRow);
46673 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
46677 updateRows : function(dataSource, firstRow, lastRow){
46678 var s = this.getScrollState();
46680 this.restoreScroll(s);
46683 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
46687 this.updateHeaderSortState();
46690 getScrollState : function(){
46691 var sb = this.scroller.dom;
46692 return {left: sb.scrollLeft, top: sb.scrollTop};
46695 stripeRows : function(startRow){
46696 if(!this.grid.stripeRows || this.ds.getCount() < 1){
46699 startRow = startRow || 0;
46700 var rows = this.getBodyTable().rows;
46701 var lrows = this.getLockedTable().rows;
46702 var cls = ' x-grid-row-alt ';
46703 for(var i = startRow, len = rows.length; i < len; i++){
46704 var row = rows[i], lrow = lrows[i];
46705 var isAlt = ((i+1) % 2 == 0);
46706 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
46707 if(isAlt == hasAlt){
46711 row.className += " x-grid-row-alt";
46713 row.className = row.className.replace("x-grid-row-alt", "");
46716 lrow.className = row.className;
46721 restoreScroll : function(state){
46722 var sb = this.scroller.dom;
46723 sb.scrollLeft = state.left;
46724 sb.scrollTop = state.top;
46728 syncScroll : function(){
46729 var sb = this.scroller.dom;
46730 var sh = this.mainHd.dom;
46731 var bs = this.mainBody.dom;
46732 var lv = this.lockedBody.dom;
46733 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
46734 lv.scrollTop = bs.scrollTop = sb.scrollTop;
46737 handleScroll : function(e){
46739 var sb = this.scroller.dom;
46740 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
46744 handleWheel : function(e){
46745 var d = e.getWheelDelta();
46746 this.scroller.dom.scrollTop -= d*22;
46747 // set this here to prevent jumpy scrolling on large tables
46748 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
46752 renderRows : function(startRow, endRow){
46753 // pull in all the crap needed to render rows
46754 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
46755 var colCount = cm.getColumnCount();
46757 if(ds.getCount() < 1){
46761 // build a map for all the columns
46763 for(var i = 0; i < colCount; i++){
46764 var name = cm.getDataIndex(i);
46766 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
46767 renderer : cm.getRenderer(i),
46768 id : cm.getColumnId(i),
46769 locked : cm.isLocked(i)
46773 startRow = startRow || 0;
46774 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
46776 // records to render
46777 var rs = ds.getRange(startRow, endRow);
46779 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
46782 // As much as I hate to duplicate code, this was branched because FireFox really hates
46783 // [].join("") on strings. The performance difference was substantial enough to
46784 // branch this function
46785 doRender : Roo.isGecko ?
46786 function(cs, rs, ds, startRow, colCount, stripe){
46787 var ts = this.templates, ct = ts.cell, rt = ts.row;
46789 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
46790 for(var j = 0, len = rs.length; j < len; j++){
46791 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
46792 for(var i = 0; i < colCount; i++){
46794 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
46796 p.css = p.attr = "";
46797 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
46798 if(p.value == undefined || p.value === "") p.value = " ";
46799 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
46800 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
46802 var markup = ct.apply(p);
46810 if(stripe && ((rowIndex+1) % 2 == 0)){
46811 alt[0] = "x-grid-row-alt";
46814 alt[1] = " x-grid-dirty-row";
46817 if(this.getRowClass){
46818 alt[2] = this.getRowClass(r, rowIndex);
46820 rp.alt = alt.join(" ");
46821 lbuf+= rt.apply(rp);
46823 buf+= rt.apply(rp);
46825 return [lbuf, buf];
46827 function(cs, rs, ds, startRow, colCount, stripe){
46828 var ts = this.templates, ct = ts.cell, rt = ts.row;
46830 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
46831 for(var j = 0, len = rs.length; j < len; j++){
46832 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
46833 for(var i = 0; i < colCount; i++){
46835 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
46837 p.css = p.attr = "";
46838 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
46839 if(p.value == undefined || p.value === "") p.value = " ";
46840 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
46841 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
46843 var markup = ct.apply(p);
46845 cb[cb.length] = markup;
46847 lcb[lcb.length] = markup;
46851 if(stripe && ((rowIndex+1) % 2 == 0)){
46852 alt[0] = "x-grid-row-alt";
46855 alt[1] = " x-grid-dirty-row";
46858 if(this.getRowClass){
46859 alt[2] = this.getRowClass(r, rowIndex);
46861 rp.alt = alt.join(" ");
46862 rp.cells = lcb.join("");
46863 lbuf[lbuf.length] = rt.apply(rp);
46864 rp.cells = cb.join("");
46865 buf[buf.length] = rt.apply(rp);
46867 return [lbuf.join(""), buf.join("")];
46870 renderBody : function(){
46871 var markup = this.renderRows();
46872 var bt = this.templates.body;
46873 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
46877 * Refreshes the grid
46878 * @param {Boolean} headersToo
46880 refresh : function(headersToo){
46881 this.fireEvent("beforerefresh", this);
46882 this.grid.stopEditing();
46883 var result = this.renderBody();
46884 this.lockedBody.update(result[0]);
46885 this.mainBody.update(result[1]);
46886 if(headersToo === true){
46887 this.updateHeaders();
46888 this.updateColumns();
46889 this.updateSplitters();
46890 this.updateHeaderSortState();
46892 this.syncRowHeights();
46894 this.fireEvent("refresh", this);
46897 handleColumnMove : function(cm, oldIndex, newIndex){
46898 this.indexMap = null;
46899 var s = this.getScrollState();
46900 this.refresh(true);
46901 this.restoreScroll(s);
46902 this.afterMove(newIndex);
46905 afterMove : function(colIndex){
46906 if(this.enableMoveAnim && Roo.enableFx){
46907 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
46911 updateCell : function(dm, rowIndex, dataIndex){
46912 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
46913 if(typeof colIndex == "undefined"){ // not present in grid
46916 var cm = this.grid.colModel;
46917 var cell = this.getCell(rowIndex, colIndex);
46918 var cellText = this.getCellText(rowIndex, colIndex);
46921 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
46922 id : cm.getColumnId(colIndex),
46923 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
46925 var renderer = cm.getRenderer(colIndex);
46926 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
46927 if(typeof val == "undefined" || val === "") val = " ";
46928 cellText.innerHTML = val;
46929 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
46930 this.syncRowHeights(rowIndex, rowIndex);
46933 calcColumnWidth : function(colIndex, maxRowsToMeasure){
46935 if(this.grid.autoSizeHeaders){
46936 var h = this.getHeaderCellMeasure(colIndex);
46937 maxWidth = Math.max(maxWidth, h.scrollWidth);
46940 if(this.cm.isLocked(colIndex)){
46941 tb = this.getLockedTable();
46944 tb = this.getBodyTable();
46945 index = colIndex - this.cm.getLockedCount();
46948 var rows = tb.rows;
46949 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
46950 for(var i = 0; i < stopIndex; i++){
46951 var cell = rows[i].childNodes[index].firstChild;
46952 maxWidth = Math.max(maxWidth, cell.scrollWidth);
46955 return maxWidth + /*margin for error in IE*/ 5;
46958 * Autofit a column to its content.
46959 * @param {Number} colIndex
46960 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
46962 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
46963 if(this.cm.isHidden(colIndex)){
46964 return; // can't calc a hidden column
46967 var cid = this.cm.getColumnId(colIndex);
46968 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
46969 if(this.grid.autoSizeHeaders){
46970 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
46973 var newWidth = this.calcColumnWidth(colIndex);
46974 this.cm.setColumnWidth(colIndex,
46975 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
46976 if(!suppressEvent){
46977 this.grid.fireEvent("columnresize", colIndex, newWidth);
46982 * Autofits all columns to their content and then expands to fit any extra space in the grid
46984 autoSizeColumns : function(){
46985 var cm = this.grid.colModel;
46986 var colCount = cm.getColumnCount();
46987 for(var i = 0; i < colCount; i++){
46988 this.autoSizeColumn(i, true, true);
46990 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
46993 this.updateColumns();
46999 * Autofits all columns to the grid's width proportionate with their current size
47000 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
47002 fitColumns : function(reserveScrollSpace){
47003 var cm = this.grid.colModel;
47004 var colCount = cm.getColumnCount();
47008 for (i = 0; i < colCount; i++){
47009 if(!cm.isHidden(i) && !cm.isFixed(i)){
47010 w = cm.getColumnWidth(i);
47016 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
47017 if(reserveScrollSpace){
47020 var frac = (avail - cm.getTotalWidth())/width;
47021 while (cols.length){
47024 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
47026 this.updateColumns();
47030 onRowSelect : function(rowIndex){
47031 var row = this.getRowComposite(rowIndex);
47032 row.addClass("x-grid-row-selected");
47035 onRowDeselect : function(rowIndex){
47036 var row = this.getRowComposite(rowIndex);
47037 row.removeClass("x-grid-row-selected");
47040 onCellSelect : function(row, col){
47041 var cell = this.getCell(row, col);
47043 Roo.fly(cell).addClass("x-grid-cell-selected");
47047 onCellDeselect : function(row, col){
47048 var cell = this.getCell(row, col);
47050 Roo.fly(cell).removeClass("x-grid-cell-selected");
47054 updateHeaderSortState : function(){
47055 var state = this.ds.getSortState();
47059 this.sortState = state;
47060 var sortColumn = this.cm.findColumnIndex(state.field);
47061 if(sortColumn != -1){
47062 var sortDir = state.direction;
47063 var sc = this.sortClasses;
47064 var hds = this.el.select(this.headerSelector).removeClass(sc);
47065 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
47069 handleHeaderClick : function(g, index){
47070 if(this.headersDisabled){
47073 var dm = g.dataSource, cm = g.colModel;
47074 if(!cm.isSortable(index)){
47078 dm.sort(cm.getDataIndex(index));
47082 destroy : function(){
47084 this.colMenu.removeAll();
47085 Roo.menu.MenuMgr.unregister(this.colMenu);
47086 this.colMenu.getEl().remove();
47087 delete this.colMenu;
47090 this.hmenu.removeAll();
47091 Roo.menu.MenuMgr.unregister(this.hmenu);
47092 this.hmenu.getEl().remove();
47095 if(this.grid.enableColumnMove){
47096 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47098 for(var dd in dds){
47099 if(!dds[dd].config.isTarget && dds[dd].dragElId){
47100 var elid = dds[dd].dragElId;
47102 Roo.get(elid).remove();
47103 } else if(dds[dd].config.isTarget){
47104 dds[dd].proxyTop.remove();
47105 dds[dd].proxyBottom.remove();
47108 if(Roo.dd.DDM.locationCache[dd]){
47109 delete Roo.dd.DDM.locationCache[dd];
47112 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47115 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
47116 this.bind(null, null);
47117 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
47120 handleLockChange : function(){
47121 this.refresh(true);
47124 onDenyColumnLock : function(){
47128 onDenyColumnHide : function(){
47132 handleHdMenuClick : function(item){
47133 var index = this.hdCtxIndex;
47134 var cm = this.cm, ds = this.ds;
47137 ds.sort(cm.getDataIndex(index), "ASC");
47140 ds.sort(cm.getDataIndex(index), "DESC");
47143 var lc = cm.getLockedCount();
47144 if(cm.getColumnCount(true) <= lc+1){
47145 this.onDenyColumnLock();
47149 cm.setLocked(index, true, true);
47150 cm.moveColumn(index, lc);
47151 this.grid.fireEvent("columnmove", index, lc);
47153 cm.setLocked(index, true);
47157 var lc = cm.getLockedCount();
47158 if((lc-1) != index){
47159 cm.setLocked(index, false, true);
47160 cm.moveColumn(index, lc-1);
47161 this.grid.fireEvent("columnmove", index, lc-1);
47163 cm.setLocked(index, false);
47167 index = cm.getIndexById(item.id.substr(4));
47169 if(item.checked && cm.getColumnCount(true) <= 1){
47170 this.onDenyColumnHide();
47173 cm.setHidden(index, item.checked);
47179 beforeColMenuShow : function(){
47180 var cm = this.cm, colCount = cm.getColumnCount();
47181 this.colMenu.removeAll();
47182 for(var i = 0; i < colCount; i++){
47183 this.colMenu.add(new Roo.menu.CheckItem({
47184 id: "col-"+cm.getColumnId(i),
47185 text: cm.getColumnHeader(i),
47186 checked: !cm.isHidden(i),
47192 handleHdCtx : function(g, index, e){
47194 var hd = this.getHeaderCell(index);
47195 this.hdCtxIndex = index;
47196 var ms = this.hmenu.items, cm = this.cm;
47197 ms.get("asc").setDisabled(!cm.isSortable(index));
47198 ms.get("desc").setDisabled(!cm.isSortable(index));
47199 if(this.grid.enableColLock !== false){
47200 ms.get("lock").setDisabled(cm.isLocked(index));
47201 ms.get("unlock").setDisabled(!cm.isLocked(index));
47203 this.hmenu.show(hd, "tl-bl");
47206 handleHdOver : function(e){
47207 var hd = this.findHeaderCell(e.getTarget());
47208 if(hd && !this.headersDisabled){
47209 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
47210 this.fly(hd).addClass("x-grid-hd-over");
47215 handleHdOut : function(e){
47216 var hd = this.findHeaderCell(e.getTarget());
47218 this.fly(hd).removeClass("x-grid-hd-over");
47222 handleSplitDblClick : function(e, t){
47223 var i = this.getCellIndex(t);
47224 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
47225 this.autoSizeColumn(i, true);
47230 render : function(){
47233 var colCount = cm.getColumnCount();
47235 if(this.grid.monitorWindowResize === true){
47236 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47238 var header = this.renderHeaders();
47239 var body = this.templates.body.apply({rows:""});
47240 var html = this.templates.master.apply({
47243 lockedHeader: header[0],
47247 //this.updateColumns();
47249 this.grid.getGridEl().dom.innerHTML = html;
47251 this.initElements();
47253 this.scroller.on("scroll", this.handleScroll, this);
47254 this.lockedBody.on("mousewheel", this.handleWheel, this);
47255 this.mainBody.on("mousewheel", this.handleWheel, this);
47257 this.mainHd.on("mouseover", this.handleHdOver, this);
47258 this.mainHd.on("mouseout", this.handleHdOut, this);
47259 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
47260 {delegate: "."+this.splitClass});
47262 this.lockedHd.on("mouseover", this.handleHdOver, this);
47263 this.lockedHd.on("mouseout", this.handleHdOut, this);
47264 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
47265 {delegate: "."+this.splitClass});
47267 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
47268 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47271 this.updateSplitters();
47273 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
47274 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47275 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47278 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
47279 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
47281 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
47282 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
47284 if(this.grid.enableColLock !== false){
47285 this.hmenu.add('-',
47286 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
47287 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
47290 if(this.grid.enableColumnHide !== false){
47292 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
47293 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
47294 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
47296 this.hmenu.add('-',
47297 {id:"columns", text: this.columnsText, menu: this.colMenu}
47300 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
47302 this.grid.on("headercontextmenu", this.handleHdCtx, this);
47305 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
47306 this.dd = new Roo.grid.GridDragZone(this.grid, {
47307 ddGroup : this.grid.ddGroup || 'GridDD'
47312 for(var i = 0; i < colCount; i++){
47313 if(cm.isHidden(i)){
47314 this.hideColumn(i);
47316 if(cm.config[i].align){
47317 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
47318 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
47322 this.updateHeaderSortState();
47324 this.beforeInitialResize();
47327 // two part rendering gives faster view to the user
47328 this.renderPhase2.defer(1, this);
47331 renderPhase2 : function(){
47332 // render the rows now
47334 if(this.grid.autoSizeColumns){
47335 this.autoSizeColumns();
47339 beforeInitialResize : function(){
47343 onColumnSplitterMoved : function(i, w){
47344 this.userResized = true;
47345 var cm = this.grid.colModel;
47346 cm.setColumnWidth(i, w, true);
47347 var cid = cm.getColumnId(i);
47348 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47349 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47350 this.updateSplitters();
47352 this.grid.fireEvent("columnresize", i, w);
47355 syncRowHeights : function(startIndex, endIndex){
47356 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
47357 startIndex = startIndex || 0;
47358 var mrows = this.getBodyTable().rows;
47359 var lrows = this.getLockedTable().rows;
47360 var len = mrows.length-1;
47361 endIndex = Math.min(endIndex || len, len);
47362 for(var i = startIndex; i <= endIndex; i++){
47363 var m = mrows[i], l = lrows[i];
47364 var h = Math.max(m.offsetHeight, l.offsetHeight);
47365 m.style.height = l.style.height = h + "px";
47370 layout : function(initialRender, is2ndPass){
47372 var auto = g.autoHeight;
47373 var scrollOffset = 16;
47374 var c = g.getGridEl(), cm = this.cm,
47375 expandCol = g.autoExpandColumn,
47377 //c.beginMeasure();
47379 if(!c.dom.offsetWidth){ // display:none?
47381 this.lockedWrap.show();
47382 this.mainWrap.show();
47387 var hasLock = this.cm.isLocked(0);
47389 var tbh = this.headerPanel.getHeight();
47390 var bbh = this.footerPanel.getHeight();
47393 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
47394 var newHeight = ch + c.getBorderWidth("tb");
47396 newHeight = Math.min(g.maxHeight, newHeight);
47398 c.setHeight(newHeight);
47402 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
47405 var s = this.scroller;
47407 var csize = c.getSize(true);
47409 this.el.setSize(csize.width, csize.height);
47411 this.headerPanel.setWidth(csize.width);
47412 this.footerPanel.setWidth(csize.width);
47414 var hdHeight = this.mainHd.getHeight();
47415 var vw = csize.width;
47416 var vh = csize.height - (tbh + bbh);
47420 var bt = this.getBodyTable();
47421 var ltWidth = hasLock ?
47422 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
47424 var scrollHeight = bt.offsetHeight;
47425 var scrollWidth = ltWidth + bt.offsetWidth;
47426 var vscroll = false, hscroll = false;
47428 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
47430 var lw = this.lockedWrap, mw = this.mainWrap;
47431 var lb = this.lockedBody, mb = this.mainBody;
47433 setTimeout(function(){
47434 var t = s.dom.offsetTop;
47435 var w = s.dom.clientWidth,
47436 h = s.dom.clientHeight;
47439 lw.setSize(ltWidth, h);
47441 mw.setLeftTop(ltWidth, t);
47442 mw.setSize(w-ltWidth, h);
47444 lb.setHeight(h-hdHeight);
47445 mb.setHeight(h-hdHeight);
47447 if(is2ndPass !== true && !gv.userResized && expandCol){
47448 // high speed resize without full column calculation
47450 var ci = cm.getIndexById(expandCol);
47452 ci = cm.findColumnIndex(expandCol);
47454 ci = Math.max(0, ci); // make sure it's got at least the first col.
47455 var expandId = cm.getColumnId(ci);
47456 var tw = cm.getTotalWidth(false);
47457 var currentWidth = cm.getColumnWidth(ci);
47458 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
47459 if(currentWidth != cw){
47460 cm.setColumnWidth(ci, cw, true);
47461 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47462 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47463 gv.updateSplitters();
47464 gv.layout(false, true);
47476 onWindowResize : function(){
47477 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
47483 appendFooter : function(parentEl){
47487 sortAscText : "Sort Ascending",
47488 sortDescText : "Sort Descending",
47489 lockText : "Lock Column",
47490 unlockText : "Unlock Column",
47491 columnsText : "Columns"
47495 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
47496 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
47497 this.proxy.el.addClass('x-grid3-col-dd');
47500 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
47501 handleMouseDown : function(e){
47505 callHandleMouseDown : function(e){
47506 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);