4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
90 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
93 enableGarbageCollector : true,
96 * True to automatically purge event listeners after uncaching an element (defaults to false).
97 * Note: this only happens if enableGarbageCollector is true.
100 enableListenerCollection:false,
103 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
104 * the IE insecure content warning (defaults to javascript:false).
107 SSL_SECURE_URL : "javascript:false",
110 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
111 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
114 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
116 emptyFn : function(){},
119 * Copies all the properties of config to obj if they don't already exist.
120 * @param {Object} obj The receiver of the properties
121 * @param {Object} config The source of the properties
122 * @return {Object} returns obj
124 applyIf : function(o, c){
127 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134 * Applies event listeners to elements by selectors when the document is ready.
135 * The event name is specified with an @ suffix.
138 // add a listener for click on all anchors in element with id foo
139 '#foo a@click' : function(e, t){
143 // add the same listener to multiple selectors (separated by comma BEFORE the @)
144 '#foo a, #bar span.some-class@mouseover' : function(){
149 * @param {Object} obj The list of behaviors to apply
151 addBehaviors : function(o){
153 Roo.onReady(function(){
158 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
160 var parts = b.split('@');
161 if(parts[1]){ // for Object prototype breakers
164 cache[s] = Roo.select(s);
166 cache[s].on(parts[1], o[b]);
173 * Generates unique ids. If the element already has an id, it is unchanged
174 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
175 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
176 * @return {String} The generated Id.
178 id : function(el, prefix){
179 prefix = prefix || "roo-gen";
181 var id = prefix + (++idSeed);
182 return el ? (el.id ? el.id : (el.id = id)) : id;
187 * Extends one class with another class and optionally overrides members with the passed literal. This class
188 * also adds the function "override()" to the class that can be used to override
189 * members on an instance.
190 * @param {Object} subclass The class inheriting the functionality
191 * @param {Object} superclass The class being extended
192 * @param {Object} overrides (optional) A literal with members
197 var io = function(o){
202 return function(sb, sp, overrides){
203 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
206 sb = function(){sp.apply(this, arguments);};
208 var F = function(){}, sbp, spp = sp.prototype;
210 sbp = sb.prototype = new F();
214 if(spp.constructor == Object.prototype.constructor){
219 sb.override = function(o){
223 Roo.override(sb, overrides);
229 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
231 Roo.override(MyClass, {
232 newMethod1: function(){
235 newMethod2: function(foo){
240 * @param {Object} origclass The class to override
241 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
242 * containing one or more methods.
245 override : function(origclass, overrides){
247 var p = origclass.prototype;
248 for(var method in overrides){
249 p[method] = overrides[method];
254 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
256 Roo.namespace('Company', 'Company.data');
257 Company.Widget = function() { ... }
258 Company.data.CustomStore = function(config) { ... }
260 * @param {String} namespace1
261 * @param {String} namespace2
262 * @param {String} etc
265 namespace : function(){
266 var a=arguments, o=null, i, j, d, rt;
267 for (i=0; i<a.length; ++i) {
271 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
272 for (j=1; j<d.length; ++j) {
273 o[d[j]]=o[d[j]] || {};
279 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
281 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
282 Roo.factory(conf, Roo.data);
284 * @param {String} classname
285 * @param {String} namespace (optional)
289 factory : function(c, ns)
291 // no xtype, no ns or c.xns - or forced off by c.xns
292 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
295 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
296 if (c.constructor == ns[c.xtype]) {// already created...
300 if (Roo.debug) console.log("Roo.Factory(" + c.xtype + ")");
301 var ret = new ns[c.xtype](c);
305 c.xns = false; // prevent recursion..
310 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
314 urlEncode : function(o){
320 var ov = o[key], k = encodeURIComponent(key);
321 var type = typeof ov;
322 if(type == 'undefined'){
324 }else if(type != "function" && type != "object"){
325 buf.push(k, "=", encodeURIComponent(ov), "&");
326 }else if(ov instanceof Array){
328 for(var i = 0, len = ov.length; i < len; i++) {
329 buf.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
341 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
342 * @param {String} string
343 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
344 * @return {Object} A literal with members
346 urlDecode : function(string, overwrite){
347 if(!string || !string.length){
351 var pairs = string.split('&');
352 var pair, name, value;
353 for(var i = 0, len = pairs.length; i < len; i++){
354 pair = pairs[i].split('=');
355 name = decodeURIComponent(pair[0]);
356 value = decodeURIComponent(pair[1]);
357 if(overwrite !== true){
358 if(typeof obj[name] == "undefined"){
360 }else if(typeof obj[name] == "string"){
361 obj[name] = [obj[name]];
362 obj[name].push(value);
364 obj[name].push(value);
374 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
375 * passed array is not really an array, your function is called once with it.
376 * The supplied function is called with (Object item, Number index, Array allItems).
377 * @param {Array/NodeList/Mixed} array
378 * @param {Function} fn
379 * @param {Object} scope
381 each : function(array, fn, scope){
382 if(typeof array.length == "undefined" || typeof array == "string"){
385 for(var i = 0, len = array.length; i < len; i++){
386 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
391 combine : function(){
392 var as = arguments, l = as.length, r = [];
393 for(var i = 0; i < l; i++){
395 if(a instanceof Array){
397 }else if(a.length !== undefined && !a.substr){
398 r = r.concat(Array.prototype.slice.call(a, 0));
407 * Escapes the passed string for use in a regular expression
408 * @param {String} str
411 escapeRe : function(s) {
412 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
416 callback : function(cb, scope, args, delay){
417 if(typeof cb == "function"){
419 cb.defer(delay, scope, args || []);
421 cb.apply(scope, args || []);
427 * Return the dom node for the passed string (id), dom node, or Roo.Element
428 * @param {String/HTMLElement/Roo.Element} el
429 * @return HTMLElement
431 getDom : function(el){
435 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
439 * Shorthand for {@link Roo.ComponentMgr#get}
441 * @return Roo.Component
443 getCmp : function(id){
444 return Roo.ComponentMgr.get(id);
447 num : function(v, defaultValue){
448 if(typeof v != 'number'){
454 destroy : function(){
455 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
459 as.removeAllListeners();
463 if(typeof as.purgeListeners == 'function'){
466 if(typeof as.destroy == 'function'){
473 // inpired by a similar function in mootools library
475 * Returns the type of object that is passed in. If the object passed in is null or undefined it
476 * return false otherwise it returns one of the following values:<ul>
477 * <li><b>string</b>: If the object passed is a string</li>
478 * <li><b>number</b>: If the object passed is a number</li>
479 * <li><b>boolean</b>: If the object passed is a boolean value</li>
480 * <li><b>function</b>: If the object passed is a function reference</li>
481 * <li><b>object</b>: If the object passed is an object</li>
482 * <li><b>array</b>: If the object passed is an array</li>
483 * <li><b>regexp</b>: If the object passed is a regular expression</li>
484 * <li><b>element</b>: If the object passed is a DOM Element</li>
485 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
486 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
487 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
488 * @param {Mixed} object
492 if(o === undefined || o === null){
499 if(t == 'object' && o.nodeName) {
501 case 1: return 'element';
502 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
505 if(t == 'object' || t == 'function') {
506 switch(o.constructor) {
507 case Array: return 'array';
508 case RegExp: return 'regexp';
510 if(typeof o.length == 'number' && typeof o.item == 'function') {
518 * Returns true if the passed value is null, undefined or an empty string (optional).
519 * @param {Mixed} value The value to test
520 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
523 isEmpty : function(v, allowBlank){
524 return v === null || v === undefined || (!allowBlank ? v === '' : false);
538 isBorderBox : isBorderBox,
540 isWindows : isWindows,
547 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
548 * you may want to set this to true.
551 useShims : ((isIE && !isIE7) || (isGecko && isMac))
557 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
558 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
561 * Ext JS Library 1.1.1
562 * Copyright(c) 2006-2007, Ext JS, LLC.
564 * Originally Released Under LGPL - original licence link has changed is not relivant.
567 * <script type="text/javascript">
571 // wrappedn so fnCleanup is not in global scope...
573 function fnCleanUp() {
574 var p = Function.prototype;
575 delete p.createSequence;
577 delete p.createDelegate;
578 delete p.createCallback;
579 delete p.createInterceptor;
581 window.detachEvent("onunload", fnCleanUp);
583 window.attachEvent("onunload", fnCleanUp);
590 * These functions are available on every Function object (any JavaScript function).
592 Roo.apply(Function.prototype, {
594 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
595 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
596 * Will create a function that is bound to those 2 args.
597 * @return {Function} The new function
599 createCallback : function(/*args...*/){
600 // make args available, in function below
601 var args = arguments;
604 return method.apply(window, args);
609 * Creates a delegate (callback) that sets the scope to obj.
610 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
611 * Will create a function that is automatically scoped to this.
612 * @param {Object} obj (optional) The object for which the scope is set
613 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
614 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
615 * if a number the args are inserted at the specified position
616 * @return {Function} The new function
618 createDelegate : function(obj, args, appendArgs){
621 var callArgs = args || arguments;
622 if(appendArgs === true){
623 callArgs = Array.prototype.slice.call(arguments, 0);
624 callArgs = callArgs.concat(args);
625 }else if(typeof appendArgs == "number"){
626 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
627 var applyArgs = [appendArgs, 0].concat(args); // create method call params
628 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
630 return method.apply(obj || window, callArgs);
635 * Calls this function after the number of millseconds specified.
636 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
637 * @param {Object} obj (optional) The object for which the scope is set
638 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
639 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
640 * if a number the args are inserted at the specified position
641 * @return {Number} The timeout id that can be used with clearTimeout
643 defer : function(millis, obj, args, appendArgs){
644 var fn = this.createDelegate(obj, args, appendArgs);
646 return setTimeout(fn, millis);
652 * Create a combined function call sequence of the original function + the passed function.
653 * The resulting function returns the results of the original function.
654 * The passed fcn is called with the parameters of the original function
655 * @param {Function} fcn The function to sequence
656 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
657 * @return {Function} The new function
659 createSequence : function(fcn, scope){
660 if(typeof fcn != "function"){
665 var retval = method.apply(this || window, arguments);
666 fcn.apply(scope || this || window, arguments);
672 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
673 * The resulting function returns the results of the original function.
674 * The passed fcn is called with the parameters of the original function.
676 * @param {Function} fcn The function to call before the original
677 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
678 * @return {Function} The new function
680 createInterceptor : function(fcn, scope){
681 if(typeof fcn != "function"){
688 if(fcn.apply(scope || this || window, arguments) === false){
691 return method.apply(this || window, arguments);
697 * Ext JS Library 1.1.1
698 * Copyright(c) 2006-2007, Ext JS, LLC.
700 * Originally Released Under LGPL - original licence link has changed is not relivant.
703 * <script type="text/javascript">
706 Roo.applyIf(String, {
711 * Escapes the passed string for ' and \
712 * @param {String} string The string to escape
713 * @return {String} The escaped string
716 escape : function(string) {
717 return string.replace(/('|\\)/g, "\\$1");
721 * Pads the left side of a string with a specified character. This is especially useful
722 * for normalizing number and date strings. Example usage:
724 var s = String.leftPad('123', 5, '0');
725 // s now contains the string: '00123'
727 * @param {String} string The original string
728 * @param {Number} size The total length of the output string
729 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
730 * @return {String} The padded string
733 leftPad : function (val, size, ch) {
734 var result = new String(val);
735 if(ch === null || ch === undefined || ch === '') {
738 while (result.length < size) {
739 result = ch + result;
745 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
746 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
748 var cls = 'my-class', text = 'Some text';
749 var s = String.format('<div class="{0}">{1}</div>', cls, text);
750 // s now contains the string: '<div class="my-class">Some text</div>'
752 * @param {String} string The tokenized string to be formatted
753 * @param {String} value1 The value to replace token {0}
754 * @param {String} value2 Etc...
755 * @return {String} The formatted string
758 format : function(format){
759 var args = Array.prototype.slice.call(arguments, 1);
760 return format.replace(/\{(\d+)\}/g, function(m, i){
761 return Roo.util.Format.htmlEncode(args[i]);
767 * Utility function that allows you to easily switch a string between two alternating values. The passed value
768 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
769 * they are already different, the first value passed in is returned. Note that this method returns the new value
770 * but does not change the current string.
772 // alternate sort directions
773 sort = sort.toggle('ASC', 'DESC');
775 // instead of conditional logic:
776 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
778 * @param {String} value The value to compare to the current string
779 * @param {String} other The new value to use if the string already equals the first value passed in
780 * @return {String} The new value
783 String.prototype.toggle = function(value, other){
784 return this == value ? other : value;
787 * Ext JS Library 1.1.1
788 * Copyright(c) 2006-2007, Ext JS, LLC.
790 * Originally Released Under LGPL - original licence link has changed is not relivant.
793 * <script type="text/javascript">
799 Roo.applyIf(Number.prototype, {
801 * Checks whether or not the current number is within a desired range. If the number is already within the
802 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
803 * exceeded. Note that this method returns the constrained value but does not change the current number.
804 * @param {Number} min The minimum number in the range
805 * @param {Number} max The maximum number in the range
806 * @return {Number} The constrained value if outside the range, otherwise the current value
808 constrain : function(min, max){
809 return Math.min(Math.max(this, min), max);
813 * Ext JS Library 1.1.1
814 * Copyright(c) 2006-2007, Ext JS, LLC.
816 * Originally Released Under LGPL - original licence link has changed is not relivant.
819 * <script type="text/javascript">
824 Roo.applyIf(Array.prototype, {
826 * Checks whether or not the specified object exists in the array.
827 * @param {Object} o The object to check for
828 * @return {Number} The index of o in the array (or -1 if it is not found)
830 indexOf : function(o){
831 for (var i = 0, len = this.length; i < len; i++){
832 if(this[i] == o) return i;
838 * Removes the specified object from the array. If the object is not found nothing happens.
839 * @param {Object} o The object to remove
841 remove : function(o){
842 var index = this.indexOf(o);
844 this.splice(index, 1);
848 * Map (JS 1.6 compatibility)
849 * @param {Function} function to call
853 var len = this.length >>> 0;
854 if (typeof fun != "function")
855 throw new TypeError();
857 var res = new Array(len);
858 var thisp = arguments[1];
859 for (var i = 0; i < len; i++)
862 res[i] = fun.call(thisp, this[i], i, this);
873 * Ext JS Library 1.1.1
874 * Copyright(c) 2006-2007, Ext JS, LLC.
876 * Originally Released Under LGPL - original licence link has changed is not relivant.
879 * <script type="text/javascript">
885 * The date parsing and format syntax is a subset of
886 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
887 * supported will provide results equivalent to their PHP versions.
889 * Following is the list of all currently supported formats:
892 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
894 Format Output Description
895 ------ ---------- --------------------------------------------------------------
896 d 10 Day of the month, 2 digits with leading zeros
897 D Wed A textual representation of a day, three letters
898 j 10 Day of the month without leading zeros
899 l Wednesday A full textual representation of the day of the week
900 S th English ordinal day of month suffix, 2 chars (use with j)
901 w 3 Numeric representation of the day of the week
902 z 9 The julian date, or day of the year (0-365)
903 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
904 F January A full textual representation of the month
905 m 01 Numeric representation of a month, with leading zeros
906 M Jan Month name abbreviation, three letters
907 n 1 Numeric representation of a month, without leading zeros
908 t 31 Number of days in the given month
909 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
910 Y 2007 A full numeric representation of a year, 4 digits
911 y 07 A two digit representation of a year
912 a pm Lowercase Ante meridiem and Post meridiem
913 A PM Uppercase Ante meridiem and Post meridiem
914 g 3 12-hour format of an hour without leading zeros
915 G 15 24-hour format of an hour without leading zeros
916 h 03 12-hour format of an hour with leading zeros
917 H 15 24-hour format of an hour with leading zeros
918 i 05 Minutes with leading zeros
919 s 01 Seconds, with leading zeros
920 O -0600 Difference to Greenwich time (GMT) in hours
921 T CST Timezone setting of the machine running the code
922 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
925 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
927 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
928 document.write(dt.format('Y-m-d')); //2007-01-10
929 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
930 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
933 * Here are some standard date/time patterns that you might find helpful. They
934 * are not part of the source of Date.js, but to use them you can simply copy this
935 * block of code into any script that is included after Date.js and they will also become
936 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
939 ISO8601Long:"Y-m-d H:i:s",
940 ISO8601Short:"Y-m-d",
942 LongDate: "l, F d, Y",
943 FullDateTime: "l, F d, Y g:i:s A",
947 SortableDateTime: "Y-m-d\\TH:i:s",
948 UniversalSortableDateTime: "Y-m-d H:i:sO",
956 document.write(dt.format(Date.patterns.ShortDate));
961 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
962 * They generate precompiled functions from date formats instead of parsing and
963 * processing the pattern every time you format a date. These functions are available
964 * on every Date object (any javascript function).
966 * The original article and download are here:
967 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
974 Returns the number of milliseconds between this date and date
975 @param {Date} date (optional) Defaults to now
976 @return {Number} The diff in milliseconds
977 @member Date getElapsed
979 Date.prototype.getElapsed = function(date) {
980 return Math.abs((date || new Date()).getTime()-this.getTime());
982 // was in date file..
986 Date.parseFunctions = {count:0};
988 Date.parseRegexes = [];
990 Date.formatFunctions = {count:0};
993 Date.prototype.dateFormat = function(format) {
994 if (Date.formatFunctions[format] == null) {
995 Date.createNewFormat(format);
997 var func = Date.formatFunctions[format];
1003 * Formats a date given the supplied format string
1004 * @param {String} format The format string
1005 * @return {String} The formatted date
1008 Date.prototype.format = Date.prototype.dateFormat;
1011 Date.createNewFormat = function(format) {
1012 var funcName = "format" + Date.formatFunctions.count++;
1013 Date.formatFunctions[format] = funcName;
1014 var code = "Date.prototype." + funcName + " = function(){return ";
1015 var special = false;
1017 for (var i = 0; i < format.length; ++i) {
1018 ch = format.charAt(i);
1019 if (!special && ch == "\\") {
1024 code += "'" + String.escape(ch) + "' + ";
1027 code += Date.getFormatCode(ch);
1030 /** eval:var:zzzzzzzzzzzzz */
1031 eval(code.substring(0, code.length - 3) + ";}");
1035 Date.getFormatCode = function(character) {
1036 switch (character) {
1038 return "String.leftPad(this.getDate(), 2, '0') + ";
1040 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1042 return "this.getDate() + ";
1044 return "Date.dayNames[this.getDay()] + ";
1046 return "this.getSuffix() + ";
1048 return "this.getDay() + ";
1050 return "this.getDayOfYear() + ";
1052 return "this.getWeekOfYear() + ";
1054 return "Date.monthNames[this.getMonth()] + ";
1056 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1058 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1060 return "(this.getMonth() + 1) + ";
1062 return "this.getDaysInMonth() + ";
1064 return "(this.isLeapYear() ? 1 : 0) + ";
1066 return "this.getFullYear() + ";
1068 return "('' + this.getFullYear()).substring(2, 4) + ";
1070 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1072 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1074 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1076 return "this.getHours() + ";
1078 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1080 return "String.leftPad(this.getHours(), 2, '0') + ";
1082 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1084 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1086 return "this.getGMTOffset() + ";
1088 return "this.getTimezone() + ";
1090 return "(this.getTimezoneOffset() * -60) + ";
1092 return "'" + String.escape(character) + "' + ";
1097 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1098 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1099 * the date format that is not specified will default to the current date value for that part. Time parts can also
1100 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1101 * string or the parse operation will fail.
1104 //dt = Fri May 25 2007 (current date)
1105 var dt = new Date();
1107 //dt = Thu May 25 2006 (today's month/day in 2006)
1108 dt = Date.parseDate("2006", "Y");
1110 //dt = Sun Jan 15 2006 (all date parts specified)
1111 dt = Date.parseDate("2006-1-15", "Y-m-d");
1113 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1114 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1116 * @param {String} input The unparsed date as a string
1117 * @param {String} format The format the date is in
1118 * @return {Date} The parsed date
1121 Date.parseDate = function(input, format) {
1122 if (Date.parseFunctions[format] == null) {
1123 Date.createParser(format);
1125 var func = Date.parseFunctions[format];
1126 return Date[func](input);
1131 Date.createParser = function(format) {
1132 var funcName = "parse" + Date.parseFunctions.count++;
1133 var regexNum = Date.parseRegexes.length;
1134 var currentGroup = 1;
1135 Date.parseFunctions[format] = funcName;
1137 var code = "Date." + funcName + " = function(input){\n"
1138 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1139 + "var d = new Date();\n"
1140 + "y = d.getFullYear();\n"
1141 + "m = d.getMonth();\n"
1142 + "d = d.getDate();\n"
1143 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1144 + "if (results && results.length > 0) {";
1147 var special = false;
1149 for (var i = 0; i < format.length; ++i) {
1150 ch = format.charAt(i);
1151 if (!special && ch == "\\") {
1156 regex += String.escape(ch);
1159 var obj = Date.formatCodeToRegex(ch, currentGroup);
1160 currentGroup += obj.g;
1162 if (obj.g && obj.c) {
1168 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1169 + "{v = new Date(y, m, d, h, i, s);}\n"
1170 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1171 + "{v = new Date(y, m, d, h, i);}\n"
1172 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1173 + "{v = new Date(y, m, d, h);}\n"
1174 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1175 + "{v = new Date(y, m, d);}\n"
1176 + "else if (y >= 0 && m >= 0)\n"
1177 + "{v = new Date(y, m);}\n"
1178 + "else if (y >= 0)\n"
1179 + "{v = new Date(y);}\n"
1180 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1181 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1182 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1185 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1186 /** eval:var:zzzzzzzzzzzzz */
1191 Date.formatCodeToRegex = function(character, currentGroup) {
1192 switch (character) {
1196 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1199 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1200 s:"(\\d{1,2})"}; // day of month without leading zeroes
1203 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1204 s:"(\\d{2})"}; // day of month with leading zeroes
1208 s:"(?:" + Date.dayNames.join("|") + ")"};
1212 s:"(?:st|nd|rd|th)"};
1227 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1228 s:"(" + Date.monthNames.join("|") + ")"};
1231 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1232 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1235 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1236 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1239 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1240 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1251 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1255 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1256 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1260 c:"if (results[" + currentGroup + "] == 'am') {\n"
1261 + "if (h == 12) { h = 0; }\n"
1262 + "} else { if (h < 12) { h += 12; }}",
1266 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1267 + "if (h == 12) { h = 0; }\n"
1268 + "} else { if (h < 12) { h += 12; }}",
1273 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1274 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1278 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1279 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1282 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1286 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1291 "o = results[", currentGroup, "];\n",
1292 "var sn = o.substring(0,1);\n", // get + / - sign
1293 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1294 "var mn = o.substring(3,5) % 60;\n", // get minutes
1295 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1296 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1302 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1305 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1306 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1307 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1311 s:String.escape(character)};
1316 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1317 * @return {String} The abbreviated timezone name (e.g. 'CST')
1319 Date.prototype.getTimezone = function() {
1320 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1324 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1325 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1327 Date.prototype.getGMTOffset = function() {
1328 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1329 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1330 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1334 * Get the numeric day number of the year, adjusted for leap year.
1335 * @return {Number} 0 through 364 (365 in leap years)
1337 Date.prototype.getDayOfYear = function() {
1339 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1340 for (var i = 0; i < this.getMonth(); ++i) {
1341 num += Date.daysInMonth[i];
1343 return num + this.getDate() - 1;
1347 * Get the string representation of the numeric week number of the year
1348 * (equivalent to the format specifier 'W').
1349 * @return {String} '00' through '52'
1351 Date.prototype.getWeekOfYear = function() {
1352 // Skip to Thursday of this week
1353 var now = this.getDayOfYear() + (4 - this.getDay());
1354 // Find the first Thursday of the year
1355 var jan1 = new Date(this.getFullYear(), 0, 1);
1356 var then = (7 - jan1.getDay() + 4);
1357 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1361 * Whether or not the current date is in a leap year.
1362 * @return {Boolean} True if the current date is in a leap year, else false
1364 Date.prototype.isLeapYear = function() {
1365 var year = this.getFullYear();
1366 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1370 * Get the first day of the current month, adjusted for leap year. The returned value
1371 * is the numeric day index within the week (0-6) which can be used in conjunction with
1372 * the {@link #monthNames} array to retrieve the textual day name.
1375 var dt = new Date('1/10/2007');
1376 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1378 * @return {Number} The day number (0-6)
1380 Date.prototype.getFirstDayOfMonth = function() {
1381 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1382 return (day < 0) ? (day + 7) : day;
1386 * Get the last day of the current month, adjusted for leap year. The returned value
1387 * is the numeric day index within the week (0-6) which can be used in conjunction with
1388 * the {@link #monthNames} array to retrieve the textual day name.
1391 var dt = new Date('1/10/2007');
1392 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1394 * @return {Number} The day number (0-6)
1396 Date.prototype.getLastDayOfMonth = function() {
1397 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1398 return (day < 0) ? (day + 7) : day;
1403 * Get the first date of this date's month
1406 Date.prototype.getFirstDateOfMonth = function() {
1407 return new Date(this.getFullYear(), this.getMonth(), 1);
1411 * Get the last date of this date's month
1414 Date.prototype.getLastDateOfMonth = function() {
1415 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1418 * Get the number of days in the current month, adjusted for leap year.
1419 * @return {Number} The number of days in the month
1421 Date.prototype.getDaysInMonth = function() {
1422 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1423 return Date.daysInMonth[this.getMonth()];
1427 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1428 * @return {String} 'st, 'nd', 'rd' or 'th'
1430 Date.prototype.getSuffix = function() {
1431 switch (this.getDate()) {
1448 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1451 * An array of textual month names.
1452 * Override these values for international dates, for example...
1453 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1472 * An array of textual day names.
1473 * Override these values for international dates, for example...
1474 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1490 Date.monthNumbers = {
1505 * Creates and returns a new Date instance with the exact same date value as the called instance.
1506 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1507 * variable will also be changed. When the intention is to create a new variable that will not
1508 * modify the original instance, you should create a clone.
1510 * Example of correctly cloning a date:
1513 var orig = new Date('10/1/2006');
1516 document.write(orig); //returns 'Thu Oct 05 2006'!
1519 var orig = new Date('10/1/2006');
1520 var copy = orig.clone();
1522 document.write(orig); //returns 'Thu Oct 01 2006'
1524 * @return {Date} The new Date instance
1526 Date.prototype.clone = function() {
1527 return new Date(this.getTime());
1531 * Clears any time information from this date
1532 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1533 @return {Date} this or the clone
1535 Date.prototype.clearTime = function(clone){
1537 return this.clone().clearTime();
1542 this.setMilliseconds(0);
1547 // safari setMonth is broken
1549 Date.brokenSetMonth = Date.prototype.setMonth;
1550 Date.prototype.setMonth = function(num){
1552 var n = Math.ceil(-num);
1553 var back_year = Math.ceil(n/12);
1554 var month = (n % 12) ? 12 - n % 12 : 0 ;
1555 this.setFullYear(this.getFullYear() - back_year);
1556 return Date.brokenSetMonth.call(this, month);
1558 return Date.brokenSetMonth.apply(this, arguments);
1563 /** Date interval constant
1567 /** Date interval constant
1571 /** Date interval constant
1575 /** Date interval constant
1579 /** Date interval constant
1583 /** Date interval constant
1587 /** Date interval constant
1593 * Provides a convenient method of performing basic date arithmetic. This method
1594 * does not modify the Date instance being called - it creates and returns
1595 * a new Date instance containing the resulting date value.
1600 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1601 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1603 //Negative values will subtract correctly:
1604 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1605 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1607 //You can even chain several calls together in one line!
1608 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1609 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1612 * @param {String} interval A valid date interval enum value
1613 * @param {Number} value The amount to add to the current date
1614 * @return {Date} The new Date instance
1616 Date.prototype.add = function(interval, value){
1617 var d = this.clone();
1618 if (!interval || value === 0) return d;
1619 switch(interval.toLowerCase()){
1621 d.setMilliseconds(this.getMilliseconds() + value);
1624 d.setSeconds(this.getSeconds() + value);
1627 d.setMinutes(this.getMinutes() + value);
1630 d.setHours(this.getHours() + value);
1633 d.setDate(this.getDate() + value);
1636 var day = this.getDate();
1638 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1641 d.setMonth(this.getMonth() + value);
1644 d.setFullYear(this.getFullYear() + value);
1650 * Ext JS Library 1.1.1
1651 * Copyright(c) 2006-2007, Ext JS, LLC.
1653 * Originally Released Under LGPL - original licence link has changed is not relivant.
1656 * <script type="text/javascript">
1660 getViewWidth : function(full) {
1661 return full ? this.getDocumentWidth() : this.getViewportWidth();
1664 getViewHeight : function(full) {
1665 return full ? this.getDocumentHeight() : this.getViewportHeight();
1668 getDocumentHeight: function() {
1669 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1670 return Math.max(scrollHeight, this.getViewportHeight());
1673 getDocumentWidth: function() {
1674 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1675 return Math.max(scrollWidth, this.getViewportWidth());
1678 getViewportHeight: function() {
1679 var height = self.innerHeight;
1680 var mode = document.compatMode;
1682 if ((mode || Roo.isIE) && !Roo.isOpera) {
1683 height = (mode == "CSS1Compat") ?
1684 document.documentElement.clientHeight :
1685 document.body.clientHeight;
1691 getViewportWidth: function() {
1692 var width = self.innerWidth;
1693 var mode = document.compatMode;
1695 if (mode || Roo.isIE) {
1696 width = (mode == "CSS1Compat") ?
1697 document.documentElement.clientWidth :
1698 document.body.clientWidth;
1703 isAncestor : function(p, c) {
1710 if (p.contains && !Roo.isSafari) {
1711 return p.contains(c);
1712 } else if (p.compareDocumentPosition) {
1713 return !!(p.compareDocumentPosition(c) & 16);
1715 var parent = c.parentNode;
1720 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1723 parent = parent.parentNode;
1729 getRegion : function(el) {
1730 return Roo.lib.Region.getRegion(el);
1733 getY : function(el) {
1734 return this.getXY(el)[1];
1737 getX : function(el) {
1738 return this.getXY(el)[0];
1741 getXY : function(el) {
1742 var p, pe, b, scroll, bd = document.body;
1743 el = Roo.getDom(el);
1744 var fly = Roo.lib.AnimBase.fly;
1745 if (el.getBoundingClientRect) {
1746 b = el.getBoundingClientRect();
1747 scroll = fly(document).getScroll();
1748 return [b.left + scroll.left, b.top + scroll.top];
1754 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1761 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1768 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1769 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1776 if (p != el && pe.getStyle('overflow') != 'visible') {
1784 if (Roo.isSafari && hasAbsolute) {
1789 if (Roo.isGecko && !hasAbsolute) {
1791 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1792 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1796 while (p && p != bd) {
1797 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1809 setXY : function(el, xy) {
1810 el = Roo.fly(el, '_setXY');
1812 var pts = el.translatePoints(xy);
1813 if (xy[0] !== false) {
1814 el.dom.style.left = pts.left + "px";
1816 if (xy[1] !== false) {
1817 el.dom.style.top = pts.top + "px";
1821 setX : function(el, x) {
1822 this.setXY(el, [x, false]);
1825 setY : function(el, y) {
1826 this.setXY(el, [false, y]);
1830 * Portions of this file are based on pieces of Yahoo User Interface Library
1831 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1832 * YUI licensed under the BSD License:
1833 * http://developer.yahoo.net/yui/license.txt
1834 * <script type="text/javascript">
1838 Roo.lib.Event = function() {
1839 var loadComplete = false;
1841 var unloadListeners = [];
1843 var onAvailStack = [];
1845 var lastError = null;
1858 startInterval: function() {
1859 if (!this._interval) {
1861 var callback = function() {
1862 self._tryPreloadAttach();
1864 this._interval = setInterval(callback, this.POLL_INTERVAL);
1869 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1870 onAvailStack.push({ id: p_id,
1873 override: p_override,
1874 checkReady: false });
1876 retryCount = this.POLL_RETRYS;
1877 this.startInterval();
1881 addListener: function(el, eventName, fn) {
1882 el = Roo.getDom(el);
1887 if ("unload" == eventName) {
1888 unloadListeners[unloadListeners.length] =
1889 [el, eventName, fn];
1893 var wrappedFn = function(e) {
1894 return fn(Roo.lib.Event.getEvent(e));
1897 var li = [el, eventName, fn, wrappedFn];
1899 var index = listeners.length;
1900 listeners[index] = li;
1902 this.doAdd(el, eventName, wrappedFn, false);
1908 removeListener: function(el, eventName, fn) {
1911 el = Roo.getDom(el);
1914 return this.purgeElement(el, false, eventName);
1918 if ("unload" == eventName) {
1920 for (i = 0,len = unloadListeners.length; i < len; i++) {
1921 var li = unloadListeners[i];
1924 li[1] == eventName &&
1926 unloadListeners.splice(i, 1);
1934 var cacheItem = null;
1937 var index = arguments[3];
1939 if ("undefined" == typeof index) {
1940 index = this._getCacheIndex(el, eventName, fn);
1944 cacheItem = listeners[index];
1947 if (!el || !cacheItem) {
1951 this.doRemove(el, eventName, cacheItem[this.WFN], false);
1953 delete listeners[index][this.WFN];
1954 delete listeners[index][this.FN];
1955 listeners.splice(index, 1);
1962 getTarget: function(ev, resolveTextNode) {
1963 ev = ev.browserEvent || ev;
1964 var t = ev.target || ev.srcElement;
1965 return this.resolveTextNode(t);
1969 resolveTextNode: function(node) {
1970 if (Roo.isSafari && node && 3 == node.nodeType) {
1971 return node.parentNode;
1978 getPageX: function(ev) {
1979 ev = ev.browserEvent || ev;
1981 if (!x && 0 !== x) {
1982 x = ev.clientX || 0;
1985 x += this.getScroll()[1];
1993 getPageY: function(ev) {
1994 ev = ev.browserEvent || ev;
1996 if (!y && 0 !== y) {
1997 y = ev.clientY || 0;
2000 y += this.getScroll()[0];
2009 getXY: function(ev) {
2010 ev = ev.browserEvent || ev;
2011 return [this.getPageX(ev), this.getPageY(ev)];
2015 getRelatedTarget: function(ev) {
2016 ev = ev.browserEvent || ev;
2017 var t = ev.relatedTarget;
2019 if (ev.type == "mouseout") {
2021 } else if (ev.type == "mouseover") {
2026 return this.resolveTextNode(t);
2030 getTime: function(ev) {
2031 ev = ev.browserEvent || ev;
2033 var t = new Date().getTime();
2037 this.lastError = ex;
2046 stopEvent: function(ev) {
2047 this.stopPropagation(ev);
2048 this.preventDefault(ev);
2052 stopPropagation: function(ev) {
2053 ev = ev.browserEvent || ev;
2054 if (ev.stopPropagation) {
2055 ev.stopPropagation();
2057 ev.cancelBubble = true;
2062 preventDefault: function(ev) {
2063 ev = ev.browserEvent || ev;
2064 if(ev.preventDefault) {
2065 ev.preventDefault();
2067 ev.returnValue = false;
2072 getEvent: function(e) {
2073 var ev = e || window.event;
2075 var c = this.getEvent.caller;
2077 ev = c.arguments[0];
2078 if (ev && Event == ev.constructor) {
2088 getCharCode: function(ev) {
2089 ev = ev.browserEvent || ev;
2090 return ev.charCode || ev.keyCode || 0;
2094 _getCacheIndex: function(el, eventName, fn) {
2095 for (var i = 0,len = listeners.length; i < len; ++i) {
2096 var li = listeners[i];
2098 li[this.FN] == fn &&
2099 li[this.EL] == el &&
2100 li[this.TYPE] == eventName) {
2112 getEl: function(id) {
2113 return document.getElementById(id);
2117 clearCache: function() {
2121 _load: function(e) {
2122 loadComplete = true;
2123 var EU = Roo.lib.Event;
2127 EU.doRemove(window, "load", EU._load);
2132 _tryPreloadAttach: function() {
2141 var tryAgain = !loadComplete;
2143 tryAgain = (retryCount > 0);
2148 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2149 var item = onAvailStack[i];
2151 var el = this.getEl(item.id);
2154 if (!item.checkReady ||
2157 (document && document.body)) {
2160 if (item.override) {
2161 if (item.override === true) {
2164 scope = item.override;
2167 item.fn.call(scope, item.obj);
2168 onAvailStack[i] = null;
2171 notAvail.push(item);
2176 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2180 this.startInterval();
2182 clearInterval(this._interval);
2183 this._interval = null;
2186 this.locked = false;
2193 purgeElement: function(el, recurse, eventName) {
2194 var elListeners = this.getListeners(el, eventName);
2196 for (var i = 0,len = elListeners.length; i < len; ++i) {
2197 var l = elListeners[i];
2198 this.removeListener(el, l.type, l.fn);
2202 if (recurse && el && el.childNodes) {
2203 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2204 this.purgeElement(el.childNodes[i], recurse, eventName);
2210 getListeners: function(el, eventName) {
2211 var results = [], searchLists;
2213 searchLists = [listeners, unloadListeners];
2214 } else if (eventName == "unload") {
2215 searchLists = [unloadListeners];
2217 searchLists = [listeners];
2220 for (var j = 0; j < searchLists.length; ++j) {
2221 var searchList = searchLists[j];
2222 if (searchList && searchList.length > 0) {
2223 for (var i = 0,len = searchList.length; i < len; ++i) {
2224 var l = searchList[i];
2225 if (l && l[this.EL] === el &&
2226 (!eventName || eventName === l[this.TYPE])) {
2231 adjust: l[this.ADJ_SCOPE],
2239 return (results.length) ? results : null;
2243 _unload: function(e) {
2245 var EU = Roo.lib.Event, i, j, l, len, index;
2247 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2248 l = unloadListeners[i];
2251 if (l[EU.ADJ_SCOPE]) {
2252 if (l[EU.ADJ_SCOPE] === true) {
2255 scope = l[EU.ADJ_SCOPE];
2258 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2259 unloadListeners[i] = null;
2265 unloadListeners = null;
2267 if (listeners && listeners.length > 0) {
2268 j = listeners.length;
2271 l = listeners[index];
2273 EU.removeListener(l[EU.EL], l[EU.TYPE],
2283 EU.doRemove(window, "unload", EU._unload);
2288 getScroll: function() {
2289 var dd = document.documentElement, db = document.body;
2290 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2291 return [dd.scrollTop, dd.scrollLeft];
2293 return [db.scrollTop, db.scrollLeft];
2300 doAdd: function () {
2301 if (window.addEventListener) {
2302 return function(el, eventName, fn, capture) {
2303 el.addEventListener(eventName, fn, (capture));
2305 } else if (window.attachEvent) {
2306 return function(el, eventName, fn, capture) {
2307 el.attachEvent("on" + eventName, fn);
2316 doRemove: function() {
2317 if (window.removeEventListener) {
2318 return function (el, eventName, fn, capture) {
2319 el.removeEventListener(eventName, fn, (capture));
2321 } else if (window.detachEvent) {
2322 return function (el, eventName, fn) {
2323 el.detachEvent("on" + eventName, fn);
2335 var E = Roo.lib.Event;
2336 E.on = E.addListener;
2337 E.un = E.removeListener;
2339 if (document && document.body) {
2342 E.doAdd(window, "load", E._load);
2344 E.doAdd(window, "unload", E._unload);
2345 E._tryPreloadAttach();
2349 * Portions of this file are based on pieces of Yahoo User Interface Library
2350 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2351 * YUI licensed under the BSD License:
2352 * http://developer.yahoo.net/yui/license.txt
2353 * <script type="text/javascript">
2360 request : function(method, uri, cb, data, options) {
2362 var hs = options.headers;
2365 if(hs.hasOwnProperty(h)){
2366 this.initHeader(h, hs[h], false);
2370 if(options.xmlData){
2371 this.initHeader('Content-Type', 'text/xml', false);
2373 data = options.xmlData;
2377 return this.asyncRequest(method, uri, cb, data);
2380 serializeForm : function(form) {
2381 if(typeof form == 'string') {
2382 form = (document.getElementById(form) || document.forms[form]);
2385 var el, name, val, disabled, data = '', hasSubmit = false;
2386 for (var i = 0; i < form.elements.length; i++) {
2387 el = form.elements[i];
2388 disabled = form.elements[i].disabled;
2389 name = form.elements[i].name;
2390 val = form.elements[i].value;
2392 if (!disabled && name){
2396 case 'select-multiple':
2397 for (var j = 0; j < el.options.length; j++) {
2398 if (el.options[j].selected) {
2400 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2403 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2411 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2424 if(hasSubmit == false) {
2425 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2430 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2435 data = data.substr(0, data.length - 1);
2443 useDefaultHeader:true,
2445 defaultPostHeader:'application/x-www-form-urlencoded',
2447 useDefaultXhrHeader:true,
2449 defaultXhrHeader:'XMLHttpRequest',
2451 hasDefaultHeaders:true,
2463 setProgId:function(id)
2465 this.activeX.unshift(id);
2468 setDefaultPostHeader:function(b)
2470 this.useDefaultHeader = b;
2473 setDefaultXhrHeader:function(b)
2475 this.useDefaultXhrHeader = b;
2478 setPollingInterval:function(i)
2480 if (typeof i == 'number' && isFinite(i)) {
2481 this.pollInterval = i;
2485 createXhrObject:function(transactionId)
2491 http = new XMLHttpRequest();
2493 obj = { conn:http, tId:transactionId };
2497 for (var i = 0; i < this.activeX.length; ++i) {
2501 http = new ActiveXObject(this.activeX[i]);
2503 obj = { conn:http, tId:transactionId };
2516 getConnectionObject:function()
2519 var tId = this.transactionId;
2523 o = this.createXhrObject(tId);
2525 this.transactionId++;
2536 asyncRequest:function(method, uri, callback, postData)
2538 var o = this.getConnectionObject();
2544 o.conn.open(method, uri, true);
2546 if (this.useDefaultXhrHeader) {
2547 if (!this.defaultHeaders['X-Requested-With']) {
2548 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2552 if(postData && this.useDefaultHeader){
2553 this.initHeader('Content-Type', this.defaultPostHeader);
2556 if (this.hasDefaultHeaders || this.hasHeaders) {
2560 this.handleReadyState(o, callback);
2561 o.conn.send(postData || null);
2567 handleReadyState:function(o, callback)
2571 if (callback && callback.timeout) {
2572 this.timeout[o.tId] = window.setTimeout(function() {
2573 oConn.abort(o, callback, true);
2574 }, callback.timeout);
2577 this.poll[o.tId] = window.setInterval(
2579 if (o.conn && o.conn.readyState == 4) {
2580 window.clearInterval(oConn.poll[o.tId]);
2581 delete oConn.poll[o.tId];
2583 if(callback && callback.timeout) {
2584 window.clearTimeout(oConn.timeout[o.tId]);
2585 delete oConn.timeout[o.tId];
2588 oConn.handleTransactionResponse(o, callback);
2591 , this.pollInterval);
2594 handleTransactionResponse:function(o, callback, isAbort)
2598 this.releaseObject(o);
2602 var httpStatus, responseObject;
2606 if (o.conn.status !== undefined && o.conn.status != 0) {
2607 httpStatus = o.conn.status;
2619 if (httpStatus >= 200 && httpStatus < 300) {
2620 responseObject = this.createResponseObject(o, callback.argument);
2621 if (callback.success) {
2622 if (!callback.scope) {
2623 callback.success(responseObject);
2628 callback.success.apply(callback.scope, [responseObject]);
2633 switch (httpStatus) {
2641 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2642 if (callback.failure) {
2643 if (!callback.scope) {
2644 callback.failure(responseObject);
2647 callback.failure.apply(callback.scope, [responseObject]);
2652 responseObject = this.createResponseObject(o, callback.argument);
2653 if (callback.failure) {
2654 if (!callback.scope) {
2655 callback.failure(responseObject);
2658 callback.failure.apply(callback.scope, [responseObject]);
2664 this.releaseObject(o);
2665 responseObject = null;
2668 createResponseObject:function(o, callbackArg)
2675 var headerStr = o.conn.getAllResponseHeaders();
2676 var header = headerStr.split('\n');
2677 for (var i = 0; i < header.length; i++) {
2678 var delimitPos = header[i].indexOf(':');
2679 if (delimitPos != -1) {
2680 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2688 obj.status = o.conn.status;
2689 obj.statusText = o.conn.statusText;
2690 obj.getResponseHeader = headerObj;
2691 obj.getAllResponseHeaders = headerStr;
2692 obj.responseText = o.conn.responseText;
2693 obj.responseXML = o.conn.responseXML;
2695 if (typeof callbackArg !== undefined) {
2696 obj.argument = callbackArg;
2702 createExceptionObject:function(tId, callbackArg, isAbort)
2705 var COMM_ERROR = 'communication failure';
2706 var ABORT_CODE = -1;
2707 var ABORT_ERROR = 'transaction aborted';
2713 obj.status = ABORT_CODE;
2714 obj.statusText = ABORT_ERROR;
2717 obj.status = COMM_CODE;
2718 obj.statusText = COMM_ERROR;
2722 obj.argument = callbackArg;
2728 initHeader:function(label, value, isDefault)
2730 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2732 if (headerObj[label] === undefined) {
2733 headerObj[label] = value;
2738 headerObj[label] = value + "," + headerObj[label];
2742 this.hasDefaultHeaders = true;
2745 this.hasHeaders = true;
2750 setHeader:function(o)
2752 if (this.hasDefaultHeaders) {
2753 for (var prop in this.defaultHeaders) {
2754 if (this.defaultHeaders.hasOwnProperty(prop)) {
2755 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2760 if (this.hasHeaders) {
2761 for (var prop in this.headers) {
2762 if (this.headers.hasOwnProperty(prop)) {
2763 o.conn.setRequestHeader(prop, this.headers[prop]);
2767 this.hasHeaders = false;
2771 resetDefaultHeaders:function() {
2772 delete this.defaultHeaders;
2773 this.defaultHeaders = {};
2774 this.hasDefaultHeaders = false;
2777 abort:function(o, callback, isTimeout)
2779 if(this.isCallInProgress(o)) {
2781 window.clearInterval(this.poll[o.tId]);
2782 delete this.poll[o.tId];
2784 delete this.timeout[o.tId];
2787 this.handleTransactionResponse(o, callback, true);
2797 isCallInProgress:function(o)
2800 return o.conn.readyState != 4 && o.conn.readyState != 0;
2809 releaseObject:function(o)
2818 'MSXML2.XMLHTTP.3.0',
2826 * Portions of this file are based on pieces of Yahoo User Interface Library
2827 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2828 * YUI licensed under the BSD License:
2829 * http://developer.yahoo.net/yui/license.txt
2830 * <script type="text/javascript">
2834 Roo.lib.Region = function(t, r, b, l) {
2844 Roo.lib.Region.prototype = {
2845 contains : function(region) {
2846 return ( region.left >= this.left &&
2847 region.right <= this.right &&
2848 region.top >= this.top &&
2849 region.bottom <= this.bottom );
2853 getArea : function() {
2854 return ( (this.bottom - this.top) * (this.right - this.left) );
2857 intersect : function(region) {
2858 var t = Math.max(this.top, region.top);
2859 var r = Math.min(this.right, region.right);
2860 var b = Math.min(this.bottom, region.bottom);
2861 var l = Math.max(this.left, region.left);
2863 if (b >= t && r >= l) {
2864 return new Roo.lib.Region(t, r, b, l);
2869 union : function(region) {
2870 var t = Math.min(this.top, region.top);
2871 var r = Math.max(this.right, region.right);
2872 var b = Math.max(this.bottom, region.bottom);
2873 var l = Math.min(this.left, region.left);
2875 return new Roo.lib.Region(t, r, b, l);
2878 adjust : function(t, l, b, r) {
2887 Roo.lib.Region.getRegion = function(el) {
2888 var p = Roo.lib.Dom.getXY(el);
2891 var r = p[0] + el.offsetWidth;
2892 var b = p[1] + el.offsetHeight;
2895 return new Roo.lib.Region(t, r, b, l);
2898 * Portions of this file are based on pieces of Yahoo User Interface Library
2899 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2900 * YUI licensed under the BSD License:
2901 * http://developer.yahoo.net/yui/license.txt
2902 * <script type="text/javascript">
2905 //@@dep Roo.lib.Region
2908 Roo.lib.Point = function(x, y) {
2909 if (x instanceof Array) {
2913 this.x = this.right = this.left = this[0] = x;
2914 this.y = this.top = this.bottom = this[1] = y;
2917 Roo.lib.Point.prototype = new Roo.lib.Region();
2919 * Portions of this file are based on pieces of Yahoo User Interface Library
2920 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2921 * YUI licensed under the BSD License:
2922 * http://developer.yahoo.net/yui/license.txt
2923 * <script type="text/javascript">
2930 scroll : function(el, args, duration, easing, cb, scope) {
2931 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2934 motion : function(el, args, duration, easing, cb, scope) {
2935 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2938 color : function(el, args, duration, easing, cb, scope) {
2939 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2942 run : function(el, args, duration, easing, cb, scope, type) {
2943 type = type || Roo.lib.AnimBase;
2944 if (typeof easing == "string") {
2945 easing = Roo.lib.Easing[easing];
2947 var anim = new type(el, args, duration, easing);
2948 anim.animateX(function() {
2949 Roo.callback(cb, scope);
2955 * Portions of this file are based on pieces of Yahoo User Interface Library
2956 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2957 * YUI licensed under the BSD License:
2958 * http://developer.yahoo.net/yui/license.txt
2959 * <script type="text/javascript">
2967 if (!libFlyweight) {
2968 libFlyweight = new Roo.Element.Flyweight();
2970 libFlyweight.dom = el;
2971 return libFlyweight;
2974 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2978 Roo.lib.AnimBase = function(el, attributes, duration, method) {
2980 this.init(el, attributes, duration, method);
2984 Roo.lib.AnimBase.fly = fly;
2988 Roo.lib.AnimBase.prototype = {
2990 toString: function() {
2991 var el = this.getEl();
2992 var id = el.id || el.tagName;
2993 return ("Anim " + id);
2997 noNegatives: /width|height|opacity|padding/i,
2998 offsetAttribute: /^((width|height)|(top|left))$/,
2999 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3000 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3004 doMethod: function(attr, start, end) {
3005 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3009 setAttribute: function(attr, val, unit) {
3010 if (this.patterns.noNegatives.test(attr)) {
3011 val = (val > 0) ? val : 0;
3014 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3018 getAttribute: function(attr) {
3019 var el = this.getEl();
3020 var val = fly(el).getStyle(attr);
3022 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3023 return parseFloat(val);
3026 var a = this.patterns.offsetAttribute.exec(attr) || [];
3027 var pos = !!( a[3] );
3028 var box = !!( a[2] );
3031 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3032 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3041 getDefaultUnit: function(attr) {
3042 if (this.patterns.defaultUnit.test(attr)) {
3049 animateX : function(callback, scope) {
3050 var f = function() {
3051 this.onComplete.removeListener(f);
3052 if (typeof callback == "function") {
3053 callback.call(scope || this, this);
3056 this.onComplete.addListener(f, this);
3061 setRuntimeAttribute: function(attr) {
3064 var attributes = this.attributes;
3066 this.runtimeAttributes[attr] = {};
3068 var isset = function(prop) {
3069 return (typeof prop !== 'undefined');
3072 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3076 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3079 if (isset(attributes[attr]['to'])) {
3080 end = attributes[attr]['to'];
3081 } else if (isset(attributes[attr]['by'])) {
3082 if (start.constructor == Array) {
3084 for (var i = 0, len = start.length; i < len; ++i) {
3085 end[i] = start[i] + attributes[attr]['by'][i];
3088 end = start + attributes[attr]['by'];
3092 this.runtimeAttributes[attr].start = start;
3093 this.runtimeAttributes[attr].end = end;
3096 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3100 init: function(el, attributes, duration, method) {
3102 var isAnimated = false;
3105 var startTime = null;
3108 var actualFrames = 0;
3111 el = Roo.getDom(el);
3114 this.attributes = attributes || {};
3117 this.duration = duration || 1;
3120 this.method = method || Roo.lib.Easing.easeNone;
3123 this.useSeconds = true;
3126 this.currentFrame = 0;
3129 this.totalFrames = Roo.lib.AnimMgr.fps;
3132 this.getEl = function() {
3137 this.isAnimated = function() {
3142 this.getStartTime = function() {
3146 this.runtimeAttributes = {};
3149 this.animate = function() {
3150 if (this.isAnimated()) {
3154 this.currentFrame = 0;
3156 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3158 Roo.lib.AnimMgr.registerElement(this);
3162 this.stop = function(finish) {
3164 this.currentFrame = this.totalFrames;
3165 this._onTween.fire();
3167 Roo.lib.AnimMgr.stop(this);
3170 var onStart = function() {
3171 this.onStart.fire();
3173 this.runtimeAttributes = {};
3174 for (var attr in this.attributes) {
3175 this.setRuntimeAttribute(attr);
3180 startTime = new Date();
3184 var onTween = function() {
3186 duration: new Date() - this.getStartTime(),
3187 currentFrame: this.currentFrame
3190 data.toString = function() {
3192 'duration: ' + data.duration +
3193 ', currentFrame: ' + data.currentFrame
3197 this.onTween.fire(data);
3199 var runtimeAttributes = this.runtimeAttributes;
3201 for (var attr in runtimeAttributes) {
3202 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3208 var onComplete = function() {
3209 var actual_duration = (new Date() - startTime) / 1000 ;
3212 duration: actual_duration,
3213 frames: actualFrames,
3214 fps: actualFrames / actual_duration
3217 data.toString = function() {
3219 'duration: ' + data.duration +
3220 ', frames: ' + data.frames +
3221 ', fps: ' + data.fps
3227 this.onComplete.fire(data);
3231 this._onStart = new Roo.util.Event(this);
3232 this.onStart = new Roo.util.Event(this);
3233 this.onTween = new Roo.util.Event(this);
3234 this._onTween = new Roo.util.Event(this);
3235 this.onComplete = new Roo.util.Event(this);
3236 this._onComplete = new Roo.util.Event(this);
3237 this._onStart.addListener(onStart);
3238 this._onTween.addListener(onTween);
3239 this._onComplete.addListener(onComplete);
3244 * Portions of this file are based on pieces of Yahoo User Interface Library
3245 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3246 * YUI licensed under the BSD License:
3247 * http://developer.yahoo.net/yui/license.txt
3248 * <script type="text/javascript">
3252 Roo.lib.AnimMgr = new function() {
3269 this.registerElement = function(tween) {
3270 queue[queue.length] = tween;
3272 tween._onStart.fire();
3277 this.unRegister = function(tween, index) {
3278 tween._onComplete.fire();
3279 index = index || getIndex(tween);
3281 queue.splice(index, 1);
3285 if (tweenCount <= 0) {
3291 this.start = function() {
3292 if (thread === null) {
3293 thread = setInterval(this.run, this.delay);
3298 this.stop = function(tween) {
3300 clearInterval(thread);
3302 for (var i = 0, len = queue.length; i < len; ++i) {
3303 if (queue[0].isAnimated()) {
3304 this.unRegister(queue[0], 0);
3313 this.unRegister(tween);
3318 this.run = function() {
3319 for (var i = 0, len = queue.length; i < len; ++i) {
3320 var tween = queue[i];
3321 if (!tween || !tween.isAnimated()) {
3325 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3327 tween.currentFrame += 1;
3329 if (tween.useSeconds) {
3330 correctFrame(tween);
3332 tween._onTween.fire();
3335 Roo.lib.AnimMgr.stop(tween, i);
3340 var getIndex = function(anim) {
3341 for (var i = 0, len = queue.length; i < len; ++i) {
3342 if (queue[i] == anim) {
3350 var correctFrame = function(tween) {
3351 var frames = tween.totalFrames;
3352 var frame = tween.currentFrame;
3353 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3354 var elapsed = (new Date() - tween.getStartTime());
3357 if (elapsed < tween.duration * 1000) {
3358 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3360 tweak = frames - (frame + 1);
3362 if (tweak > 0 && isFinite(tweak)) {
3363 if (tween.currentFrame + tweak >= frames) {
3364 tweak = frames - (frame + 1);
3367 tween.currentFrame += tweak;
3371 * Portions of this file are based on pieces of Yahoo User Interface Library
3372 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3373 * YUI licensed under the BSD License:
3374 * http://developer.yahoo.net/yui/license.txt
3375 * <script type="text/javascript">
3378 Roo.lib.Bezier = new function() {
3380 this.getPosition = function(points, t) {
3381 var n = points.length;
3384 for (var i = 0; i < n; ++i) {
3385 tmp[i] = [points[i][0], points[i][1]];
3388 for (var j = 1; j < n; ++j) {
3389 for (i = 0; i < n - j; ++i) {
3390 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3391 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3395 return [ tmp[0][0], tmp[0][1] ];
3399 * Portions of this file are based on pieces of Yahoo User Interface Library
3400 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3401 * YUI licensed under the BSD License:
3402 * http://developer.yahoo.net/yui/license.txt
3403 * <script type="text/javascript">
3408 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3409 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3412 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3414 var fly = Roo.lib.AnimBase.fly;
3416 var superclass = Y.ColorAnim.superclass;
3417 var proto = Y.ColorAnim.prototype;
3419 proto.toString = function() {
3420 var el = this.getEl();
3421 var id = el.id || el.tagName;
3422 return ("ColorAnim " + id);
3425 proto.patterns.color = /color$/i;
3426 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3427 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3428 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3429 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3432 proto.parseColor = function(s) {
3433 if (s.length == 3) {
3437 var c = this.patterns.hex.exec(s);
3438 if (c && c.length == 4) {
3439 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3442 c = this.patterns.rgb.exec(s);
3443 if (c && c.length == 4) {
3444 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3447 c = this.patterns.hex3.exec(s);
3448 if (c && c.length == 4) {
3449 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3454 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3455 proto.getAttribute = function(attr) {
3456 var el = this.getEl();
3457 if (this.patterns.color.test(attr)) {
3458 var val = fly(el).getStyle(attr);
3460 if (this.patterns.transparent.test(val)) {
3461 var parent = el.parentNode;
3462 val = fly(parent).getStyle(attr);
3464 while (parent && this.patterns.transparent.test(val)) {
3465 parent = parent.parentNode;
3466 val = fly(parent).getStyle(attr);
3467 if (parent.tagName.toUpperCase() == 'HTML') {
3473 val = superclass.getAttribute.call(this, attr);
3478 proto.getAttribute = function(attr) {
3479 var el = this.getEl();
3480 if (this.patterns.color.test(attr)) {
3481 var val = fly(el).getStyle(attr);
3483 if (this.patterns.transparent.test(val)) {
3484 var parent = el.parentNode;
3485 val = fly(parent).getStyle(attr);
3487 while (parent && this.patterns.transparent.test(val)) {
3488 parent = parent.parentNode;
3489 val = fly(parent).getStyle(attr);
3490 if (parent.tagName.toUpperCase() == 'HTML') {
3496 val = superclass.getAttribute.call(this, attr);
3502 proto.doMethod = function(attr, start, end) {
3505 if (this.patterns.color.test(attr)) {
3507 for (var i = 0, len = start.length; i < len; ++i) {
3508 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3511 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3514 val = superclass.doMethod.call(this, attr, start, end);
3520 proto.setRuntimeAttribute = function(attr) {
3521 superclass.setRuntimeAttribute.call(this, attr);
3523 if (this.patterns.color.test(attr)) {
3524 var attributes = this.attributes;
3525 var start = this.parseColor(this.runtimeAttributes[attr].start);
3526 var end = this.parseColor(this.runtimeAttributes[attr].end);
3528 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3529 end = this.parseColor(attributes[attr].by);
3531 for (var i = 0, len = start.length; i < len; ++i) {
3532 end[i] = start[i] + end[i];
3536 this.runtimeAttributes[attr].start = start;
3537 this.runtimeAttributes[attr].end = end;
3543 * Portions of this file are based on pieces of Yahoo User Interface Library
3544 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3545 * YUI licensed under the BSD License:
3546 * http://developer.yahoo.net/yui/license.txt
3547 * <script type="text/javascript">
3553 easeNone: function (t, b, c, d) {
3554 return c * t / d + b;
3558 easeIn: function (t, b, c, d) {
3559 return c * (t /= d) * t + b;
3563 easeOut: function (t, b, c, d) {
3564 return -c * (t /= d) * (t - 2) + b;
3568 easeBoth: function (t, b, c, d) {
3569 if ((t /= d / 2) < 1) {
3570 return c / 2 * t * t + b;
3573 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3577 easeInStrong: function (t, b, c, d) {
3578 return c * (t /= d) * t * t * t + b;
3582 easeOutStrong: function (t, b, c, d) {
3583 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3587 easeBothStrong: function (t, b, c, d) {
3588 if ((t /= d / 2) < 1) {
3589 return c / 2 * t * t * t * t + b;
3592 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3597 elasticIn: function (t, b, c, d, a, p) {
3601 if ((t /= d) == 1) {
3608 if (!a || a < Math.abs(c)) {
3613 var s = p / (2 * Math.PI) * Math.asin(c / a);
3616 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3620 elasticOut: function (t, b, c, d, a, p) {
3624 if ((t /= d) == 1) {
3631 if (!a || a < Math.abs(c)) {
3636 var s = p / (2 * Math.PI) * Math.asin(c / a);
3639 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3643 elasticBoth: function (t, b, c, d, a, p) {
3648 if ((t /= d / 2) == 2) {
3656 if (!a || a < Math.abs(c)) {
3661 var s = p / (2 * Math.PI) * Math.asin(c / a);
3665 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3666 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3668 return a * Math.pow(2, -10 * (t -= 1)) *
3669 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3674 backIn: function (t, b, c, d, s) {
3675 if (typeof s == 'undefined') {
3678 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3682 backOut: function (t, b, c, d, s) {
3683 if (typeof s == 'undefined') {
3686 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3690 backBoth: function (t, b, c, d, s) {
3691 if (typeof s == 'undefined') {
3695 if ((t /= d / 2 ) < 1) {
3696 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3698 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3702 bounceIn: function (t, b, c, d) {
3703 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3707 bounceOut: function (t, b, c, d) {
3708 if ((t /= d) < (1 / 2.75)) {
3709 return c * (7.5625 * t * t) + b;
3710 } else if (t < (2 / 2.75)) {
3711 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3712 } else if (t < (2.5 / 2.75)) {
3713 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3715 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3719 bounceBoth: function (t, b, c, d) {
3721 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3723 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3726 * Portions of this file are based on pieces of Yahoo User Interface Library
3727 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3728 * YUI licensed under the BSD License:
3729 * http://developer.yahoo.net/yui/license.txt
3730 * <script type="text/javascript">
3734 Roo.lib.Motion = function(el, attributes, duration, method) {
3736 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3740 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3744 var superclass = Y.Motion.superclass;
3745 var proto = Y.Motion.prototype;
3747 proto.toString = function() {
3748 var el = this.getEl();
3749 var id = el.id || el.tagName;
3750 return ("Motion " + id);
3753 proto.patterns.points = /^points$/i;
3755 proto.setAttribute = function(attr, val, unit) {
3756 if (this.patterns.points.test(attr)) {
3757 unit = unit || 'px';
3758 superclass.setAttribute.call(this, 'left', val[0], unit);
3759 superclass.setAttribute.call(this, 'top', val[1], unit);
3761 superclass.setAttribute.call(this, attr, val, unit);
3765 proto.getAttribute = function(attr) {
3766 if (this.patterns.points.test(attr)) {
3768 superclass.getAttribute.call(this, 'left'),
3769 superclass.getAttribute.call(this, 'top')
3772 val = superclass.getAttribute.call(this, attr);
3778 proto.doMethod = function(attr, start, end) {
3781 if (this.patterns.points.test(attr)) {
3782 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3783 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3785 val = superclass.doMethod.call(this, attr, start, end);
3790 proto.setRuntimeAttribute = function(attr) {
3791 if (this.patterns.points.test(attr)) {
3792 var el = this.getEl();
3793 var attributes = this.attributes;
3795 var control = attributes['points']['control'] || [];
3799 if (control.length > 0 && !(control[0] instanceof Array)) {
3800 control = [control];
3803 for (i = 0,len = control.length; i < len; ++i) {
3804 tmp[i] = control[i];
3809 Roo.fly(el).position();
3811 if (isset(attributes['points']['from'])) {
3812 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3815 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3818 start = this.getAttribute('points');
3821 if (isset(attributes['points']['to'])) {
3822 end = translateValues.call(this, attributes['points']['to'], start);
3824 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3825 for (i = 0,len = control.length; i < len; ++i) {
3826 control[i] = translateValues.call(this, control[i], start);
3830 } else if (isset(attributes['points']['by'])) {
3831 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3833 for (i = 0,len = control.length; i < len; ++i) {
3834 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3838 this.runtimeAttributes[attr] = [start];
3840 if (control.length > 0) {
3841 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3844 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3847 superclass.setRuntimeAttribute.call(this, attr);
3851 var translateValues = function(val, start) {
3852 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3853 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3858 var isset = function(prop) {
3859 return (typeof prop !== 'undefined');
3863 * Portions of this file are based on pieces of Yahoo User Interface Library
3864 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3865 * YUI licensed under the BSD License:
3866 * http://developer.yahoo.net/yui/license.txt
3867 * <script type="text/javascript">
3871 Roo.lib.Scroll = function(el, attributes, duration, method) {
3873 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3877 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3881 var superclass = Y.Scroll.superclass;
3882 var proto = Y.Scroll.prototype;
3884 proto.toString = function() {
3885 var el = this.getEl();
3886 var id = el.id || el.tagName;
3887 return ("Scroll " + id);
3890 proto.doMethod = function(attr, start, end) {
3893 if (attr == 'scroll') {
3895 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3896 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3900 val = superclass.doMethod.call(this, attr, start, end);
3905 proto.getAttribute = function(attr) {
3907 var el = this.getEl();
3909 if (attr == 'scroll') {
3910 val = [ el.scrollLeft, el.scrollTop ];
3912 val = superclass.getAttribute.call(this, attr);
3918 proto.setAttribute = function(attr, val, unit) {
3919 var el = this.getEl();
3921 if (attr == 'scroll') {
3922 el.scrollLeft = val[0];
3923 el.scrollTop = val[1];
3925 superclass.setAttribute.call(this, attr, val, unit);
3931 * Ext JS Library 1.1.1
3932 * Copyright(c) 2006-2007, Ext JS, LLC.
3934 * Originally Released Under LGPL - original licence link has changed is not relivant.
3937 * <script type="text/javascript">
3942 * @class Roo.DomHelper
3943 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3944 * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
3947 Roo.DomHelper = function(){
3948 var tempTableEl = null;
3949 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3950 var tableRe = /^table|tbody|tr|td$/i;
3952 // build as innerHTML where available
3954 var createHtml = function(o){
3955 if(typeof o == 'string'){
3964 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3965 if(attr == "style"){
3967 if(typeof s == "function"){
3970 if(typeof s == "string"){
3971 b += ' style="' + s + '"';
3972 }else if(typeof s == "object"){
3975 if(typeof s[key] != "function"){
3976 b += key + ":" + s[key] + ";";
3983 b += ' class="' + o["cls"] + '"';
3984 }else if(attr == "htmlFor"){
3985 b += ' for="' + o["htmlFor"] + '"';
3987 b += " " + attr + '="' + o[attr] + '"';
3991 if(emptyTags.test(o.tag)){
3995 var cn = o.children || o.cn;
3997 //http://bugs.kde.org/show_bug.cgi?id=71506
3998 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
3999 for(var i = 0, len = cn.length; i < len; i++) {
4000 b += createHtml(cn[i], b);
4003 b += createHtml(cn, b);
4009 b += "</" + o.tag + ">";
4016 var createDom = function(o, parentNode){
4018 // defininition craeted..
4020 if (o.ns && o.ns != 'html') {
4022 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4023 xmlns[o.ns] = o.xmlns;
4026 if (typeof(xmlns[o.ns]) == 'undefined') {
4027 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4033 if (typeof(o) == 'string') {
4034 return parentNode.appendChild(document.createTextNode(o));
4036 o.tag = o.tag || div;
4037 if (o.ns && Roo.isIE) {
4039 o.tag = o.ns + ':' + o.tag;
4042 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4043 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4046 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4047 attr == "style" || typeof o[attr] == "function") continue;
4049 if(attr=="cls" && Roo.isIE){
4050 el.className = o["cls"];
4052 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4053 else el[attr] = o[attr];
4056 Roo.DomHelper.applyStyles(el, o.style);
4057 var cn = o.children || o.cn;
4059 //http://bugs.kde.org/show_bug.cgi?id=71506
4060 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4061 for(var i = 0, len = cn.length; i < len; i++) {
4062 createDom(cn[i], el);
4069 el.innerHTML = o.html;
4072 parentNode.appendChild(el);
4077 var ieTable = function(depth, s, h, e){
4078 tempTableEl.innerHTML = [s, h, e].join('');
4079 var i = -1, el = tempTableEl;
4086 // kill repeat to save bytes
4090 tbe = '</tbody>'+te,
4096 * Nasty code for IE's broken table implementation
4098 var insertIntoTable = function(tag, where, el, html){
4100 tempTableEl = document.createElement('div');
4105 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4108 if(where == 'beforebegin'){
4112 before = el.nextSibling;
4115 node = ieTable(4, trs, html, tre);
4117 else if(tag == 'tr'){
4118 if(where == 'beforebegin'){
4121 node = ieTable(3, tbs, html, tbe);
4122 } else if(where == 'afterend'){
4123 before = el.nextSibling;
4125 node = ieTable(3, tbs, html, tbe);
4126 } else{ // INTO a TR
4127 if(where == 'afterbegin'){
4128 before = el.firstChild;
4130 node = ieTable(4, trs, html, tre);
4132 } else if(tag == 'tbody'){
4133 if(where == 'beforebegin'){
4136 node = ieTable(2, ts, html, te);
4137 } else if(where == 'afterend'){
4138 before = el.nextSibling;
4140 node = ieTable(2, ts, html, te);
4142 if(where == 'afterbegin'){
4143 before = el.firstChild;
4145 node = ieTable(3, tbs, html, tbe);
4148 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4151 if(where == 'afterbegin'){
4152 before = el.firstChild;
4154 node = ieTable(2, ts, html, te);
4156 el.insertBefore(node, before);
4161 /** True to force the use of DOM instead of html fragments @type Boolean */
4165 * Returns the markup for the passed Element(s) config
4166 * @param {Object} o The Dom object spec (and children)
4169 markup : function(o){
4170 return createHtml(o);
4174 * Applies a style specification to an element
4175 * @param {String/HTMLElement} el The element to apply styles to
4176 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4177 * a function which returns such a specification.
4179 applyStyles : function(el, styles){
4182 if(typeof styles == "string"){
4183 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4185 while ((matches = re.exec(styles)) != null){
4186 el.setStyle(matches[1], matches[2]);
4188 }else if (typeof styles == "object"){
4189 for (var style in styles){
4190 el.setStyle(style, styles[style]);
4192 }else if (typeof styles == "function"){
4193 Roo.DomHelper.applyStyles(el, styles.call());
4199 * Inserts an HTML fragment into the Dom
4200 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4201 * @param {HTMLElement} el The context element
4202 * @param {String} html The HTML fragmenet
4203 * @return {HTMLElement} The new node
4205 insertHtml : function(where, el, html){
4206 where = where.toLowerCase();
4207 if(el.insertAdjacentHTML){
4208 if(tableRe.test(el.tagName)){
4210 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4216 el.insertAdjacentHTML('BeforeBegin', html);
4217 return el.previousSibling;
4219 el.insertAdjacentHTML('AfterBegin', html);
4220 return el.firstChild;
4222 el.insertAdjacentHTML('BeforeEnd', html);
4223 return el.lastChild;
4225 el.insertAdjacentHTML('AfterEnd', html);
4226 return el.nextSibling;
4228 throw 'Illegal insertion point -> "' + where + '"';
4230 var range = el.ownerDocument.createRange();
4234 range.setStartBefore(el);
4235 frag = range.createContextualFragment(html);
4236 el.parentNode.insertBefore(frag, el);
4237 return el.previousSibling;
4240 range.setStartBefore(el.firstChild);
4241 frag = range.createContextualFragment(html);
4242 el.insertBefore(frag, el.firstChild);
4243 return el.firstChild;
4245 el.innerHTML = html;
4246 return el.firstChild;
4250 range.setStartAfter(el.lastChild);
4251 frag = range.createContextualFragment(html);
4252 el.appendChild(frag);
4253 return el.lastChild;
4255 el.innerHTML = html;
4256 return el.lastChild;
4259 range.setStartAfter(el);
4260 frag = range.createContextualFragment(html);
4261 el.parentNode.insertBefore(frag, el.nextSibling);
4262 return el.nextSibling;
4264 throw 'Illegal insertion point -> "' + where + '"';
4268 * Creates new Dom element(s) and inserts them before el
4269 * @param {String/HTMLElement/Element} el The context element
4270 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4271 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4272 * @return {HTMLElement/Roo.Element} The new node
4274 insertBefore : function(el, o, returnElement){
4275 return this.doInsert(el, o, returnElement, "beforeBegin");
4279 * Creates new Dom element(s) and inserts them after el
4280 * @param {String/HTMLElement/Element} el The context element
4281 * @param {Object} o The Dom object spec (and children)
4282 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4283 * @return {HTMLElement/Roo.Element} The new node
4285 insertAfter : function(el, o, returnElement){
4286 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4290 * Creates new Dom element(s) and inserts them as the first child of el
4291 * @param {String/HTMLElement/Element} el The context element
4292 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4293 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4294 * @return {HTMLElement/Roo.Element} The new node
4296 insertFirst : function(el, o, returnElement){
4297 return this.doInsert(el, o, returnElement, "afterBegin");
4301 doInsert : function(el, o, returnElement, pos, sibling){
4302 el = Roo.getDom(el);
4304 if(this.useDom || o.ns){
4305 newNode = createDom(o, null);
4306 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4308 var html = createHtml(o);
4309 newNode = this.insertHtml(pos, el, html);
4311 return returnElement ? Roo.get(newNode, true) : newNode;
4315 * Creates new Dom element(s) and appends them to el
4316 * @param {String/HTMLElement/Element} el The context element
4317 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4318 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4319 * @return {HTMLElement/Roo.Element} The new node
4321 append : function(el, o, returnElement){
4322 el = Roo.getDom(el);
4324 if(this.useDom || o.ns){
4325 newNode = createDom(o, null);
4326 el.appendChild(newNode);
4328 var html = createHtml(o);
4329 newNode = this.insertHtml("beforeEnd", el, html);
4331 return returnElement ? Roo.get(newNode, true) : newNode;
4335 * Creates new Dom element(s) and overwrites the contents of el with them
4336 * @param {String/HTMLElement/Element} el The context element
4337 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4338 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4339 * @return {HTMLElement/Roo.Element} The new node
4341 overwrite : function(el, o, returnElement){
4342 el = Roo.getDom(el);
4345 while (el.childNodes.length) {
4346 el.removeChild(el.firstChild);
4350 el.innerHTML = createHtml(o);
4353 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4357 * Creates a new Roo.DomHelper.Template from the Dom object spec
4358 * @param {Object} o The Dom object spec (and children)
4359 * @return {Roo.DomHelper.Template} The new template
4361 createTemplate : function(o){
4362 var html = createHtml(o);
4363 return new Roo.Template(html);
4369 * Ext JS Library 1.1.1
4370 * Copyright(c) 2006-2007, Ext JS, LLC.
4372 * Originally Released Under LGPL - original licence link has changed is not relivant.
4375 * <script type="text/javascript">
4379 * @class Roo.Template
4380 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4381 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4384 var t = new Roo.Template(
4385 '<div name="{id}">',
4386 '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
4389 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4391 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>.
4393 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4395 Roo.Template = function(html){
4396 if(html instanceof Array){
4397 html = html.join("");
4398 }else if(arguments.length > 1){
4399 html = Array.prototype.join.call(arguments, "");
4405 Roo.Template.prototype = {
4407 * Returns an HTML fragment of this template with the specified values applied.
4408 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4409 * @return {String} The HTML fragment
4411 applyTemplate : function(values){
4413 return this.compiled(values);
4415 var useF = this.disableFormats !== true;
4416 var fm = Roo.util.Format, tpl = this;
4417 var fn = function(m, name, format, args){
4419 if(format.substr(0, 5) == "this."){
4420 return tpl.call(format.substr(5), values[name], values);
4423 // quoted values are required for strings in compiled templates,
4424 // but for non compiled we need to strip them
4425 // quoted reversed for jsmin
4426 var re = /^\s*['"](.*)["']\s*$/;
4427 args = args.split(',');
4428 for(var i = 0, len = args.length; i < len; i++){
4429 args[i] = args[i].replace(re, "$1");
4431 args = [values[name]].concat(args);
4433 args = [values[name]];
4435 return fm[format].apply(fm, args);
4438 return values[name] !== undefined ? values[name] : "";
4441 return this.html.replace(this.re, fn);
4445 * Sets the HTML used as the template and optionally compiles it.
4446 * @param {String} html
4447 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4448 * @return {Roo.Template} this
4450 set : function(html, compile){
4452 this.compiled = null;
4460 * True to disable format functions (defaults to false)
4463 disableFormats : false,
4466 * The regular expression used to match template variables
4470 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4473 * Compiles the template into an internal function, eliminating the RegEx overhead.
4474 * @return {Roo.Template} this
4476 compile : function(){
4477 var fm = Roo.util.Format;
4478 var useF = this.disableFormats !== true;
4479 var sep = Roo.isGecko ? "+" : ",";
4480 var fn = function(m, name, format, args){
4482 args = args ? ',' + args : "";
4483 if(format.substr(0, 5) != "this."){
4484 format = "fm." + format + '(';
4486 format = 'this.call("'+ format.substr(5) + '", ';
4490 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4492 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4495 // branched to use + in gecko and [].join() in others
4497 body = "this.compiled = function(values){ return '" +
4498 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4501 body = ["this.compiled = function(values){ return ['"];
4502 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4503 body.push("'].join('');};");
4504 body = body.join('');
4514 // private function used to call members
4515 call : function(fnName, value, allValues){
4516 return this[fnName](value, allValues);
4520 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4521 * @param {String/HTMLElement/Roo.Element} el The context element
4522 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4523 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4524 * @return {HTMLElement/Roo.Element} The new node or Element
4526 insertFirst: function(el, values, returnElement){
4527 return this.doInsert('afterBegin', el, values, returnElement);
4531 * Applies the supplied values to the template and inserts the new node(s) before el.
4532 * @param {String/HTMLElement/Roo.Element} el The context element
4533 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4534 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4535 * @return {HTMLElement/Roo.Element} The new node or Element
4537 insertBefore: function(el, values, returnElement){
4538 return this.doInsert('beforeBegin', el, values, returnElement);
4542 * Applies the supplied values to the template and inserts the new node(s) after el.
4543 * @param {String/HTMLElement/Roo.Element} el The context element
4544 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4545 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4546 * @return {HTMLElement/Roo.Element} The new node or Element
4548 insertAfter : function(el, values, returnElement){
4549 return this.doInsert('afterEnd', el, values, returnElement);
4553 * Applies the supplied values to the template and appends the new node(s) to el.
4554 * @param {String/HTMLElement/Roo.Element} el The context element
4555 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4556 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4557 * @return {HTMLElement/Roo.Element} The new node or Element
4559 append : function(el, values, returnElement){
4560 return this.doInsert('beforeEnd', el, values, returnElement);
4563 doInsert : function(where, el, values, returnEl){
4564 el = Roo.getDom(el);
4565 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4566 return returnEl ? Roo.get(newNode, true) : newNode;
4570 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4571 * @param {String/HTMLElement/Roo.Element} el The context element
4572 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4573 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4574 * @return {HTMLElement/Roo.Element} The new node or Element
4576 overwrite : function(el, values, returnElement){
4577 el = Roo.getDom(el);
4578 el.innerHTML = this.applyTemplate(values);
4579 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4583 * Alias for {@link #applyTemplate}
4586 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4589 Roo.DomHelper.Template = Roo.Template;
4592 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4593 * @param {String/HTMLElement} el A DOM element or its id
4594 * @returns {Roo.Template} The created template
4597 Roo.Template.from = function(el){
4598 el = Roo.getDom(el);
4599 return new Roo.Template(el.value || el.innerHTML);
4602 * Ext JS Library 1.1.1
4603 * Copyright(c) 2006-2007, Ext JS, LLC.
4605 * Originally Released Under LGPL - original licence link has changed is not relivant.
4608 * <script type="text/javascript">
4613 * This is code is also distributed under MIT license for use
4614 * with jQuery and prototype JavaScript libraries.
4617 * @class Roo.DomQuery
4618 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4620 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4623 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4625 <h4>Element Selectors:</h4>
4627 <li> <b>*</b> any element</li>
4628 <li> <b>E</b> an element with the tag E</li>
4629 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4630 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4631 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4632 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4634 <h4>Attribute Selectors:</h4>
4635 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4637 <li> <b>E[foo]</b> has an attribute "foo"</li>
4638 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4639 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4640 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4641 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4642 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4643 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4645 <h4>Pseudo Classes:</h4>
4647 <li> <b>E:first-child</b> E is the first child of its parent</li>
4648 <li> <b>E:last-child</b> E is the last child of its parent</li>
4649 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4650 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4651 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4652 <li> <b>E:only-child</b> E is the only child of its parent</li>
4653 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4654 <li> <b>E:first</b> the first E in the resultset</li>
4655 <li> <b>E:last</b> the last E in the resultset</li>
4656 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4657 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4658 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4659 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4660 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4661 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4662 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4663 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4664 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4666 <h4>CSS Value Selectors:</h4>
4668 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4669 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4670 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4671 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4672 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4673 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4677 Roo.DomQuery = function(){
4678 var cache = {}, simpleCache = {}, valueCache = {};
4679 var nonSpace = /\S/;
4680 var trimRe = /^\s+|\s+$/g;
4681 var tplRe = /\{(\d+)\}/g;
4682 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4683 var tagTokenRe = /^(#)?([\w-\*]+)/;
4684 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4686 function child(p, index){
4688 var n = p.firstChild;
4690 if(n.nodeType == 1){
4701 while((n = n.nextSibling) && n.nodeType != 1);
4706 while((n = n.previousSibling) && n.nodeType != 1);
4710 function children(d){
4711 var n = d.firstChild, ni = -1;
4713 var nx = n.nextSibling;
4714 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4724 function byClassName(c, a, v){
4728 var r = [], ri = -1, cn;
4729 for(var i = 0, ci; ci = c[i]; i++){
4730 if((' '+ci.className+' ').indexOf(v) != -1){
4737 function attrValue(n, attr){
4738 if(!n.tagName && typeof n.length != "undefined"){
4747 if(attr == "class" || attr == "className"){
4750 return n.getAttribute(attr) || n[attr];
4754 function getNodes(ns, mode, tagName){
4755 var result = [], ri = -1, cs;
4759 tagName = tagName || "*";
4760 if(typeof ns.getElementsByTagName != "undefined"){
4764 for(var i = 0, ni; ni = ns[i]; i++){
4765 cs = ni.getElementsByTagName(tagName);
4766 for(var j = 0, ci; ci = cs[j]; j++){
4770 }else if(mode == "/" || mode == ">"){
4771 var utag = tagName.toUpperCase();
4772 for(var i = 0, ni, cn; ni = ns[i]; i++){
4773 cn = ni.children || ni.childNodes;
4774 for(var j = 0, cj; cj = cn[j]; j++){
4775 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4780 }else if(mode == "+"){
4781 var utag = tagName.toUpperCase();
4782 for(var i = 0, n; n = ns[i]; i++){
4783 while((n = n.nextSibling) && n.nodeType != 1);
4784 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4788 }else if(mode == "~"){
4789 for(var i = 0, n; n = ns[i]; i++){
4790 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4799 function concat(a, b){
4803 for(var i = 0, l = b.length; i < l; i++){
4809 function byTag(cs, tagName){
4810 if(cs.tagName || cs == document){
4816 var r = [], ri = -1;
4817 tagName = tagName.toLowerCase();
4818 for(var i = 0, ci; ci = cs[i]; i++){
4819 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4826 function byId(cs, attr, id){
4827 if(cs.tagName || cs == document){
4833 var r = [], ri = -1;
4834 for(var i = 0,ci; ci = cs[i]; i++){
4835 if(ci && ci.id == id){
4843 function byAttribute(cs, attr, value, op, custom){
4844 var r = [], ri = -1, st = custom=="{";
4845 var f = Roo.DomQuery.operators[op];
4846 for(var i = 0, ci; ci = cs[i]; i++){
4849 a = Roo.DomQuery.getStyle(ci, attr);
4851 else if(attr == "class" || attr == "className"){
4853 }else if(attr == "for"){
4855 }else if(attr == "href"){
4856 a = ci.getAttribute("href", 2);
4858 a = ci.getAttribute(attr);
4860 if((f && f(a, value)) || (!f && a)){
4867 function byPseudo(cs, name, value){
4868 return Roo.DomQuery.pseudos[name](cs, value);
4871 // This is for IE MSXML which does not support expandos.
4872 // IE runs the same speed using setAttribute, however FF slows way down
4873 // and Safari completely fails so they need to continue to use expandos.
4874 var isIE = window.ActiveXObject ? true : false;
4876 // this eval is stop the compressor from
4877 // renaming the variable to something shorter
4879 /** eval:var:batch */
4884 function nodupIEXml(cs){
4886 cs[0].setAttribute("_nodup", d);
4888 for(var i = 1, len = cs.length; i < len; i++){
4890 if(!c.getAttribute("_nodup") != d){
4891 c.setAttribute("_nodup", d);
4895 for(var i = 0, len = cs.length; i < len; i++){
4896 cs[i].removeAttribute("_nodup");
4905 var len = cs.length, c, i, r = cs, cj, ri = -1;
4906 if(!len || typeof cs.nodeType != "undefined" || len == 1){
4909 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4910 return nodupIEXml(cs);
4914 for(i = 1; c = cs[i]; i++){
4919 for(var j = 0; j < i; j++){
4922 for(j = i+1; cj = cs[j]; j++){
4934 function quickDiffIEXml(c1, c2){
4936 for(var i = 0, len = c1.length; i < len; i++){
4937 c1[i].setAttribute("_qdiff", d);
4940 for(var i = 0, len = c2.length; i < len; i++){
4941 if(c2[i].getAttribute("_qdiff") != d){
4942 r[r.length] = c2[i];
4945 for(var i = 0, len = c1.length; i < len; i++){
4946 c1[i].removeAttribute("_qdiff");
4951 function quickDiff(c1, c2){
4952 var len1 = c1.length;
4956 if(isIE && c1[0].selectSingleNode){
4957 return quickDiffIEXml(c1, c2);
4960 for(var i = 0; i < len1; i++){
4964 for(var i = 0, len = c2.length; i < len; i++){
4965 if(c2[i]._qdiff != d){
4966 r[r.length] = c2[i];
4972 function quickId(ns, mode, root, id){
4974 var d = root.ownerDocument || root;
4975 return d.getElementById(id);
4977 ns = getNodes(ns, mode, "*");
4978 return byId(ns, null, id);
4982 getStyle : function(el, name){
4983 return Roo.fly(el).getStyle(name);
4986 * Compiles a selector/xpath query into a reusable function. The returned function
4987 * takes one parameter "root" (optional), which is the context node from where the query should start.
4988 * @param {String} selector The selector/xpath query
4989 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
4990 * @return {Function}
4992 compile : function(path, type){
4993 type = type || "select";
4995 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
4996 var q = path, mode, lq;
4997 var tk = Roo.DomQuery.matchers;
4998 var tklen = tk.length;
5001 // accept leading mode switch
5002 var lmode = q.match(modeRe);
5003 if(lmode && lmode[1]){
5004 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5005 q = q.replace(lmode[1], "");
5007 // strip leading slashes
5008 while(path.substr(0, 1)=="/"){
5009 path = path.substr(1);
5012 while(q && lq != q){
5014 var tm = q.match(tagTokenRe);
5015 if(type == "select"){
5018 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5020 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5022 q = q.replace(tm[0], "");
5023 }else if(q.substr(0, 1) != '@'){
5024 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5029 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5031 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5033 q = q.replace(tm[0], "");
5036 while(!(mm = q.match(modeRe))){
5037 var matched = false;
5038 for(var j = 0; j < tklen; j++){
5040 var m = q.match(t.re);
5042 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5045 q = q.replace(m[0], "");
5050 // prevent infinite loop on bad selector
5052 throw 'Error parsing selector, parsing failed at "' + q + '"';
5056 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5057 q = q.replace(mm[1], "");
5060 fn[fn.length] = "return nodup(n);\n}";
5063 * list of variables that need from compression as they are used by eval.
5073 * eval:var:byClassName
5075 * eval:var:byAttribute
5076 * eval:var:attrValue
5084 * Selects a group of elements.
5085 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5086 * @param {Node} root (optional) The start of the query (defaults to document).
5089 select : function(path, root, type){
5090 if(!root || root == document){
5093 if(typeof root == "string"){
5094 root = document.getElementById(root);
5096 var paths = path.split(",");
5098 for(var i = 0, len = paths.length; i < len; i++){
5099 var p = paths[i].replace(trimRe, "");
5101 cache[p] = Roo.DomQuery.compile(p);
5103 throw p + " is not a valid selector";
5106 var result = cache[p](root);
5107 if(result && result != document){
5108 results = results.concat(result);
5111 if(paths.length > 1){
5112 return nodup(results);
5118 * Selects a single element.
5119 * @param {String} selector The selector/xpath query
5120 * @param {Node} root (optional) The start of the query (defaults to document).
5123 selectNode : function(path, root){
5124 return Roo.DomQuery.select(path, root)[0];
5128 * Selects the value of a node, optionally replacing null with the defaultValue.
5129 * @param {String} selector The selector/xpath query
5130 * @param {Node} root (optional) The start of the query (defaults to document).
5131 * @param {String} defaultValue
5133 selectValue : function(path, root, defaultValue){
5134 path = path.replace(trimRe, "");
5135 if(!valueCache[path]){
5136 valueCache[path] = Roo.DomQuery.compile(path, "select");
5138 var n = valueCache[path](root);
5139 n = n[0] ? n[0] : n;
5140 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5141 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5145 * Selects the value of a node, parsing integers and floats.
5146 * @param {String} selector The selector/xpath query
5147 * @param {Node} root (optional) The start of the query (defaults to document).
5148 * @param {Number} defaultValue
5151 selectNumber : function(path, root, defaultValue){
5152 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5153 return parseFloat(v);
5157 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5158 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5159 * @param {String} selector The simple selector to test
5162 is : function(el, ss){
5163 if(typeof el == "string"){
5164 el = document.getElementById(el);
5166 var isArray = (el instanceof Array);
5167 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5168 return isArray ? (result.length == el.length) : (result.length > 0);
5172 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5173 * @param {Array} el An array of elements to filter
5174 * @param {String} selector The simple selector to test
5175 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5176 * the selector instead of the ones that match
5179 filter : function(els, ss, nonMatches){
5180 ss = ss.replace(trimRe, "");
5181 if(!simpleCache[ss]){
5182 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5184 var result = simpleCache[ss](els);
5185 return nonMatches ? quickDiff(result, els) : result;
5189 * Collection of matching regular expressions and code snippets.
5193 select: 'n = byClassName(n, null, " {1} ");'
5195 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5196 select: 'n = byPseudo(n, "{1}", "{2}");'
5198 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5199 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5202 select: 'n = byId(n, null, "{1}");'
5205 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5210 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5211 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5214 "=" : function(a, v){
5217 "!=" : function(a, v){
5220 "^=" : function(a, v){
5221 return a && a.substr(0, v.length) == v;
5223 "$=" : function(a, v){
5224 return a && a.substr(a.length-v.length) == v;
5226 "*=" : function(a, v){
5227 return a && a.indexOf(v) !== -1;
5229 "%=" : function(a, v){
5230 return (a % v) == 0;
5232 "|=" : function(a, v){
5233 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5235 "~=" : function(a, v){
5236 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5241 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5242 * and the argument (if any) supplied in the selector.
5245 "first-child" : function(c){
5246 var r = [], ri = -1, n;
5247 for(var i = 0, ci; ci = n = c[i]; i++){
5248 while((n = n.previousSibling) && n.nodeType != 1);
5256 "last-child" : function(c){
5257 var r = [], ri = -1, n;
5258 for(var i = 0, ci; ci = n = c[i]; i++){
5259 while((n = n.nextSibling) && n.nodeType != 1);
5267 "nth-child" : function(c, a) {
5268 var r = [], ri = -1;
5269 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5270 var f = (m[1] || 1) - 0, l = m[2] - 0;
5271 for(var i = 0, n; n = c[i]; i++){
5272 var pn = n.parentNode;
5273 if (batch != pn._batch) {
5275 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5276 if(cn.nodeType == 1){
5283 if (l == 0 || n.nodeIndex == l){
5286 } else if ((n.nodeIndex + l) % f == 0){
5294 "only-child" : function(c){
5295 var r = [], ri = -1;;
5296 for(var i = 0, ci; ci = c[i]; i++){
5297 if(!prev(ci) && !next(ci)){
5304 "empty" : function(c){
5305 var r = [], ri = -1;
5306 for(var i = 0, ci; ci = c[i]; i++){
5307 var cns = ci.childNodes, j = 0, cn, empty = true;
5310 if(cn.nodeType == 1 || cn.nodeType == 3){
5322 "contains" : function(c, v){
5323 var r = [], ri = -1;
5324 for(var i = 0, ci; ci = c[i]; i++){
5325 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5332 "nodeValue" : function(c, v){
5333 var r = [], ri = -1;
5334 for(var i = 0, ci; ci = c[i]; i++){
5335 if(ci.firstChild && ci.firstChild.nodeValue == v){
5342 "checked" : function(c){
5343 var r = [], ri = -1;
5344 for(var i = 0, ci; ci = c[i]; i++){
5345 if(ci.checked == true){
5352 "not" : function(c, ss){
5353 return Roo.DomQuery.filter(c, ss, true);
5356 "odd" : function(c){
5357 return this["nth-child"](c, "odd");
5360 "even" : function(c){
5361 return this["nth-child"](c, "even");
5364 "nth" : function(c, a){
5365 return c[a-1] || [];
5368 "first" : function(c){
5372 "last" : function(c){
5373 return c[c.length-1] || [];
5376 "has" : function(c, ss){
5377 var s = Roo.DomQuery.select;
5378 var r = [], ri = -1;
5379 for(var i = 0, ci; ci = c[i]; i++){
5380 if(s(ss, ci).length > 0){
5387 "next" : function(c, ss){
5388 var is = Roo.DomQuery.is;
5389 var r = [], ri = -1;
5390 for(var i = 0, ci; ci = c[i]; i++){
5399 "prev" : function(c, ss){
5400 var is = Roo.DomQuery.is;
5401 var r = [], ri = -1;
5402 for(var i = 0, ci; ci = c[i]; i++){
5415 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5416 * @param {String} path The selector/xpath query
5417 * @param {Node} root (optional) The start of the query (defaults to document).
5422 Roo.query = Roo.DomQuery.select;
5425 * Ext JS Library 1.1.1
5426 * Copyright(c) 2006-2007, Ext JS, LLC.
5428 * Originally Released Under LGPL - original licence link has changed is not relivant.
5431 * <script type="text/javascript">
5435 * @class Roo.util.Observable
5436 * Base class that provides a common interface for publishing events. Subclasses are expected to
5437 * to have a property "events" with all the events defined.<br>
5440 Employee = function(name){
5447 Roo.extend(Employee, Roo.util.Observable);
5449 * @param {Object} config properties to use (incuding events / listeners)
5452 Roo.util.Observable = function(cfg){
5455 this.addEvents(cfg.events || {});
5457 delete cfg.events; // make sure
5460 Roo.apply(this, cfg);
5463 this.on(this.listeners);
5464 delete this.listeners;
5467 Roo.util.Observable.prototype = {
5469 * @cfg {Object} listeners list of events and functions to call for this object,
5473 'click' : function(e) {
5483 * Fires the specified event with the passed parameters (minus the event name).
5484 * @param {String} eventName
5485 * @param {Object...} args Variable number of parameters are passed to handlers
5486 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5488 fireEvent : function(){
5489 var ce = this.events[arguments[0].toLowerCase()];
5490 if(typeof ce == "object"){
5491 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5498 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5501 * Appends an event handler to this component
5502 * @param {String} eventName The type of event to listen for
5503 * @param {Function} handler The method the event invokes
5504 * @param {Object} scope (optional) The scope in which to execute the handler
5505 * function. The handler function's "this" context.
5506 * @param {Object} options (optional) An object containing handler configuration
5507 * properties. This may contain any of the following properties:<ul>
5508 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5509 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5510 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5511 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5512 * by the specified number of milliseconds. If the event fires again within that time, the original
5513 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5516 * <b>Combining Options</b><br>
5517 * Using the options argument, it is possible to combine different types of listeners:<br>
5519 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5521 el.on('click', this.onClick, this, {
5528 * <b>Attaching multiple handlers in 1 call</b><br>
5529 * The method also allows for a single argument to be passed which is a config object containing properties
5530 * which specify multiple handlers.
5539 fn: this.onMouseOver,
5543 fn: this.onMouseOut,
5549 * Or a shorthand syntax which passes the same scope object to all handlers:
5552 'click': this.onClick,
5553 'mouseover': this.onMouseOver,
5554 'mouseout': this.onMouseOut,
5559 addListener : function(eventName, fn, scope, o){
5560 if(typeof eventName == "object"){
5563 if(this.filterOptRe.test(e)){
5566 if(typeof o[e] == "function"){
5568 this.addListener(e, o[e], o.scope, o);
5570 // individual options
5571 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5576 o = (!o || typeof o == "boolean") ? {} : o;
5577 eventName = eventName.toLowerCase();
5578 var ce = this.events[eventName] || true;
5579 if(typeof ce == "boolean"){
5580 ce = new Roo.util.Event(this, eventName);
5581 this.events[eventName] = ce;
5583 ce.addListener(fn, scope, o);
5587 * Removes a listener
5588 * @param {String} eventName The type of event to listen for
5589 * @param {Function} handler The handler to remove
5590 * @param {Object} scope (optional) The scope (this object) for the handler
5592 removeListener : function(eventName, fn, scope){
5593 var ce = this.events[eventName.toLowerCase()];
5594 if(typeof ce == "object"){
5595 ce.removeListener(fn, scope);
5600 * Removes all listeners for this object
5602 purgeListeners : function(){
5603 for(var evt in this.events){
5604 if(typeof this.events[evt] == "object"){
5605 this.events[evt].clearListeners();
5610 relayEvents : function(o, events){
5611 var createHandler = function(ename){
5613 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5616 for(var i = 0, len = events.length; i < len; i++){
5617 var ename = events[i];
5618 if(!this.events[ename]){ this.events[ename] = true; };
5619 o.on(ename, createHandler(ename), this);
5624 * Used to define events on this Observable
5625 * @param {Object} object The object with the events defined
5627 addEvents : function(o){
5631 Roo.applyIf(this.events, o);
5635 * Checks to see if this object has any listeners for a specified event
5636 * @param {String} eventName The name of the event to check for
5637 * @return {Boolean} True if the event is being listened for, else false
5639 hasListener : function(eventName){
5640 var e = this.events[eventName];
5641 return typeof e == "object" && e.listeners.length > 0;
5645 * Appends an event handler to this element (shorthand for addListener)
5646 * @param {String} eventName The type of event to listen for
5647 * @param {Function} handler The method the event invokes
5648 * @param {Object} scope (optional) The scope in which to execute the handler
5649 * function. The handler function's "this" context.
5650 * @param {Object} options (optional)
5653 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5655 * Removes a listener (shorthand for removeListener)
5656 * @param {String} eventName The type of event to listen for
5657 * @param {Function} handler The handler to remove
5658 * @param {Object} scope (optional) The scope (this object) for the handler
5661 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5664 * Starts capture on the specified Observable. All events will be passed
5665 * to the supplied function with the event name + standard signature of the event
5666 * <b>before</b> the event is fired. If the supplied function returns false,
5667 * the event will not fire.
5668 * @param {Observable} o The Observable to capture
5669 * @param {Function} fn The function to call
5670 * @param {Object} scope (optional) The scope (this object) for the fn
5673 Roo.util.Observable.capture = function(o, fn, scope){
5674 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5678 * Removes <b>all</b> added captures from the Observable.
5679 * @param {Observable} o The Observable to release
5682 Roo.util.Observable.releaseCapture = function(o){
5683 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5688 var createBuffered = function(h, o, scope){
5689 var task = new Roo.util.DelayedTask();
5691 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5695 var createSingle = function(h, e, fn, scope){
5697 e.removeListener(fn, scope);
5698 return h.apply(scope, arguments);
5702 var createDelayed = function(h, o, scope){
5704 var args = Array.prototype.slice.call(arguments, 0);
5705 setTimeout(function(){
5706 h.apply(scope, args);
5711 Roo.util.Event = function(obj, name){
5714 this.listeners = [];
5717 Roo.util.Event.prototype = {
5718 addListener : function(fn, scope, options){
5719 var o = options || {};
5720 scope = scope || this.obj;
5721 if(!this.isListening(fn, scope)){
5722 var l = {fn: fn, scope: scope, options: o};
5725 h = createDelayed(h, o, scope);
5728 h = createSingle(h, this, fn, scope);
5731 h = createBuffered(h, o, scope);
5734 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5735 this.listeners.push(l);
5737 this.listeners = this.listeners.slice(0);
5738 this.listeners.push(l);
5743 findListener : function(fn, scope){
5744 scope = scope || this.obj;
5745 var ls = this.listeners;
5746 for(var i = 0, len = ls.length; i < len; i++){
5748 if(l.fn == fn && l.scope == scope){
5755 isListening : function(fn, scope){
5756 return this.findListener(fn, scope) != -1;
5759 removeListener : function(fn, scope){
5761 if((index = this.findListener(fn, scope)) != -1){
5763 this.listeners.splice(index, 1);
5765 this.listeners = this.listeners.slice(0);
5766 this.listeners.splice(index, 1);
5773 clearListeners : function(){
5774 this.listeners = [];
5778 var ls = this.listeners, scope, len = ls.length;
5781 var args = Array.prototype.slice.call(arguments, 0);
5782 for(var i = 0; i < len; i++){
5784 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5785 this.firing = false;
5789 this.firing = false;
5796 * Ext JS Library 1.1.1
5797 * Copyright(c) 2006-2007, Ext JS, LLC.
5799 * Originally Released Under LGPL - original licence link has changed is not relivant.
5802 * <script type="text/javascript">
5806 * @class Roo.EventManager
5807 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5808 * several useful events directly.
5809 * See {@link Roo.EventObject} for more details on normalized event objects.
5812 Roo.EventManager = function(){
5813 var docReadyEvent, docReadyProcId, docReadyState = false;
5814 var resizeEvent, resizeTask, textEvent, textSize;
5815 var E = Roo.lib.Event;
5816 var D = Roo.lib.Dom;
5819 var fireDocReady = function(){
5821 docReadyState = true;
5824 clearInterval(docReadyProcId);
5826 if(Roo.isGecko || Roo.isOpera) {
5827 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5830 var defer = document.getElementById("ie-deferred-loader");
5832 defer.onreadystatechange = null;
5833 defer.parentNode.removeChild(defer);
5837 docReadyEvent.fire();
5838 docReadyEvent.clearListeners();
5843 var initDocReady = function(){
5844 docReadyEvent = new Roo.util.Event();
5845 if(Roo.isGecko || Roo.isOpera) {
5846 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5848 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5849 var defer = document.getElementById("ie-deferred-loader");
5850 defer.onreadystatechange = function(){
5851 if(this.readyState == "complete"){
5855 }else if(Roo.isSafari){
5856 docReadyProcId = setInterval(function(){
5857 var rs = document.readyState;
5858 if(rs == "complete") {
5863 // no matter what, make sure it fires on load
5864 E.on(window, "load", fireDocReady);
5867 var createBuffered = function(h, o){
5868 var task = new Roo.util.DelayedTask(h);
5870 // create new event object impl so new events don't wipe out properties
5871 e = new Roo.EventObjectImpl(e);
5872 task.delay(o.buffer, h, null, [e]);
5876 var createSingle = function(h, el, ename, fn){
5878 Roo.EventManager.removeListener(el, ename, fn);
5883 var createDelayed = function(h, o){
5885 // create new event object impl so new events don't wipe out properties
5886 e = new Roo.EventObjectImpl(e);
5887 setTimeout(function(){
5893 var listen = function(element, ename, opt, fn, scope){
5894 var o = (!opt || typeof opt == "boolean") ? {} : opt;
5895 fn = fn || o.fn; scope = scope || o.scope;
5896 var el = Roo.getDom(element);
5898 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5900 var h = function(e){
5901 e = Roo.EventObject.setEvent(e);
5904 t = e.getTarget(o.delegate, el);
5911 if(o.stopEvent === true){
5914 if(o.preventDefault === true){
5917 if(o.stopPropagation === true){
5918 e.stopPropagation();
5921 if(o.normalized === false){
5925 fn.call(scope || el, e, t, o);
5928 h = createDelayed(h, o);
5931 h = createSingle(h, el, ename, fn);
5934 h = createBuffered(h, o);
5936 fn._handlers = fn._handlers || [];
5937 fn._handlers.push([Roo.id(el), ename, h]);
5940 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5941 el.addEventListener("DOMMouseScroll", h, false);
5942 E.on(window, 'unload', function(){
5943 el.removeEventListener("DOMMouseScroll", h, false);
5946 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5947 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5952 var stopListening = function(el, ename, fn){
5953 var id = Roo.id(el), hds = fn._handlers, hd = fn;
5955 for(var i = 0, len = hds.length; i < len; i++){
5957 if(h[0] == id && h[1] == ename){
5964 E.un(el, ename, hd);
5965 el = Roo.getDom(el);
5966 if(ename == "mousewheel" && el.addEventListener){
5967 el.removeEventListener("DOMMouseScroll", hd, false);
5969 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5970 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5974 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
5981 * @scope Roo.EventManager
5986 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
5987 * object with a Roo.EventObject
5988 * @param {Function} fn The method the event invokes
5989 * @param {Object} scope An object that becomes the scope of the handler
5990 * @param {boolean} override If true, the obj passed in becomes
5991 * the execution scope of the listener
5992 * @return {Function} The wrapped function
5995 wrap : function(fn, scope, override){
5997 Roo.EventObject.setEvent(e);
5998 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6003 * Appends an event handler to an element (shorthand for addListener)
6004 * @param {String/HTMLElement} element The html element or id to assign the
6005 * @param {String} eventName The type of event to listen for
6006 * @param {Function} handler The method the event invokes
6007 * @param {Object} scope (optional) The scope in which to execute the handler
6008 * function. The handler function's "this" context.
6009 * @param {Object} options (optional) An object containing handler configuration
6010 * properties. This may contain any of the following properties:<ul>
6011 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6012 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6013 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6014 * <li>preventDefault {Boolean} True to prevent the default action</li>
6015 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6016 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6017 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6018 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6019 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6020 * by the specified number of milliseconds. If the event fires again within that time, the original
6021 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6024 * <b>Combining Options</b><br>
6025 * Using the options argument, it is possible to combine different types of listeners:<br>
6027 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6029 el.on('click', this.onClick, this, {
6036 * <b>Attaching multiple handlers in 1 call</b><br>
6037 * The method also allows for a single argument to be passed which is a config object containing properties
6038 * which specify multiple handlers.
6048 fn: this.onMouseOver
6057 * Or a shorthand syntax:<br>
6060 'click' : this.onClick,
6061 'mouseover' : this.onMouseOver,
6062 'mouseout' : this.onMouseOut
6066 addListener : function(element, eventName, fn, scope, options){
6067 if(typeof eventName == "object"){
6073 if(typeof o[e] == "function"){
6075 listen(element, e, o, o[e], o.scope);
6077 // individual options
6078 listen(element, e, o[e]);
6083 return listen(element, eventName, options, fn, scope);
6087 * Removes an event handler
6089 * @param {String/HTMLElement} element The id or html element to remove the
6091 * @param {String} eventName The type of event
6092 * @param {Function} fn
6093 * @return {Boolean} True if a listener was actually removed
6095 removeListener : function(element, eventName, fn){
6096 return stopListening(element, eventName, fn);
6100 * Fires when the document is ready (before onload and before images are loaded). Can be
6101 * accessed shorthanded Roo.onReady().
6102 * @param {Function} fn The method the event invokes
6103 * @param {Object} scope An object that becomes the scope of the handler
6104 * @param {boolean} options
6106 onDocumentReady : function(fn, scope, options){
6107 if(docReadyState){ // if it already fired
6108 docReadyEvent.addListener(fn, scope, options);
6109 docReadyEvent.fire();
6110 docReadyEvent.clearListeners();
6116 docReadyEvent.addListener(fn, scope, options);
6120 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6121 * @param {Function} fn The method the event invokes
6122 * @param {Object} scope An object that becomes the scope of the handler
6123 * @param {boolean} options
6125 onWindowResize : function(fn, scope, options){
6127 resizeEvent = new Roo.util.Event();
6128 resizeTask = new Roo.util.DelayedTask(function(){
6129 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6131 E.on(window, "resize", function(){
6133 resizeTask.delay(50);
6135 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6139 resizeEvent.addListener(fn, scope, options);
6143 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6144 * @param {Function} fn The method the event invokes
6145 * @param {Object} scope An object that becomes the scope of the handler
6146 * @param {boolean} options
6148 onTextResize : function(fn, scope, options){
6150 textEvent = new Roo.util.Event();
6151 var textEl = new Roo.Element(document.createElement('div'));
6152 textEl.dom.className = 'x-text-resize';
6153 textEl.dom.innerHTML = 'X';
6154 textEl.appendTo(document.body);
6155 textSize = textEl.dom.offsetHeight;
6156 setInterval(function(){
6157 if(textEl.dom.offsetHeight != textSize){
6158 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6160 }, this.textResizeInterval);
6162 textEvent.addListener(fn, scope, options);
6166 * Removes the passed window resize listener.
6167 * @param {Function} fn The method the event invokes
6168 * @param {Object} scope The scope of handler
6170 removeResizeListener : function(fn, scope){
6172 resizeEvent.removeListener(fn, scope);
6177 fireResize : function(){
6179 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6183 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6187 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6189 textResizeInterval : 50
6194 * @scopeAlias pub=Roo.EventManager
6198 * Appends an event handler to an element (shorthand for addListener)
6199 * @param {String/HTMLElement} element The html element or id to assign the
6200 * @param {String} eventName The type of event to listen for
6201 * @param {Function} handler The method the event invokes
6202 * @param {Object} scope (optional) The scope in which to execute the handler
6203 * function. The handler function's "this" context.
6204 * @param {Object} options (optional) An object containing handler configuration
6205 * properties. This may contain any of the following properties:<ul>
6206 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6207 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6208 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6209 * <li>preventDefault {Boolean} True to prevent the default action</li>
6210 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6211 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6212 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6213 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6214 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6215 * by the specified number of milliseconds. If the event fires again within that time, the original
6216 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6219 * <b>Combining Options</b><br>
6220 * Using the options argument, it is possible to combine different types of listeners:<br>
6222 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6224 el.on('click', this.onClick, this, {
6231 * <b>Attaching multiple handlers in 1 call</b><br>
6232 * The method also allows for a single argument to be passed which is a config object containing properties
6233 * which specify multiple handlers.
6243 fn: this.onMouseOver
6252 * Or a shorthand syntax:<br>
6255 'click' : this.onClick,
6256 'mouseover' : this.onMouseOver,
6257 'mouseout' : this.onMouseOut
6261 pub.on = pub.addListener;
6262 pub.un = pub.removeListener;
6264 pub.stoppedMouseDownEvent = new Roo.util.Event();
6268 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6269 * @param {Function} fn The method the event invokes
6270 * @param {Object} scope An object that becomes the scope of the handler
6271 * @param {boolean} override If true, the obj passed in becomes
6272 * the execution scope of the listener
6276 Roo.onReady = Roo.EventManager.onDocumentReady;
6278 Roo.onReady(function(){
6279 var bd = Roo.get(document.body);
6284 : Roo.isGecko ? "roo-gecko"
6285 : Roo.isOpera ? "roo-opera"
6286 : Roo.isSafari ? "roo-safari" : ""];
6289 cls.push("roo-mac");
6292 cls.push("roo-linux");
6294 if(Roo.isBorderBox){
6295 cls.push('roo-border-box');
6297 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6298 var p = bd.dom.parentNode;
6300 p.className += ' roo-strict';
6303 bd.addClass(cls.join(' '));
6307 * @class Roo.EventObject
6308 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6309 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6312 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6314 var target = e.getTarget();
6317 var myDiv = Roo.get("myDiv");
6318 myDiv.on("click", handleClick);
6320 Roo.EventManager.on("myDiv", 'click', handleClick);
6321 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6325 Roo.EventObject = function(){
6327 var E = Roo.lib.Event;
6329 // safari keypress events for special keys return bad keycodes
6332 63235 : 39, // right
6335 63276 : 33, // page up
6336 63277 : 34, // page down
6337 63272 : 46, // delete
6342 // normalize button clicks
6343 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6344 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6346 Roo.EventObjectImpl = function(e){
6348 this.setEvent(e.browserEvent || e);
6351 Roo.EventObjectImpl.prototype = {
6353 * Used to fix doc tools.
6354 * @scope Roo.EventObject.prototype
6360 /** The normal browser event */
6361 browserEvent : null,
6362 /** The button pressed in a mouse event */
6364 /** True if the shift key was down during the event */
6366 /** True if the control key was down during the event */
6368 /** True if the alt key was down during the event */
6427 setEvent : function(e){
6428 if(e == this || (e && e.browserEvent)){ // already wrapped
6431 this.browserEvent = e;
6433 // normalize buttons
6434 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6435 if(e.type == 'click' && this.button == -1){
6439 this.shiftKey = e.shiftKey;
6440 // mac metaKey behaves like ctrlKey
6441 this.ctrlKey = e.ctrlKey || e.metaKey;
6442 this.altKey = e.altKey;
6443 // in getKey these will be normalized for the mac
6444 this.keyCode = e.keyCode;
6445 // keyup warnings on firefox.
6446 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6447 // cache the target for the delayed and or buffered events
6448 this.target = E.getTarget(e);
6450 this.xy = E.getXY(e);
6453 this.shiftKey = false;
6454 this.ctrlKey = false;
6455 this.altKey = false;
6465 * Stop the event (preventDefault and stopPropagation)
6467 stopEvent : function(){
6468 if(this.browserEvent){
6469 if(this.browserEvent.type == 'mousedown'){
6470 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6472 E.stopEvent(this.browserEvent);
6477 * Prevents the browsers default handling of the event.
6479 preventDefault : function(){
6480 if(this.browserEvent){
6481 E.preventDefault(this.browserEvent);
6486 isNavKeyPress : function(){
6487 var k = this.keyCode;
6488 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6489 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6492 isSpecialKey : function(){
6493 var k = this.keyCode;
6494 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6495 (k == 16) || (k == 17) ||
6496 (k >= 18 && k <= 20) ||
6497 (k >= 33 && k <= 35) ||
6498 (k >= 36 && k <= 39) ||
6499 (k >= 44 && k <= 45);
6502 * Cancels bubbling of the event.
6504 stopPropagation : function(){
6505 if(this.browserEvent){
6506 if(this.type == 'mousedown'){
6507 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6509 E.stopPropagation(this.browserEvent);
6514 * Gets the key code for the event.
6517 getCharCode : function(){
6518 return this.charCode || this.keyCode;
6522 * Returns a normalized keyCode for the event.
6523 * @return {Number} The key code
6525 getKey : function(){
6526 var k = this.keyCode || this.charCode;
6527 return Roo.isSafari ? (safariKeys[k] || k) : k;
6531 * Gets the x coordinate of the event.
6534 getPageX : function(){
6539 * Gets the y coordinate of the event.
6542 getPageY : function(){
6547 * Gets the time of the event.
6550 getTime : function(){
6551 if(this.browserEvent){
6552 return E.getTime(this.browserEvent);
6558 * Gets the page coordinates of the event.
6559 * @return {Array} The xy values like [x, y]
6566 * Gets the target for the event.
6567 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6568 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6569 search as a number or element (defaults to 10 || document.body)
6570 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6571 * @return {HTMLelement}
6573 getTarget : function(selector, maxDepth, returnEl){
6574 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6577 * Gets the related target.
6578 * @return {HTMLElement}
6580 getRelatedTarget : function(){
6581 if(this.browserEvent){
6582 return E.getRelatedTarget(this.browserEvent);
6588 * Normalizes mouse wheel delta across browsers
6589 * @return {Number} The delta
6591 getWheelDelta : function(){
6592 var e = this.browserEvent;
6594 if(e.wheelDelta){ /* IE/Opera. */
6595 delta = e.wheelDelta/120;
6596 }else if(e.detail){ /* Mozilla case. */
6597 delta = -e.detail/3;
6603 * Returns true if the control, meta, shift or alt key was pressed during this event.
6606 hasModifier : function(){
6607 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6611 * Returns true if the target of this event equals el or is a child of el
6612 * @param {String/HTMLElement/Element} el
6613 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6616 within : function(el, related){
6617 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6618 return t && Roo.fly(el).contains(t);
6621 getPoint : function(){
6622 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6626 return new Roo.EventObjectImpl();
6631 * Ext JS Library 1.1.1
6632 * Copyright(c) 2006-2007, Ext JS, LLC.
6634 * Originally Released Under LGPL - original licence link has changed is not relivant.
6637 * <script type="text/javascript">
6641 // was in Composite Element!??!?!
6644 var D = Roo.lib.Dom;
6645 var E = Roo.lib.Event;
6646 var A = Roo.lib.Anim;
6648 // local style camelizing for speed
6650 var camelRe = /(-[a-z])/gi;
6651 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6652 var view = document.defaultView;
6655 * @class Roo.Element
6656 * Represents an Element in the DOM.<br><br>
6659 var el = Roo.get("my-div");
6662 var el = getEl("my-div");
6664 // or with a DOM element
6665 var el = Roo.get(myDivElement);
6667 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6668 * each call instead of constructing a new one.<br><br>
6669 * <b>Animations</b><br />
6670 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6671 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6673 Option Default Description
6674 --------- -------- ---------------------------------------------
6675 duration .35 The duration of the animation in seconds
6676 easing easeOut The YUI easing method
6677 callback none A function to execute when the anim completes
6678 scope this The scope (this) of the callback function
6680 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6681 * manipulate the animation. Here's an example:
6683 var el = Roo.get("my-div");
6688 // default animation
6689 el.setWidth(100, true);
6691 // animation with some options set
6698 // using the "anim" property to get the Anim object
6704 el.setWidth(100, opt);
6706 if(opt.anim.isAnimated()){
6710 * <b> Composite (Collections of) Elements</b><br />
6711 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6712 * @constructor Create a new Element directly.
6713 * @param {String/HTMLElement} element
6714 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6716 Roo.Element = function(element, forceNew){
6717 var dom = typeof element == "string" ?
6718 document.getElementById(element) : element;
6719 if(!dom){ // invalid id/element
6723 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6724 return Roo.Element.cache[id];
6734 * The DOM element ID
6737 this.id = id || Roo.id(dom);
6740 var El = Roo.Element;
6744 * The element's default display mode (defaults to "")
6747 originalDisplay : "",
6751 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6756 * Sets the element's visibility mode. When setVisible() is called it
6757 * will use this to determine whether to set the visibility or the display property.
6758 * @param visMode Element.VISIBILITY or Element.DISPLAY
6759 * @return {Roo.Element} this
6761 setVisibilityMode : function(visMode){
6762 this.visibilityMode = visMode;
6766 * Convenience method for setVisibilityMode(Element.DISPLAY)
6767 * @param {String} display (optional) What to set display to when visible
6768 * @return {Roo.Element} this
6770 enableDisplayMode : function(display){
6771 this.setVisibilityMode(El.DISPLAY);
6772 if(typeof display != "undefined") this.originalDisplay = display;
6777 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6778 * @param {String} selector The simple selector to test
6779 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6780 search as a number or element (defaults to 10 || document.body)
6781 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6782 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6784 findParent : function(simpleSelector, maxDepth, returnEl){
6785 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6786 maxDepth = maxDepth || 50;
6787 if(typeof maxDepth != "number"){
6788 stopEl = Roo.getDom(maxDepth);
6791 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6792 if(dq.is(p, simpleSelector)){
6793 return returnEl ? Roo.get(p) : p;
6803 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6804 * @param {String} selector The simple selector to test
6805 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6806 search as a number or element (defaults to 10 || document.body)
6807 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6808 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6810 findParentNode : function(simpleSelector, maxDepth, returnEl){
6811 var p = Roo.fly(this.dom.parentNode, '_internal');
6812 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6816 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6817 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6818 * @param {String} selector The simple selector to test
6819 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6820 search as a number or element (defaults to 10 || document.body)
6821 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6823 up : function(simpleSelector, maxDepth){
6824 return this.findParentNode(simpleSelector, maxDepth, true);
6830 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6831 * @param {String} selector The simple selector to test
6832 * @return {Boolean} True if this element matches the selector, else false
6834 is : function(simpleSelector){
6835 return Roo.DomQuery.is(this.dom, simpleSelector);
6839 * Perform animation on this element.
6840 * @param {Object} args The YUI animation control args
6841 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6842 * @param {Function} onComplete (optional) Function to call when animation completes
6843 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6844 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6845 * @return {Roo.Element} this
6847 animate : function(args, duration, onComplete, easing, animType){
6848 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6853 * @private Internal animation call
6855 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6856 animType = animType || 'run';
6858 var anim = Roo.lib.Anim[animType](
6860 (opt.duration || defaultDur) || .35,
6861 (opt.easing || defaultEase) || 'easeOut',
6863 Roo.callback(cb, this);
6864 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6872 // private legacy anim prep
6873 preanim : function(a, i){
6874 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6878 * Removes worthless text nodes
6879 * @param {Boolean} forceReclean (optional) By default the element
6880 * keeps track if it has been cleaned already so
6881 * you can call this over and over. However, if you update the element and
6882 * need to force a reclean, you can pass true.
6884 clean : function(forceReclean){
6885 if(this.isCleaned && forceReclean !== true){
6889 var d = this.dom, n = d.firstChild, ni = -1;
6891 var nx = n.nextSibling;
6892 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6899 this.isCleaned = true;
6904 calcOffsetsTo : function(el){
6907 var restorePos = false;
6908 if(el.getStyle('position') == 'static'){
6909 el.position('relative');
6914 while(op && op != d && op.tagName != 'HTML'){
6917 op = op.offsetParent;
6920 el.position('static');
6926 * Scrolls this element into view within the passed container.
6927 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6928 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6929 * @return {Roo.Element} this
6931 scrollIntoView : function(container, hscroll){
6932 var c = Roo.getDom(container) || document.body;
6935 var o = this.calcOffsetsTo(c),
6938 b = t+el.offsetHeight,
6939 r = l+el.offsetWidth;
6941 var ch = c.clientHeight;
6942 var ct = parseInt(c.scrollTop, 10);
6943 var cl = parseInt(c.scrollLeft, 10);
6945 var cr = cl + c.clientWidth;
6953 if(hscroll !== false){
6957 c.scrollLeft = r-c.clientWidth;
6964 scrollChildIntoView : function(child, hscroll){
6965 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6969 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6970 * the new height may not be available immediately.
6971 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6972 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6973 * @param {Function} onComplete (optional) Function to call when animation completes
6974 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
6975 * @return {Roo.Element} this
6977 autoHeight : function(animate, duration, onComplete, easing){
6978 var oldHeight = this.getHeight();
6980 this.setHeight(1); // force clipping
6981 setTimeout(function(){
6982 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
6984 this.setHeight(height);
6986 if(typeof onComplete == "function"){
6990 this.setHeight(oldHeight); // restore original height
6991 this.setHeight(height, animate, duration, function(){
6993 if(typeof onComplete == "function") onComplete();
6994 }.createDelegate(this), easing);
6996 }.createDelegate(this), 0);
7001 * Returns true if this element is an ancestor of the passed element
7002 * @param {HTMLElement/String} el The element to check
7003 * @return {Boolean} True if this element is an ancestor of el, else false
7005 contains : function(el){
7006 if(!el){return false;}
7007 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7011 * Checks whether the element is currently visible using both visibility and display properties.
7012 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7013 * @return {Boolean} True if the element is currently visible, else false
7015 isVisible : function(deep) {
7016 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7017 if(deep !== true || !vis){
7020 var p = this.dom.parentNode;
7021 while(p && p.tagName.toLowerCase() != "body"){
7022 if(!Roo.fly(p, '_isVisible').isVisible()){
7031 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7032 * @param {String} selector The CSS selector
7033 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7034 * @return {CompositeElement/CompositeElementLite} The composite element
7036 select : function(selector, unique){
7037 return El.select(selector, unique, this.dom);
7041 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7042 * @param {String} selector The CSS selector
7043 * @return {Array} An array of the matched nodes
7045 query : function(selector, unique){
7046 return Roo.DomQuery.select(selector, this.dom);
7050 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7051 * @param {String} selector The CSS selector
7052 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7053 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7055 child : function(selector, returnDom){
7056 var n = Roo.DomQuery.selectNode(selector, this.dom);
7057 return returnDom ? n : Roo.get(n);
7061 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7062 * @param {String} selector The CSS selector
7063 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7064 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7066 down : function(selector, returnDom){
7067 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7068 return returnDom ? n : Roo.get(n);
7072 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7073 * @param {String} group The group the DD object is member of
7074 * @param {Object} config The DD config object
7075 * @param {Object} overrides An object containing methods to override/implement on the DD object
7076 * @return {Roo.dd.DD} The DD object
7078 initDD : function(group, config, overrides){
7079 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7080 return Roo.apply(dd, overrides);
7084 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7085 * @param {String} group The group the DDProxy object is member of
7086 * @param {Object} config The DDProxy config object
7087 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7088 * @return {Roo.dd.DDProxy} The DDProxy object
7090 initDDProxy : function(group, config, overrides){
7091 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7092 return Roo.apply(dd, overrides);
7096 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7097 * @param {String} group The group the DDTarget object is member of
7098 * @param {Object} config The DDTarget config object
7099 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7100 * @return {Roo.dd.DDTarget} The DDTarget object
7102 initDDTarget : function(group, config, overrides){
7103 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7104 return Roo.apply(dd, overrides);
7108 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7109 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7110 * @param {Boolean} visible Whether the element is visible
7111 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7112 * @return {Roo.Element} this
7114 setVisible : function(visible, animate){
7116 if(this.visibilityMode == El.DISPLAY){
7117 this.setDisplayed(visible);
7120 this.dom.style.visibility = visible ? "visible" : "hidden";
7123 // closure for composites
7125 var visMode = this.visibilityMode;
7127 this.setOpacity(.01);
7128 this.setVisible(true);
7130 this.anim({opacity: { to: (visible?1:0) }},
7131 this.preanim(arguments, 1),
7132 null, .35, 'easeIn', function(){
7134 if(visMode == El.DISPLAY){
7135 dom.style.display = "none";
7137 dom.style.visibility = "hidden";
7139 Roo.get(dom).setOpacity(1);
7147 * Returns true if display is not "none"
7150 isDisplayed : function() {
7151 return this.getStyle("display") != "none";
7155 * Toggles the element's visibility or display, depending on visibility mode.
7156 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7157 * @return {Roo.Element} this
7159 toggle : function(animate){
7160 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7165 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7166 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7167 * @return {Roo.Element} this
7169 setDisplayed : function(value) {
7170 if(typeof value == "boolean"){
7171 value = value ? this.originalDisplay : "none";
7173 this.setStyle("display", value);
7178 * Tries to focus the element. Any exceptions are caught and ignored.
7179 * @return {Roo.Element} this
7181 focus : function() {
7189 * Tries to blur the element. Any exceptions are caught and ignored.
7190 * @return {Roo.Element} this
7200 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7201 * @param {String/Array} className The CSS class to add, or an array of classes
7202 * @return {Roo.Element} this
7204 addClass : function(className){
7205 if(className instanceof Array){
7206 for(var i = 0, len = className.length; i < len; i++) {
7207 this.addClass(className[i]);
7210 if(className && !this.hasClass(className)){
7211 this.dom.className = this.dom.className + " " + className;
7218 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7219 * @param {String/Array} className The CSS class to add, or an array of classes
7220 * @return {Roo.Element} this
7222 radioClass : function(className){
7223 var siblings = this.dom.parentNode.childNodes;
7224 for(var i = 0; i < siblings.length; i++) {
7225 var s = siblings[i];
7226 if(s.nodeType == 1){
7227 Roo.get(s).removeClass(className);
7230 this.addClass(className);
7235 * Removes one or more CSS classes from the element.
7236 * @param {String/Array} className The CSS class to remove, or an array of classes
7237 * @return {Roo.Element} this
7239 removeClass : function(className){
7240 if(!className || !this.dom.className){
7243 if(className instanceof Array){
7244 for(var i = 0, len = className.length; i < len; i++) {
7245 this.removeClass(className[i]);
7248 if(this.hasClass(className)){
7249 var re = this.classReCache[className];
7251 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7252 this.classReCache[className] = re;
7254 this.dom.className =
7255 this.dom.className.replace(re, " ");
7265 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7266 * @param {String} className The CSS class to toggle
7267 * @return {Roo.Element} this
7269 toggleClass : function(className){
7270 if(this.hasClass(className)){
7271 this.removeClass(className);
7273 this.addClass(className);
7279 * Checks if the specified CSS class exists on this element's DOM node.
7280 * @param {String} className The CSS class to check for
7281 * @return {Boolean} True if the class exists, else false
7283 hasClass : function(className){
7284 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7288 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7289 * @param {String} oldClassName The CSS class to replace
7290 * @param {String} newClassName The replacement CSS class
7291 * @return {Roo.Element} this
7293 replaceClass : function(oldClassName, newClassName){
7294 this.removeClass(oldClassName);
7295 this.addClass(newClassName);
7300 * Returns an object with properties matching the styles requested.
7301 * For example, el.getStyles('color', 'font-size', 'width') might return
7302 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7303 * @param {String} style1 A style name
7304 * @param {String} style2 A style name
7305 * @param {String} etc.
7306 * @return {Object} The style object
7308 getStyles : function(){
7309 var a = arguments, len = a.length, r = {};
7310 for(var i = 0; i < len; i++){
7311 r[a[i]] = this.getStyle(a[i]);
7317 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7318 * @param {String} property The style property whose value is returned.
7319 * @return {String} The current value of the style property for this element.
7321 getStyle : function(){
7322 return view && view.getComputedStyle ?
7324 var el = this.dom, v, cs, camel;
7325 if(prop == 'float'){
7328 if(el.style && (v = el.style[prop])){
7331 if(cs = view.getComputedStyle(el, "")){
7332 if(!(camel = propCache[prop])){
7333 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7340 var el = this.dom, v, cs, camel;
7341 if(prop == 'opacity'){
7342 if(typeof el.style.filter == 'string'){
7343 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7345 var fv = parseFloat(m[1]);
7347 return fv ? fv / 100 : 0;
7352 }else if(prop == 'float'){
7353 prop = "styleFloat";
7355 if(!(camel = propCache[prop])){
7356 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7358 if(v = el.style[camel]){
7361 if(cs = el.currentStyle){
7369 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7370 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7371 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7372 * @return {Roo.Element} this
7374 setStyle : function(prop, value){
7375 if(typeof prop == "string"){
7377 if (prop == 'float') {
7378 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7383 if(!(camel = propCache[prop])){
7384 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7387 if(camel == 'opacity') {
7388 this.setOpacity(value);
7390 this.dom.style[camel] = value;
7393 for(var style in prop){
7394 if(typeof prop[style] != "function"){
7395 this.setStyle(style, prop[style]);
7403 * More flexible version of {@link #setStyle} for setting style properties.
7404 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7405 * a function which returns such a specification.
7406 * @return {Roo.Element} this
7408 applyStyles : function(style){
7409 Roo.DomHelper.applyStyles(this.dom, style);
7414 * 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).
7415 * @return {Number} The X position of the element
7418 return D.getX(this.dom);
7422 * 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).
7423 * @return {Number} The Y position of the element
7426 return D.getY(this.dom);
7430 * 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).
7431 * @return {Array} The XY position of the element
7434 return D.getXY(this.dom);
7438 * 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).
7439 * @param {Number} The X position of the element
7440 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7441 * @return {Roo.Element} this
7443 setX : function(x, animate){
7445 D.setX(this.dom, x);
7447 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7453 * 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).
7454 * @param {Number} The Y position of the element
7455 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7456 * @return {Roo.Element} this
7458 setY : function(y, animate){
7460 D.setY(this.dom, y);
7462 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7468 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7469 * @param {String} left The left CSS property value
7470 * @return {Roo.Element} this
7472 setLeft : function(left){
7473 this.setStyle("left", this.addUnits(left));
7478 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7479 * @param {String} top The top CSS property value
7480 * @return {Roo.Element} this
7482 setTop : function(top){
7483 this.setStyle("top", this.addUnits(top));
7488 * Sets the element's CSS right style.
7489 * @param {String} right The right CSS property value
7490 * @return {Roo.Element} this
7492 setRight : function(right){
7493 this.setStyle("right", this.addUnits(right));
7498 * Sets the element's CSS bottom style.
7499 * @param {String} bottom The bottom CSS property value
7500 * @return {Roo.Element} this
7502 setBottom : function(bottom){
7503 this.setStyle("bottom", this.addUnits(bottom));
7508 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7509 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7510 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7511 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7512 * @return {Roo.Element} this
7514 setXY : function(pos, animate){
7516 D.setXY(this.dom, pos);
7518 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7524 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7525 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7526 * @param {Number} x X value for new position (coordinates are page-based)
7527 * @param {Number} y Y value for new position (coordinates are page-based)
7528 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7529 * @return {Roo.Element} this
7531 setLocation : function(x, y, animate){
7532 this.setXY([x, y], this.preanim(arguments, 2));
7537 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7538 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7539 * @param {Number} x X value for new position (coordinates are page-based)
7540 * @param {Number} y Y value for new position (coordinates are page-based)
7541 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7542 * @return {Roo.Element} this
7544 moveTo : function(x, y, animate){
7545 this.setXY([x, y], this.preanim(arguments, 2));
7550 * Returns the region of the given element.
7551 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7552 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7554 getRegion : function(){
7555 return D.getRegion(this.dom);
7559 * Returns the offset height of the element
7560 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7561 * @return {Number} The element's height
7563 getHeight : function(contentHeight){
7564 var h = this.dom.offsetHeight || 0;
7565 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7569 * Returns the offset width of the element
7570 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7571 * @return {Number} The element's width
7573 getWidth : function(contentWidth){
7574 var w = this.dom.offsetWidth || 0;
7575 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7579 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7580 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7581 * if a height has not been set using CSS.
7584 getComputedHeight : function(){
7585 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7587 h = parseInt(this.getStyle('height'), 10) || 0;
7588 if(!this.isBorderBox()){
7589 h += this.getFrameWidth('tb');
7596 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7597 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7598 * if a width has not been set using CSS.
7601 getComputedWidth : function(){
7602 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7604 w = parseInt(this.getStyle('width'), 10) || 0;
7605 if(!this.isBorderBox()){
7606 w += this.getFrameWidth('lr');
7613 * Returns the size of the element.
7614 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7615 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7617 getSize : function(contentSize){
7618 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7622 * Returns the width and height of the viewport.
7623 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7625 getViewSize : function(){
7626 var d = this.dom, doc = document, aw = 0, ah = 0;
7627 if(d == doc || d == doc.body){
7628 return {width : D.getViewWidth(), height: D.getViewHeight()};
7631 width : d.clientWidth,
7632 height: d.clientHeight
7638 * Returns the value of the "value" attribute
7639 * @param {Boolean} asNumber true to parse the value as a number
7640 * @return {String/Number}
7642 getValue : function(asNumber){
7643 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7647 adjustWidth : function(width){
7648 if(typeof width == "number"){
7649 if(this.autoBoxAdjust && !this.isBorderBox()){
7650 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7660 adjustHeight : function(height){
7661 if(typeof height == "number"){
7662 if(this.autoBoxAdjust && !this.isBorderBox()){
7663 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7673 * Set the width of the element
7674 * @param {Number} width The new width
7675 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7676 * @return {Roo.Element} this
7678 setWidth : function(width, animate){
7679 width = this.adjustWidth(width);
7681 this.dom.style.width = this.addUnits(width);
7683 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7689 * Set the height of the element
7690 * @param {Number} height The new height
7691 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7692 * @return {Roo.Element} this
7694 setHeight : function(height, animate){
7695 height = this.adjustHeight(height);
7697 this.dom.style.height = this.addUnits(height);
7699 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7705 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7706 * @param {Number} width The new width
7707 * @param {Number} height The new height
7708 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7709 * @return {Roo.Element} this
7711 setSize : function(width, height, animate){
7712 if(typeof width == "object"){ // in case of object from getSize()
7713 height = width.height; width = width.width;
7715 width = this.adjustWidth(width); height = this.adjustHeight(height);
7717 this.dom.style.width = this.addUnits(width);
7718 this.dom.style.height = this.addUnits(height);
7720 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7726 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7727 * @param {Number} x X value for new position (coordinates are page-based)
7728 * @param {Number} y Y value for new position (coordinates are page-based)
7729 * @param {Number} width The new width
7730 * @param {Number} height The new height
7731 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7732 * @return {Roo.Element} this
7734 setBounds : function(x, y, width, height, animate){
7736 this.setSize(width, height);
7737 this.setLocation(x, y);
7739 width = this.adjustWidth(width); height = this.adjustHeight(height);
7740 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7741 this.preanim(arguments, 4), 'motion');
7747 * 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.
7748 * @param {Roo.lib.Region} region The region to fill
7749 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7750 * @return {Roo.Element} this
7752 setRegion : function(region, animate){
7753 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7758 * Appends an event handler
7760 * @param {String} eventName The type of event to append
7761 * @param {Function} fn The method the event invokes
7762 * @param {Object} scope (optional) The scope (this object) of the fn
7763 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7765 addListener : function(eventName, fn, scope, options){
7766 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7770 * Removes an event handler from this element
7771 * @param {String} eventName the type of event to remove
7772 * @param {Function} fn the method the event invokes
7773 * @return {Roo.Element} this
7775 removeListener : function(eventName, fn){
7776 Roo.EventManager.removeListener(this.dom, eventName, fn);
7781 * Removes all previous added listeners from this element
7782 * @return {Roo.Element} this
7784 removeAllListeners : function(){
7785 E.purgeElement(this.dom);
7789 relayEvent : function(eventName, observable){
7790 this.on(eventName, function(e){
7791 observable.fireEvent(eventName, e);
7796 * Set the opacity of the element
7797 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7798 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7799 * @return {Roo.Element} this
7801 setOpacity : function(opacity, animate){
7803 var s = this.dom.style;
7806 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7807 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7809 s.opacity = opacity;
7812 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7818 * Gets the left X coordinate
7819 * @param {Boolean} local True to get the local css position instead of page coordinate
7822 getLeft : function(local){
7826 return parseInt(this.getStyle("left"), 10) || 0;
7831 * Gets the right X coordinate of the element (element X position + element width)
7832 * @param {Boolean} local True to get the local css position instead of page coordinate
7835 getRight : function(local){
7837 return this.getX() + this.getWidth();
7839 return (this.getLeft(true) + this.getWidth()) || 0;
7844 * Gets the top Y coordinate
7845 * @param {Boolean} local True to get the local css position instead of page coordinate
7848 getTop : function(local) {
7852 return parseInt(this.getStyle("top"), 10) || 0;
7857 * Gets the bottom Y coordinate of the element (element Y position + element height)
7858 * @param {Boolean} local True to get the local css position instead of page coordinate
7861 getBottom : function(local){
7863 return this.getY() + this.getHeight();
7865 return (this.getTop(true) + this.getHeight()) || 0;
7870 * Initializes positioning on this element. If a desired position is not passed, it will make the
7871 * the element positioned relative IF it is not already positioned.
7872 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7873 * @param {Number} zIndex (optional) The zIndex to apply
7874 * @param {Number} x (optional) Set the page X position
7875 * @param {Number} y (optional) Set the page Y position
7877 position : function(pos, zIndex, x, y){
7879 if(this.getStyle('position') == 'static'){
7880 this.setStyle('position', 'relative');
7883 this.setStyle("position", pos);
7886 this.setStyle("z-index", zIndex);
7888 if(x !== undefined && y !== undefined){
7890 }else if(x !== undefined){
7892 }else if(y !== undefined){
7898 * Clear positioning back to the default when the document was loaded
7899 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7900 * @return {Roo.Element} this
7902 clearPositioning : function(value){
7910 "position" : "static"
7916 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7917 * snapshot before performing an update and then restoring the element.
7920 getPositioning : function(){
7921 var l = this.getStyle("left");
7922 var t = this.getStyle("top");
7924 "position" : this.getStyle("position"),
7926 "right" : l ? "" : this.getStyle("right"),
7928 "bottom" : t ? "" : this.getStyle("bottom"),
7929 "z-index" : this.getStyle("z-index")
7934 * Gets the width of the border(s) for the specified side(s)
7935 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7936 * passing lr would get the border (l)eft width + the border (r)ight width.
7937 * @return {Number} The width of the sides passed added together
7939 getBorderWidth : function(side){
7940 return this.addStyles(side, El.borders);
7944 * Gets the width of the padding(s) for the specified side(s)
7945 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7946 * passing lr would get the padding (l)eft + the padding (r)ight.
7947 * @return {Number} The padding of the sides passed added together
7949 getPadding : function(side){
7950 return this.addStyles(side, El.paddings);
7954 * Set positioning with an object returned by getPositioning().
7955 * @param {Object} posCfg
7956 * @return {Roo.Element} this
7958 setPositioning : function(pc){
7959 this.applyStyles(pc);
7960 if(pc.right == "auto"){
7961 this.dom.style.right = "";
7963 if(pc.bottom == "auto"){
7964 this.dom.style.bottom = "";
7970 fixDisplay : function(){
7971 if(this.getStyle("display") == "none"){
7972 this.setStyle("visibility", "hidden");
7973 this.setStyle("display", this.originalDisplay); // first try reverting to default
7974 if(this.getStyle("display") == "none"){ // if that fails, default to block
7975 this.setStyle("display", "block");
7981 * Quick set left and top adding default units
7982 * @param {String} left The left CSS property value
7983 * @param {String} top The top CSS property value
7984 * @return {Roo.Element} this
7986 setLeftTop : function(left, top){
7987 this.dom.style.left = this.addUnits(left);
7988 this.dom.style.top = this.addUnits(top);
7993 * Move this element relative to its current position.
7994 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
7995 * @param {Number} distance How far to move the element in pixels
7996 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7997 * @return {Roo.Element} this
7999 move : function(direction, distance, animate){
8000 var xy = this.getXY();
8001 direction = direction.toLowerCase();
8005 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8009 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8014 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8019 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8026 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8027 * @return {Roo.Element} this
8030 if(!this.isClipped){
8031 this.isClipped = true;
8032 this.originalClip = {
8033 "o": this.getStyle("overflow"),
8034 "x": this.getStyle("overflow-x"),
8035 "y": this.getStyle("overflow-y")
8037 this.setStyle("overflow", "hidden");
8038 this.setStyle("overflow-x", "hidden");
8039 this.setStyle("overflow-y", "hidden");
8045 * Return clipping (overflow) to original clipping before clip() was called
8046 * @return {Roo.Element} this
8048 unclip : function(){
8050 this.isClipped = false;
8051 var o = this.originalClip;
8052 if(o.o){this.setStyle("overflow", o.o);}
8053 if(o.x){this.setStyle("overflow-x", o.x);}
8054 if(o.y){this.setStyle("overflow-y", o.y);}
8061 * Gets the x,y coordinates specified by the anchor position on the element.
8062 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8063 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8064 * {width: (target width), height: (target height)} (defaults to the element's current size)
8065 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8066 * @return {Array} [x, y] An array containing the element's x and y coordinates
8068 getAnchorXY : function(anchor, local, s){
8069 //Passing a different size is useful for pre-calculating anchors,
8070 //especially for anchored animations that change the el size.
8072 var w, h, vp = false;
8075 if(d == document.body || d == document){
8077 w = D.getViewWidth(); h = D.getViewHeight();
8079 w = this.getWidth(); h = this.getHeight();
8082 w = s.width; h = s.height;
8084 var x = 0, y = 0, r = Math.round;
8085 switch((anchor || "tl").toLowerCase()){
8127 var sc = this.getScroll();
8128 return [x + sc.left, y + sc.top];
8130 //Add the element's offset xy
8131 var o = this.getXY();
8132 return [x+o[0], y+o[1]];
8136 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8137 * supported position values.
8138 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8139 * @param {String} position The position to align to.
8140 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8141 * @return {Array} [x, y]
8143 getAlignToXY : function(el, p, o){
8147 throw "Element.alignTo with an element that doesn't exist";
8149 var c = false; //constrain to viewport
8150 var p1 = "", p2 = "";
8157 }else if(p.indexOf("-") == -1){
8160 p = p.toLowerCase();
8161 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8163 throw "Element.alignTo with an invalid alignment " + p;
8165 p1 = m[1]; p2 = m[2]; c = !!m[3];
8167 //Subtract the aligned el's internal xy from the target's offset xy
8168 //plus custom offset to get the aligned el's new offset xy
8169 var a1 = this.getAnchorXY(p1, true);
8170 var a2 = el.getAnchorXY(p2, false);
8171 var x = a2[0] - a1[0] + o[0];
8172 var y = a2[1] - a1[1] + o[1];
8174 //constrain the aligned el to viewport if necessary
8175 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8176 // 5px of margin for ie
8177 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8179 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8180 //perpendicular to the vp border, allow the aligned el to slide on that border,
8181 //otherwise swap the aligned el to the opposite border of the target.
8182 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8183 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8184 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8185 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8188 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8189 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8191 if((x+w) > dw + scrollX){
8192 x = swapX ? r.left-w : dw+scrollX-w;
8195 x = swapX ? r.right : scrollX;
8197 if((y+h) > dh + scrollY){
8198 y = swapY ? r.top-h : dh+scrollY-h;
8201 y = swapY ? r.bottom : scrollY;
8208 getConstrainToXY : function(){
8209 var os = {top:0, left:0, bottom:0, right: 0};
8211 return function(el, local, offsets, proposedXY){
8213 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8215 var vw, vh, vx = 0, vy = 0;
8216 if(el.dom == document.body || el.dom == document){
8217 vw = Roo.lib.Dom.getViewWidth();
8218 vh = Roo.lib.Dom.getViewHeight();
8220 vw = el.dom.clientWidth;
8221 vh = el.dom.clientHeight;
8223 var vxy = el.getXY();
8229 var s = el.getScroll();
8231 vx += offsets.left + s.left;
8232 vy += offsets.top + s.top;
8234 vw -= offsets.right;
8235 vh -= offsets.bottom;
8240 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8241 var x = xy[0], y = xy[1];
8242 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8244 // only move it if it needs it
8247 // first validate right/bottom
8256 // then make sure top/left isn't negative
8265 return moved ? [x, y] : false;
8270 adjustForConstraints : function(xy, parent, offsets){
8271 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8275 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8276 * document it aligns it to the viewport.
8277 * The position parameter is optional, and can be specified in any one of the following formats:
8279 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8280 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8281 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8282 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8283 * <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
8284 * element's anchor point, and the second value is used as the target's anchor point.</li>
8286 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8287 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8288 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8289 * that specified in order to enforce the viewport constraints.
8290 * Following are all of the supported anchor positions:
8293 ----- -----------------------------
8294 tl The top left corner (default)
8295 t The center of the top edge
8296 tr The top right corner
8297 l The center of the left edge
8298 c In the center of the element
8299 r The center of the right edge
8300 bl The bottom left corner
8301 b The center of the bottom edge
8302 br The bottom right corner
8306 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8307 el.alignTo("other-el");
8309 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8310 el.alignTo("other-el", "tr?");
8312 // align the bottom right corner of el with the center left edge of other-el
8313 el.alignTo("other-el", "br-l?");
8315 // align the center of el with the bottom left corner of other-el and
8316 // adjust the x position by -6 pixels (and the y position by 0)
8317 el.alignTo("other-el", "c-bl", [-6, 0]);
8319 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8320 * @param {String} position The position to align to.
8321 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8322 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8323 * @return {Roo.Element} this
8325 alignTo : function(element, position, offsets, animate){
8326 var xy = this.getAlignToXY(element, position, offsets);
8327 this.setXY(xy, this.preanim(arguments, 3));
8332 * Anchors an element to another element and realigns it when the window is resized.
8333 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8334 * @param {String} position The position to align to.
8335 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8336 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8337 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8338 * is a number, it is used as the buffer delay (defaults to 50ms).
8339 * @param {Function} callback The function to call after the animation finishes
8340 * @return {Roo.Element} this
8342 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8343 var action = function(){
8344 this.alignTo(el, alignment, offsets, animate);
8345 Roo.callback(callback, this);
8347 Roo.EventManager.onWindowResize(action, this);
8348 var tm = typeof monitorScroll;
8349 if(tm != 'undefined'){
8350 Roo.EventManager.on(window, 'scroll', action, this,
8351 {buffer: tm == 'number' ? monitorScroll : 50});
8353 action.call(this); // align immediately
8357 * Clears any opacity settings from this element. Required in some cases for IE.
8358 * @return {Roo.Element} this
8360 clearOpacity : function(){
8361 if (window.ActiveXObject) {
8362 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8363 this.dom.style.filter = "";
8366 this.dom.style.opacity = "";
8367 this.dom.style["-moz-opacity"] = "";
8368 this.dom.style["-khtml-opacity"] = "";
8374 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8375 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8376 * @return {Roo.Element} this
8378 hide : function(animate){
8379 this.setVisible(false, this.preanim(arguments, 0));
8384 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8385 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8386 * @return {Roo.Element} this
8388 show : function(animate){
8389 this.setVisible(true, this.preanim(arguments, 0));
8394 * @private Test if size has a unit, otherwise appends the default
8396 addUnits : function(size){
8397 return Roo.Element.addUnits(size, this.defaultUnit);
8401 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8402 * @return {Roo.Element} this
8404 beginMeasure : function(){
8406 if(el.offsetWidth || el.offsetHeight){
8407 return this; // offsets work already
8410 var p = this.dom, b = document.body; // start with this element
8411 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8412 var pe = Roo.get(p);
8413 if(pe.getStyle('display') == 'none'){
8414 changed.push({el: p, visibility: pe.getStyle("visibility")});
8415 p.style.visibility = "hidden";
8416 p.style.display = "block";
8420 this._measureChanged = changed;
8426 * Restores displays to before beginMeasure was called
8427 * @return {Roo.Element} this
8429 endMeasure : function(){
8430 var changed = this._measureChanged;
8432 for(var i = 0, len = changed.length; i < len; i++) {
8434 r.el.style.visibility = r.visibility;
8435 r.el.style.display = "none";
8437 this._measureChanged = null;
8443 * Update the innerHTML of this element, optionally searching for and processing scripts
8444 * @param {String} html The new HTML
8445 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8446 * @param {Function} callback For async script loading you can be noticed when the update completes
8447 * @return {Roo.Element} this
8449 update : function(html, loadScripts, callback){
8450 if(typeof html == "undefined"){
8453 if(loadScripts !== true){
8454 this.dom.innerHTML = html;
8455 if(typeof callback == "function"){
8463 html += '<span id="' + id + '"></span>';
8465 E.onAvailable(id, function(){
8466 var hd = document.getElementsByTagName("head")[0];
8467 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8468 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8469 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8472 while(match = re.exec(html)){
8473 var attrs = match[1];
8474 var srcMatch = attrs ? attrs.match(srcRe) : false;
8475 if(srcMatch && srcMatch[2]){
8476 var s = document.createElement("script");
8477 s.src = srcMatch[2];
8478 var typeMatch = attrs.match(typeRe);
8479 if(typeMatch && typeMatch[2]){
8480 s.type = typeMatch[2];
8483 }else if(match[2] && match[2].length > 0){
8484 if(window.execScript) {
8485 window.execScript(match[2]);
8493 window.eval(match[2]);
8497 var el = document.getElementById(id);
8498 if(el){el.parentNode.removeChild(el);}
8499 if(typeof callback == "function"){
8503 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8508 * Direct access to the UpdateManager update() method (takes the same parameters).
8509 * @param {String/Function} url The url for this request or a function to call to get the url
8510 * @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}
8511 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8512 * @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.
8513 * @return {Roo.Element} this
8516 var um = this.getUpdateManager();
8517 um.update.apply(um, arguments);
8522 * Gets this element's UpdateManager
8523 * @return {Roo.UpdateManager} The UpdateManager
8525 getUpdateManager : function(){
8526 if(!this.updateManager){
8527 this.updateManager = new Roo.UpdateManager(this);
8529 return this.updateManager;
8533 * Disables text selection for this element (normalized across browsers)
8534 * @return {Roo.Element} this
8536 unselectable : function(){
8537 this.dom.unselectable = "on";
8538 this.swallowEvent("selectstart", true);
8539 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8540 this.addClass("x-unselectable");
8545 * Calculates the x, y to center this element on the screen
8546 * @return {Array} The x, y values [x, y]
8548 getCenterXY : function(){
8549 return this.getAlignToXY(document, 'c-c');
8553 * Centers the Element in either the viewport, or another Element.
8554 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8556 center : function(centerIn){
8557 this.alignTo(centerIn || document, 'c-c');
8562 * Tests various css rules/browsers to determine if this element uses a border box
8565 isBorderBox : function(){
8566 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8570 * Return a box {x, y, width, height} that can be used to set another elements
8571 * size/location to match this element.
8572 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8573 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8574 * @return {Object} box An object in the format {x, y, width, height}
8576 getBox : function(contentBox, local){
8581 var left = parseInt(this.getStyle("left"), 10) || 0;
8582 var top = parseInt(this.getStyle("top"), 10) || 0;
8585 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8587 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8589 var l = this.getBorderWidth("l")+this.getPadding("l");
8590 var r = this.getBorderWidth("r")+this.getPadding("r");
8591 var t = this.getBorderWidth("t")+this.getPadding("t");
8592 var b = this.getBorderWidth("b")+this.getPadding("b");
8593 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)};
8595 bx.right = bx.x + bx.width;
8596 bx.bottom = bx.y + bx.height;
8601 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8602 for more information about the sides.
8603 * @param {String} sides
8606 getFrameWidth : function(sides, onlyContentBox){
8607 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8611 * 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.
8612 * @param {Object} box The box to fill {x, y, width, height}
8613 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8614 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8615 * @return {Roo.Element} this
8617 setBox : function(box, adjust, animate){
8618 var w = box.width, h = box.height;
8619 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8620 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8621 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8623 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8628 * Forces the browser to repaint this element
8629 * @return {Roo.Element} this
8631 repaint : function(){
8633 this.addClass("x-repaint");
8634 setTimeout(function(){
8635 Roo.get(dom).removeClass("x-repaint");
8641 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8642 * then it returns the calculated width of the sides (see getPadding)
8643 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8644 * @return {Object/Number}
8646 getMargins : function(side){
8649 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8650 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8651 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8652 right: parseInt(this.getStyle("margin-right"), 10) || 0
8655 return this.addStyles(side, El.margins);
8660 addStyles : function(sides, styles){
8662 for(var i = 0, len = sides.length; i < len; i++){
8663 v = this.getStyle(styles[sides.charAt(i)]);
8665 w = parseInt(v, 10);
8673 * Creates a proxy element of this element
8674 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8675 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8676 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8677 * @return {Roo.Element} The new proxy element
8679 createProxy : function(config, renderTo, matchBox){
8681 renderTo = Roo.getDom(renderTo);
8683 renderTo = document.body;
8685 config = typeof config == "object" ?
8686 config : {tag : "div", cls: config};
8687 var proxy = Roo.DomHelper.append(renderTo, config, true);
8689 proxy.setBox(this.getBox());
8695 * Puts a mask over this element to disable user interaction. Requires core.css.
8696 * This method can only be applied to elements which accept child nodes.
8697 * @param {String} msg (optional) A message to display in the mask
8698 * @param {String} msgCls (optional) A css class to apply to the msg element
8699 * @return {Element} The mask element
8701 mask : function(msg, msgCls){
8702 if(this.getStyle("position") == "static"){
8703 this.setStyle("position", "relative");
8706 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8708 this.addClass("x-masked");
8709 this._mask.setDisplayed(true);
8710 if(typeof msg == 'string'){
8712 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8714 var mm = this._maskMsg;
8715 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8716 mm.dom.firstChild.innerHTML = msg;
8717 mm.setDisplayed(true);
8720 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8721 this._mask.setHeight(this.getHeight());
8727 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8728 * it is cached for reuse.
8730 unmask : function(removeEl){
8732 if(removeEl === true){
8733 this._mask.remove();
8736 this._maskMsg.remove();
8737 delete this._maskMsg;
8740 this._mask.setDisplayed(false);
8742 this._maskMsg.setDisplayed(false);
8746 this.removeClass("x-masked");
8750 * Returns true if this element is masked
8753 isMasked : function(){
8754 return this._mask && this._mask.isVisible();
8758 * Creates an iframe shim for this element to keep selects and other windowed objects from
8760 * @return {Roo.Element} The new shim element
8762 createShim : function(){
8763 var el = document.createElement('iframe');
8764 el.frameBorder = 'no';
8765 el.className = 'roo-shim';
8766 if(Roo.isIE && Roo.isSecure){
8767 el.src = Roo.SSL_SECURE_URL;
8769 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8770 shim.autoBoxAdjust = false;
8775 * Removes this element from the DOM and deletes it from the cache
8777 remove : function(){
8778 if(this.dom.parentNode){
8779 this.dom.parentNode.removeChild(this.dom);
8781 delete El.cache[this.dom.id];
8785 * Sets up event handlers to add and remove a css class when the mouse is over this element
8786 * @param {String} className
8787 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8788 * mouseout events for children elements
8789 * @return {Roo.Element} this
8791 addClassOnOver : function(className, preventFlicker){
8792 this.on("mouseover", function(){
8793 Roo.fly(this, '_internal').addClass(className);
8795 var removeFn = function(e){
8796 if(preventFlicker !== true || !e.within(this, true)){
8797 Roo.fly(this, '_internal').removeClass(className);
8800 this.on("mouseout", removeFn, this.dom);
8805 * Sets up event handlers to add and remove a css class when this element has the focus
8806 * @param {String} className
8807 * @return {Roo.Element} this
8809 addClassOnFocus : function(className){
8810 this.on("focus", function(){
8811 Roo.fly(this, '_internal').addClass(className);
8813 this.on("blur", function(){
8814 Roo.fly(this, '_internal').removeClass(className);
8819 * 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)
8820 * @param {String} className
8821 * @return {Roo.Element} this
8823 addClassOnClick : function(className){
8825 this.on("mousedown", function(){
8826 Roo.fly(dom, '_internal').addClass(className);
8827 var d = Roo.get(document);
8828 var fn = function(){
8829 Roo.fly(dom, '_internal').removeClass(className);
8830 d.removeListener("mouseup", fn);
8832 d.on("mouseup", fn);
8838 * Stops the specified event from bubbling and optionally prevents the default action
8839 * @param {String} eventName
8840 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8841 * @return {Roo.Element} this
8843 swallowEvent : function(eventName, preventDefault){
8844 var fn = function(e){
8845 e.stopPropagation();
8850 if(eventName instanceof Array){
8851 for(var i = 0, len = eventName.length; i < len; i++){
8852 this.on(eventName[i], fn);
8856 this.on(eventName, fn);
8863 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8866 * Sizes this element to its parent element's dimensions performing
8867 * neccessary box adjustments.
8868 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8869 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8870 * @return {Roo.Element} this
8872 fitToParent : function(monitorResize, targetParent) {
8873 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8874 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8875 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8878 var p = Roo.get(targetParent || this.dom.parentNode);
8879 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8880 if (monitorResize === true) {
8881 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8882 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8888 * Gets the next sibling, skipping text nodes
8889 * @return {HTMLElement} The next sibling or null
8891 getNextSibling : function(){
8892 var n = this.dom.nextSibling;
8893 while(n && n.nodeType != 1){
8900 * Gets the previous sibling, skipping text nodes
8901 * @return {HTMLElement} The previous sibling or null
8903 getPrevSibling : function(){
8904 var n = this.dom.previousSibling;
8905 while(n && n.nodeType != 1){
8906 n = n.previousSibling;
8913 * Appends the passed element(s) to this element
8914 * @param {String/HTMLElement/Array/Element/CompositeElement} el
8915 * @return {Roo.Element} this
8917 appendChild: function(el){
8924 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8925 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
8926 * automatically generated with the specified attributes.
8927 * @param {HTMLElement} insertBefore (optional) a child element of this element
8928 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8929 * @return {Roo.Element} The new child element
8931 createChild: function(config, insertBefore, returnDom){
8932 config = config || {tag:'div'};
8934 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8936 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
8940 * Appends this element to the passed element
8941 * @param {String/HTMLElement/Element} el The new parent element
8942 * @return {Roo.Element} this
8944 appendTo: function(el){
8945 el = Roo.getDom(el);
8946 el.appendChild(this.dom);
8951 * Inserts this element before the passed element in the DOM
8952 * @param {String/HTMLElement/Element} el The element to insert before
8953 * @return {Roo.Element} this
8955 insertBefore: function(el){
8956 el = Roo.getDom(el);
8957 el.parentNode.insertBefore(this.dom, el);
8962 * Inserts this element after the passed element in the DOM
8963 * @param {String/HTMLElement/Element} el The element to insert after
8964 * @return {Roo.Element} this
8966 insertAfter: function(el){
8967 el = Roo.getDom(el);
8968 el.parentNode.insertBefore(this.dom, el.nextSibling);
8973 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8974 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8975 * @return {Roo.Element} The new child
8977 insertFirst: function(el, returnDom){
8979 if(typeof el == 'object' && !el.nodeType){ // dh config
8980 return this.createChild(el, this.dom.firstChild, returnDom);
8982 el = Roo.getDom(el);
8983 this.dom.insertBefore(el, this.dom.firstChild);
8984 return !returnDom ? Roo.get(el) : el;
8989 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
8990 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8991 * @param {String} where (optional) 'before' or 'after' defaults to before
8992 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8993 * @return {Roo.Element} the inserted Element
8995 insertSibling: function(el, where, returnDom){
8996 where = where ? where.toLowerCase() : 'before';
8998 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9000 if(typeof el == 'object' && !el.nodeType){ // dh config
9001 if(where == 'after' && !this.dom.nextSibling){
9002 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9004 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9008 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9009 where == 'before' ? this.dom : this.dom.nextSibling);
9018 * Creates and wraps this element with another element
9019 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9020 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9021 * @return {HTMLElement/Element} The newly created wrapper element
9023 wrap: function(config, returnDom){
9025 config = {tag: "div"};
9027 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9028 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9033 * Replaces the passed element with this element
9034 * @param {String/HTMLElement/Element} el The element to replace
9035 * @return {Roo.Element} this
9037 replace: function(el){
9039 this.insertBefore(el);
9045 * Inserts an html fragment into this element
9046 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9047 * @param {String} html The HTML fragment
9048 * @param {Boolean} returnEl True to return an Roo.Element
9049 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9051 insertHtml : function(where, html, returnEl){
9052 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9053 return returnEl ? Roo.get(el) : el;
9057 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9058 * @param {Object} o The object with the attributes
9059 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9060 * @return {Roo.Element} this
9062 set : function(o, useSet){
9064 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9066 if(attr == "style" || typeof o[attr] == "function") continue;
9068 el.className = o["cls"];
9070 if(useSet) el.setAttribute(attr, o[attr]);
9071 else el[attr] = o[attr];
9075 Roo.DomHelper.applyStyles(el, o.style);
9081 * Convenience method for constructing a KeyMap
9082 * @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:
9083 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9084 * @param {Function} fn The function to call
9085 * @param {Object} scope (optional) The scope of the function
9086 * @return {Roo.KeyMap} The KeyMap created
9088 addKeyListener : function(key, fn, scope){
9090 if(typeof key != "object" || key instanceof Array){
9106 return new Roo.KeyMap(this, config);
9110 * Creates a KeyMap for this element
9111 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9112 * @return {Roo.KeyMap} The KeyMap created
9114 addKeyMap : function(config){
9115 return new Roo.KeyMap(this, config);
9119 * Returns true if this element is scrollable.
9122 isScrollable : function(){
9124 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9128 * 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().
9129 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9130 * @param {Number} value The new scroll value
9131 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9132 * @return {Element} this
9135 scrollTo : function(side, value, animate){
9136 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9138 this.dom[prop] = value;
9140 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9141 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9147 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9148 * within this element's scrollable range.
9149 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9150 * @param {Number} distance How far to scroll the element in pixels
9151 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9152 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9153 * was scrolled as far as it could go.
9155 scroll : function(direction, distance, animate){
9156 if(!this.isScrollable()){
9160 var l = el.scrollLeft, t = el.scrollTop;
9161 var w = el.scrollWidth, h = el.scrollHeight;
9162 var cw = el.clientWidth, ch = el.clientHeight;
9163 direction = direction.toLowerCase();
9164 var scrolled = false;
9165 var a = this.preanim(arguments, 2);
9170 var v = Math.min(l + distance, w-cw);
9171 this.scrollTo("left", v, a);
9178 var v = Math.max(l - distance, 0);
9179 this.scrollTo("left", v, a);
9187 var v = Math.max(t - distance, 0);
9188 this.scrollTo("top", v, a);
9196 var v = Math.min(t + distance, h-ch);
9197 this.scrollTo("top", v, a);
9206 * Translates the passed page coordinates into left/top css values for this element
9207 * @param {Number/Array} x The page x or an array containing [x, y]
9208 * @param {Number} y The page y
9209 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9211 translatePoints : function(x, y){
9212 if(typeof x == 'object' || x instanceof Array){
9215 var p = this.getStyle('position');
9216 var o = this.getXY();
9218 var l = parseInt(this.getStyle('left'), 10);
9219 var t = parseInt(this.getStyle('top'), 10);
9222 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9225 t = (p == "relative") ? 0 : this.dom.offsetTop;
9228 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9232 * Returns the current scroll position of the element.
9233 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9235 getScroll : function(){
9236 var d = this.dom, doc = document;
9237 if(d == doc || d == doc.body){
9238 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9239 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9240 return {left: l, top: t};
9242 return {left: d.scrollLeft, top: d.scrollTop};
9247 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9248 * are convert to standard 6 digit hex color.
9249 * @param {String} attr The css attribute
9250 * @param {String} defaultValue The default value to use when a valid color isn't found
9251 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9254 getColor : function(attr, defaultValue, prefix){
9255 var v = this.getStyle(attr);
9256 if(!v || v == "transparent" || v == "inherit") {
9257 return defaultValue;
9259 var color = typeof prefix == "undefined" ? "#" : prefix;
9260 if(v.substr(0, 4) == "rgb("){
9261 var rvs = v.slice(4, v.length -1).split(",");
9262 for(var i = 0; i < 3; i++){
9263 var h = parseInt(rvs[i]).toString(16);
9270 if(v.substr(0, 1) == "#"){
9272 for(var i = 1; i < 4; i++){
9273 var c = v.charAt(i);
9276 }else if(v.length == 7){
9277 color += v.substr(1);
9281 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9285 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9286 * gradient background, rounded corners and a 4-way shadow.
9287 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9288 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9289 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9290 * @return {Roo.Element} this
9292 boxWrap : function(cls){
9293 cls = cls || 'x-box';
9294 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9295 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9300 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9301 * @param {String} namespace The namespace in which to look for the attribute
9302 * @param {String} name The attribute name
9303 * @return {String} The attribute value
9305 getAttributeNS : Roo.isIE ? function(ns, name){
9307 var type = typeof d[ns+":"+name];
9308 if(type != 'undefined' && type != 'unknown'){
9309 return d[ns+":"+name];
9312 } : function(ns, name){
9314 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9318 var ep = El.prototype;
9321 * Appends an event handler (Shorthand for addListener)
9322 * @param {String} eventName The type of event to append
9323 * @param {Function} fn The method the event invokes
9324 * @param {Object} scope (optional) The scope (this object) of the fn
9325 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9328 ep.on = ep.addListener;
9330 ep.mon = ep.addListener;
9333 * Removes an event handler from this element (shorthand for removeListener)
9334 * @param {String} eventName the type of event to remove
9335 * @param {Function} fn the method the event invokes
9336 * @return {Roo.Element} this
9339 ep.un = ep.removeListener;
9342 * true to automatically adjust width and height settings for box-model issues (default to true)
9344 ep.autoBoxAdjust = true;
9347 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9350 El.addUnits = function(v, defaultUnit){
9351 if(v === "" || v == "auto"){
9354 if(v === undefined){
9357 if(typeof v == "number" || !El.unitPattern.test(v)){
9358 return v + (defaultUnit || 'px');
9363 // special markup used throughout Roo when box wrapping elements
9364 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>';
9366 * Visibility mode constant - Use visibility to hide element
9372 * Visibility mode constant - Use display to hide element
9378 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9379 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9380 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9392 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9393 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9394 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9395 * @return {Element} The Element object
9398 El.get = function(el){
9400 if(!el){ return null; }
9401 if(typeof el == "string"){ // element id
9402 if(!(elm = document.getElementById(el))){
9405 if(ex = El.cache[el]){
9408 ex = El.cache[el] = new El(elm);
9411 }else if(el.tagName){ // dom element
9415 if(ex = El.cache[id]){
9418 ex = El.cache[id] = new El(el);
9421 }else if(el instanceof El){
9423 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9424 // catch case where it hasn't been appended
9425 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9428 }else if(el.isComposite){
9430 }else if(el instanceof Array){
9431 return El.select(el);
9432 }else if(el == document){
9433 // create a bogus element object representing the document object
9435 var f = function(){};
9436 f.prototype = El.prototype;
9438 docEl.dom = document;
9446 El.uncache = function(el){
9447 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9449 delete El.cache[a[i].id || a[i]];
9455 // Garbage collection - uncache elements/purge listeners on orphaned elements
9456 // so we don't hold a reference and cause the browser to retain them
9457 El.garbageCollect = function(){
9458 if(!Roo.enableGarbageCollector){
9459 clearInterval(El.collectorThread);
9462 for(var eid in El.cache){
9463 var el = El.cache[eid], d = el.dom;
9464 // -------------------------------------------------------
9465 // Determining what is garbage:
9466 // -------------------------------------------------------
9468 // dom node is null, definitely garbage
9469 // -------------------------------------------------------
9471 // no parentNode == direct orphan, definitely garbage
9472 // -------------------------------------------------------
9473 // !d.offsetParent && !document.getElementById(eid)
9474 // display none elements have no offsetParent so we will
9475 // also try to look it up by it's id. However, check
9476 // offsetParent first so we don't do unneeded lookups.
9477 // This enables collection of elements that are not orphans
9478 // directly, but somewhere up the line they have an orphan
9480 // -------------------------------------------------------
9481 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9482 delete El.cache[eid];
9483 if(d && Roo.enableListenerCollection){
9489 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9493 El.Flyweight = function(dom){
9496 El.Flyweight.prototype = El.prototype;
9498 El._flyweights = {};
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 * @param {String/HTMLElement} el The dom node or id
9503 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9504 * prevent conflicts (e.g. internally Roo uses "_internal")
9506 * @return {Element} The shared Element object
9508 El.fly = function(el, named){
9509 named = named || '_global';
9510 el = Roo.getDom(el);
9514 if(!El._flyweights[named]){
9515 El._flyweights[named] = new El.Flyweight();
9517 El._flyweights[named].dom = el;
9518 return El._flyweights[named];
9522 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9523 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9524 * Shorthand of {@link Roo.Element#get}
9525 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9526 * @return {Element} The Element object
9532 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9533 * the dom node can be overwritten by other code.
9534 * Shorthand of {@link Roo.Element#fly}
9535 * @param {String/HTMLElement} el The dom node or id
9536 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9537 * prevent conflicts (e.g. internally Roo uses "_internal")
9539 * @return {Element} The shared Element object
9545 // speedy lookup for elements never to box adjust
9546 var noBoxAdjust = Roo.isStrict ? {
9549 input:1, select:1, textarea:1
9551 if(Roo.isIE || Roo.isGecko){
9552 noBoxAdjust['button'] = 1;
9556 Roo.EventManager.on(window, 'unload', function(){
9558 delete El._flyweights;
9566 Roo.Element.selectorFunction = Roo.DomQuery.select;
9569 Roo.Element.select = function(selector, unique, root){
9571 if(typeof selector == "string"){
9572 els = Roo.Element.selectorFunction(selector, root);
9573 }else if(selector.length !== undefined){
9576 throw "Invalid selector";
9578 if(unique === true){
9579 return new Roo.CompositeElement(els);
9581 return new Roo.CompositeElementLite(els);
9585 * Selects elements based on the passed CSS selector to enable working on them as 1.
9586 * @param {String/Array} selector The CSS selector or an array of elements
9587 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9588 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9589 * @return {CompositeElementLite/CompositeElement}
9593 Roo.select = Roo.Element.select;
9610 * Ext JS Library 1.1.1
9611 * Copyright(c) 2006-2007, Ext JS, LLC.
9613 * Originally Released Under LGPL - original licence link has changed is not relivant.
9616 * <script type="text/javascript">
9621 //Notifies Element that fx methods are available
9622 Roo.enableFx = true;
9626 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9627 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9628 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9629 * Element effects to work.</p><br/>
9631 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9632 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9633 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9634 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9635 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9636 * expected results and should be done with care.</p><br/>
9638 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9639 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9642 ----- -----------------------------
9643 tl The top left corner
9644 t The center of the top edge
9645 tr The top right corner
9646 l The center of the left edge
9647 r The center of the right edge
9648 bl The bottom left corner
9649 b The center of the bottom edge
9650 br The bottom right corner
9652 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9653 * below are common options that can be passed to any Fx method.</b>
9654 * @cfg {Function} callback A function called when the effect is finished
9655 * @cfg {Object} scope The scope of the effect function
9656 * @cfg {String} easing A valid Easing value for the effect
9657 * @cfg {String} afterCls A css class to apply after the effect
9658 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9659 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9660 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9661 * effects that end with the element being visually hidden, ignored otherwise)
9662 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9663 * a function which returns such a specification that will be applied to the Element after the effect finishes
9664 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9665 * @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
9666 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9670 * Slides the element into view. An anchor point can be optionally passed to set the point of
9671 * origin for the slide effect. This function automatically handles wrapping the element with
9672 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9675 // default: slide the element in from the top
9678 // custom: slide the element in from the right with a 2-second duration
9679 el.slideIn('r', { duration: 2 });
9681 // common config options shown with default values
9687 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9688 * @param {Object} options (optional) Object literal with any of the Fx config options
9689 * @return {Roo.Element} The Element
9691 slideIn : function(anchor, o){
9692 var el = this.getFxEl();
9695 el.queueFx(o, function(){
9697 anchor = anchor || "t";
9699 // fix display to visibility
9702 // restore values after effect
9703 var r = this.getFxRestore();
9704 var b = this.getBox();
9705 // fixed size for slide
9709 var wrap = this.fxWrap(r.pos, o, "hidden");
9711 var st = this.dom.style;
9712 st.visibility = "visible";
9713 st.position = "absolute";
9715 // clear out temp styles after slide and unwrap
9716 var after = function(){
9717 el.fxUnwrap(wrap, r.pos, o);
9719 st.height = r.height;
9722 // time to calc the positions
9723 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9725 switch(anchor.toLowerCase()){
9727 wrap.setSize(b.width, 0);
9728 st.left = st.bottom = "0";
9732 wrap.setSize(0, b.height);
9733 st.right = st.top = "0";
9737 wrap.setSize(0, b.height);
9739 st.left = st.top = "0";
9740 a = {width: bw, points: pt};
9743 wrap.setSize(b.width, 0);
9744 wrap.setY(b.bottom);
9745 st.left = st.top = "0";
9746 a = {height: bh, points: pt};
9750 st.right = st.bottom = "0";
9751 a = {width: bw, height: bh};
9755 wrap.setY(b.y+b.height);
9756 st.right = st.top = "0";
9757 a = {width: bw, height: bh, points: pt};
9761 wrap.setXY([b.right, b.bottom]);
9762 st.left = st.top = "0";
9763 a = {width: bw, height: bh, points: pt};
9767 wrap.setX(b.x+b.width);
9768 st.left = st.bottom = "0";
9769 a = {width: bw, height: bh, points: pt};
9772 this.dom.style.visibility = "visible";
9775 arguments.callee.anim = wrap.fxanim(a,
9785 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9786 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9787 * 'hidden') but block elements will still take up space in the document. The element must be removed
9788 * from the DOM using the 'remove' config option if desired. This function automatically handles
9789 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9792 // default: slide the element out to the top
9795 // custom: slide the element out to the right with a 2-second duration
9796 el.slideOut('r', { duration: 2 });
9798 // common config options shown with default values
9806 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9807 * @param {Object} options (optional) Object literal with any of the Fx config options
9808 * @return {Roo.Element} The Element
9810 slideOut : function(anchor, o){
9811 var el = this.getFxEl();
9814 el.queueFx(o, function(){
9816 anchor = anchor || "t";
9818 // restore values after effect
9819 var r = this.getFxRestore();
9821 var b = this.getBox();
9822 // fixed size for slide
9826 var wrap = this.fxWrap(r.pos, o, "visible");
9828 var st = this.dom.style;
9829 st.visibility = "visible";
9830 st.position = "absolute";
9834 var after = function(){
9836 el.setDisplayed(false);
9841 el.fxUnwrap(wrap, r.pos, o);
9844 st.height = r.height;
9849 var a, zero = {to: 0};
9850 switch(anchor.toLowerCase()){
9852 st.left = st.bottom = "0";
9856 st.right = st.top = "0";
9860 st.left = st.top = "0";
9861 a = {width: zero, points: {to:[b.right, b.y]}};
9864 st.left = st.top = "0";
9865 a = {height: zero, points: {to:[b.x, b.bottom]}};
9868 st.right = st.bottom = "0";
9869 a = {width: zero, height: zero};
9872 st.right = st.top = "0";
9873 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9876 st.left = st.top = "0";
9877 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9880 st.left = st.bottom = "0";
9881 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9885 arguments.callee.anim = wrap.fxanim(a,
9895 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
9896 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
9897 * The element must be removed from the DOM using the 'remove' config option if desired.
9903 // common config options shown with default values
9911 * @param {Object} options (optional) Object literal with any of the Fx config options
9912 * @return {Roo.Element} The Element
9915 var el = this.getFxEl();
9918 el.queueFx(o, function(){
9919 this.clearOpacity();
9922 // restore values after effect
9923 var r = this.getFxRestore();
9924 var st = this.dom.style;
9926 var after = function(){
9928 el.setDisplayed(false);
9935 el.setPositioning(r.pos);
9937 st.height = r.height;
9942 var width = this.getWidth();
9943 var height = this.getHeight();
9945 arguments.callee.anim = this.fxanim({
9946 width : {to: this.adjustWidth(width * 2)},
9947 height : {to: this.adjustHeight(height * 2)},
9948 points : {by: [-(width * .5), -(height * .5)]},
9950 fontSize: {to:200, unit: "%"}
9961 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9962 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
9963 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9969 // all config options shown with default values
9977 * @param {Object} options (optional) Object literal with any of the Fx config options
9978 * @return {Roo.Element} The Element
9980 switchOff : function(o){
9981 var el = this.getFxEl();
9984 el.queueFx(o, function(){
9985 this.clearOpacity();
9988 // restore values after effect
9989 var r = this.getFxRestore();
9990 var st = this.dom.style;
9992 var after = function(){
9994 el.setDisplayed(false);
10000 el.setPositioning(r.pos);
10001 st.width = r.width;
10002 st.height = r.height;
10007 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10008 this.clearOpacity();
10012 points:{by:[0, this.getHeight() * .5]}
10013 }, o, 'motion', 0.3, 'easeIn', after);
10014 }).defer(100, this);
10021 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10022 * changed using the "attr" config option) and then fading back to the original color. If no original
10023 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10026 // default: highlight background to yellow
10029 // custom: highlight foreground text to blue for 2 seconds
10030 el.highlight("0000ff", { attr: 'color', duration: 2 });
10032 // common config options shown with default values
10033 el.highlight("ffff9c", {
10034 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10035 endColor: (current color) or "ffffff",
10040 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10041 * @param {Object} options (optional) Object literal with any of the Fx config options
10042 * @return {Roo.Element} The Element
10044 highlight : function(color, o){
10045 var el = this.getFxEl();
10048 el.queueFx(o, function(){
10049 color = color || "ffff9c";
10050 attr = o.attr || "backgroundColor";
10052 this.clearOpacity();
10055 var origColor = this.getColor(attr);
10056 var restoreColor = this.dom.style[attr];
10057 endColor = (o.endColor || origColor) || "ffffff";
10059 var after = function(){
10060 el.dom.style[attr] = restoreColor;
10065 a[attr] = {from: color, to: endColor};
10066 arguments.callee.anim = this.fxanim(a,
10076 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10079 // default: a single light blue ripple
10082 // custom: 3 red ripples lasting 3 seconds total
10083 el.frame("ff0000", 3, { duration: 3 });
10085 // common config options shown with default values
10086 el.frame("C3DAF9", 1, {
10087 duration: 1 //duration of entire animation (not each individual ripple)
10088 // Note: Easing is not configurable and will be ignored if included
10091 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10092 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10093 * @param {Object} options (optional) Object literal with any of the Fx config options
10094 * @return {Roo.Element} The Element
10096 frame : function(color, count, o){
10097 var el = this.getFxEl();
10100 el.queueFx(o, function(){
10101 color = color || "#C3DAF9";
10102 if(color.length == 6){
10103 color = "#" + color;
10105 count = count || 1;
10106 duration = o.duration || 1;
10109 var b = this.getBox();
10110 var animFn = function(){
10111 var proxy = this.createProxy({
10114 visbility:"hidden",
10115 position:"absolute",
10116 "z-index":"35000", // yee haw
10117 border:"0px solid " + color
10120 var scale = Roo.isBorderBox ? 2 : 1;
10122 top:{from:b.y, to:b.y - 20},
10123 left:{from:b.x, to:b.x - 20},
10124 borderWidth:{from:0, to:10},
10125 opacity:{from:1, to:0},
10126 height:{from:b.height, to:(b.height + (20*scale))},
10127 width:{from:b.width, to:(b.width + (20*scale))}
10128 }, duration, function(){
10132 animFn.defer((duration/2)*1000, this);
10143 * Creates a pause before any subsequent queued effects begin. If there are
10144 * no effects queued after the pause it will have no effect.
10149 * @param {Number} seconds The length of time to pause (in seconds)
10150 * @return {Roo.Element} The Element
10152 pause : function(seconds){
10153 var el = this.getFxEl();
10156 el.queueFx(o, function(){
10157 setTimeout(function(){
10159 }, seconds * 1000);
10165 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10166 * using the "endOpacity" config option.
10169 // default: fade in from opacity 0 to 100%
10172 // custom: fade in from opacity 0 to 75% over 2 seconds
10173 el.fadeIn({ endOpacity: .75, duration: 2});
10175 // common config options shown with default values
10177 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10182 * @param {Object} options (optional) Object literal with any of the Fx config options
10183 * @return {Roo.Element} The Element
10185 fadeIn : function(o){
10186 var el = this.getFxEl();
10188 el.queueFx(o, function(){
10189 this.setOpacity(0);
10191 this.dom.style.visibility = 'visible';
10192 var to = o.endOpacity || 1;
10193 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10194 o, null, .5, "easeOut", function(){
10196 this.clearOpacity();
10205 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10206 * using the "endOpacity" config option.
10209 // default: fade out from the element's current opacity to 0
10212 // custom: fade out from the element's current opacity to 25% over 2 seconds
10213 el.fadeOut({ endOpacity: .25, duration: 2});
10215 // common config options shown with default values
10217 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10224 * @param {Object} options (optional) Object literal with any of the Fx config options
10225 * @return {Roo.Element} The Element
10227 fadeOut : function(o){
10228 var el = this.getFxEl();
10230 el.queueFx(o, function(){
10231 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10232 o, null, .5, "easeOut", function(){
10233 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10234 this.dom.style.display = "none";
10236 this.dom.style.visibility = "hidden";
10238 this.clearOpacity();
10246 * Animates the transition of an element's dimensions from a starting height/width
10247 * to an ending height/width.
10250 // change height and width to 100x100 pixels
10251 el.scale(100, 100);
10253 // common config options shown with default values. The height and width will default to
10254 // the element's existing values if passed as null.
10257 [element's height], {
10262 * @param {Number} width The new width (pass undefined to keep the original width)
10263 * @param {Number} height The new height (pass undefined to keep the original height)
10264 * @param {Object} options (optional) Object literal with any of the Fx config options
10265 * @return {Roo.Element} The Element
10267 scale : function(w, h, o){
10268 this.shift(Roo.apply({}, o, {
10276 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10277 * Any of these properties not specified in the config object will not be changed. This effect
10278 * requires that at least one new dimension, position or opacity setting must be passed in on
10279 * the config object in order for the function to have any effect.
10282 // slide the element horizontally to x position 200 while changing the height and opacity
10283 el.shift({ x: 200, height: 50, opacity: .8 });
10285 // common config options shown with default values.
10287 width: [element's width],
10288 height: [element's height],
10289 x: [element's x position],
10290 y: [element's y position],
10291 opacity: [element's opacity],
10296 * @param {Object} options Object literal with any of the Fx config options
10297 * @return {Roo.Element} The Element
10299 shift : function(o){
10300 var el = this.getFxEl();
10302 el.queueFx(o, function(){
10303 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10304 if(w !== undefined){
10305 a.width = {to: this.adjustWidth(w)};
10307 if(h !== undefined){
10308 a.height = {to: this.adjustHeight(h)};
10310 if(x !== undefined || y !== undefined){
10312 x !== undefined ? x : this.getX(),
10313 y !== undefined ? y : this.getY()
10316 if(op !== undefined){
10317 a.opacity = {to: op};
10319 if(o.xy !== undefined){
10320 a.points = {to: o.xy};
10322 arguments.callee.anim = this.fxanim(a,
10323 o, 'motion', .35, "easeOut", function(){
10331 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10332 * ending point of the effect.
10335 // default: slide the element downward while fading out
10338 // custom: slide the element out to the right with a 2-second duration
10339 el.ghost('r', { duration: 2 });
10341 // common config options shown with default values
10349 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10350 * @param {Object} options (optional) Object literal with any of the Fx config options
10351 * @return {Roo.Element} The Element
10353 ghost : function(anchor, o){
10354 var el = this.getFxEl();
10357 el.queueFx(o, function(){
10358 anchor = anchor || "b";
10360 // restore values after effect
10361 var r = this.getFxRestore();
10362 var w = this.getWidth(),
10363 h = this.getHeight();
10365 var st = this.dom.style;
10367 var after = function(){
10369 el.setDisplayed(false);
10375 el.setPositioning(r.pos);
10376 st.width = r.width;
10377 st.height = r.height;
10382 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10383 switch(anchor.toLowerCase()){
10410 arguments.callee.anim = this.fxanim(a,
10420 * Ensures that all effects queued after syncFx is called on the element are
10421 * run concurrently. This is the opposite of {@link #sequenceFx}.
10422 * @return {Roo.Element} The Element
10424 syncFx : function(){
10425 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10434 * Ensures that all effects queued after sequenceFx is called on the element are
10435 * run in sequence. This is the opposite of {@link #syncFx}.
10436 * @return {Roo.Element} The Element
10438 sequenceFx : function(){
10439 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10441 concurrent : false,
10448 nextFx : function(){
10449 var ef = this.fxQueue[0];
10456 * Returns true if the element has any effects actively running or queued, else returns false.
10457 * @return {Boolean} True if element has active effects, else false
10459 hasActiveFx : function(){
10460 return this.fxQueue && this.fxQueue[0];
10464 * Stops any running effects and clears the element's internal effects queue if it contains
10465 * any additional effects that haven't started yet.
10466 * @return {Roo.Element} The Element
10468 stopFx : function(){
10469 if(this.hasActiveFx()){
10470 var cur = this.fxQueue[0];
10471 if(cur && cur.anim && cur.anim.isAnimated()){
10472 this.fxQueue = [cur]; // clear out others
10473 cur.anim.stop(true);
10480 beforeFx : function(o){
10481 if(this.hasActiveFx() && !o.concurrent){
10492 * Returns true if the element is currently blocking so that no other effect can be queued
10493 * until this effect is finished, else returns false if blocking is not set. This is commonly
10494 * used to ensure that an effect initiated by a user action runs to completion prior to the
10495 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10496 * @return {Boolean} True if blocking, else false
10498 hasFxBlock : function(){
10499 var q = this.fxQueue;
10500 return q && q[0] && q[0].block;
10504 queueFx : function(o, fn){
10508 if(!this.hasFxBlock()){
10509 Roo.applyIf(o, this.fxDefaults);
10511 var run = this.beforeFx(o);
10512 fn.block = o.block;
10513 this.fxQueue.push(fn);
10525 fxWrap : function(pos, o, vis){
10527 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10530 wrapXY = this.getXY();
10532 var div = document.createElement("div");
10533 div.style.visibility = vis;
10534 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10535 wrap.setPositioning(pos);
10536 if(wrap.getStyle("position") == "static"){
10537 wrap.position("relative");
10539 this.clearPositioning('auto');
10541 wrap.dom.appendChild(this.dom);
10543 wrap.setXY(wrapXY);
10550 fxUnwrap : function(wrap, pos, o){
10551 this.clearPositioning();
10552 this.setPositioning(pos);
10554 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10560 getFxRestore : function(){
10561 var st = this.dom.style;
10562 return {pos: this.getPositioning(), width: st.width, height : st.height};
10566 afterFx : function(o){
10568 this.applyStyles(o.afterStyle);
10571 this.addClass(o.afterCls);
10573 if(o.remove === true){
10576 Roo.callback(o.callback, o.scope, [this]);
10578 this.fxQueue.shift();
10584 getFxEl : function(){ // support for composite element fx
10585 return Roo.get(this.dom);
10589 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10590 animType = animType || 'run';
10592 var anim = Roo.lib.Anim[animType](
10594 (opt.duration || defaultDur) || .35,
10595 (opt.easing || defaultEase) || 'easeOut',
10597 Roo.callback(cb, this);
10606 // backwords compat
10607 Roo.Fx.resize = Roo.Fx.scale;
10609 //When included, Roo.Fx is automatically applied to Element so that all basic
10610 //effects are available directly via the Element API
10611 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10613 * Ext JS Library 1.1.1
10614 * Copyright(c) 2006-2007, Ext JS, LLC.
10616 * Originally Released Under LGPL - original licence link has changed is not relivant.
10619 * <script type="text/javascript">
10624 * @class Roo.CompositeElement
10625 * Standard composite class. Creates a Roo.Element for every element in the collection.
10627 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10628 * actions will be performed on all the elements in this collection.</b>
10630 * All methods return <i>this</i> and can be chained.
10632 var els = Roo.select("#some-el div.some-class", true);
10633 // or select directly from an existing element
10634 var el = Roo.get('some-el');
10635 el.select('div.some-class', true);
10637 els.setWidth(100); // all elements become 100 width
10638 els.hide(true); // all elements fade out and hide
10640 els.setWidth(100).hide(true);
10643 Roo.CompositeElement = function(els){
10644 this.elements = [];
10645 this.addElements(els);
10647 Roo.CompositeElement.prototype = {
10649 addElements : function(els){
10650 if(!els) return this;
10651 if(typeof els == "string"){
10652 els = Roo.Element.selectorFunction(els);
10654 var yels = this.elements;
10655 var index = yels.length-1;
10656 for(var i = 0, len = els.length; i < len; i++) {
10657 yels[++index] = Roo.get(els[i]);
10663 * Clears this composite and adds the elements returned by the passed selector.
10664 * @param {String/Array} els A string CSS selector, an array of elements or an element
10665 * @return {CompositeElement} this
10667 fill : function(els){
10668 this.elements = [];
10674 * Filters this composite to only elements that match the passed selector.
10675 * @param {String} selector A string CSS selector
10676 * @return {CompositeElement} this
10678 filter : function(selector){
10680 this.each(function(el){
10681 if(el.is(selector)){
10682 els[els.length] = el.dom;
10689 invoke : function(fn, args){
10690 var els = this.elements;
10691 for(var i = 0, len = els.length; i < len; i++) {
10692 Roo.Element.prototype[fn].apply(els[i], args);
10697 * Adds elements to this composite.
10698 * @param {String/Array} els A string CSS selector, an array of elements or an element
10699 * @return {CompositeElement} this
10701 add : function(els){
10702 if(typeof els == "string"){
10703 this.addElements(Roo.Element.selectorFunction(els));
10704 }else if(els.length !== undefined){
10705 this.addElements(els);
10707 this.addElements([els]);
10712 * Calls the passed function passing (el, this, index) for each element in this composite.
10713 * @param {Function} fn The function to call
10714 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10715 * @return {CompositeElement} this
10717 each : function(fn, scope){
10718 var els = this.elements;
10719 for(var i = 0, len = els.length; i < len; i++){
10720 if(fn.call(scope || els[i], els[i], this, i) === false) {
10728 * Returns the Element object at the specified index
10729 * @param {Number} index
10730 * @return {Roo.Element}
10732 item : function(index){
10733 return this.elements[index] || null;
10737 * Returns the first Element
10738 * @return {Roo.Element}
10740 first : function(){
10741 return this.item(0);
10745 * Returns the last Element
10746 * @return {Roo.Element}
10749 return this.item(this.elements.length-1);
10753 * Returns the number of elements in this composite
10756 getCount : function(){
10757 return this.elements.length;
10761 * Returns true if this composite contains the passed element
10764 contains : function(el){
10765 return this.indexOf(el) !== -1;
10769 * Returns true if this composite contains the passed element
10772 indexOf : function(el){
10773 return this.elements.indexOf(Roo.get(el));
10778 * Removes the specified element(s).
10779 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10780 * or an array of any of those.
10781 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10782 * @return {CompositeElement} this
10784 removeElement : function(el, removeDom){
10785 if(el instanceof Array){
10786 for(var i = 0, len = el.length; i < len; i++){
10787 this.removeElement(el[i]);
10791 var index = typeof el == 'number' ? el : this.indexOf(el);
10794 var d = this.elements[index];
10798 d.parentNode.removeChild(d);
10801 this.elements.splice(index, 1);
10807 * Replaces the specified element with the passed element.
10808 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10810 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10811 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10812 * @return {CompositeElement} this
10814 replaceElement : function(el, replacement, domReplace){
10815 var index = typeof el == 'number' ? el : this.indexOf(el);
10818 this.elements[index].replaceWith(replacement);
10820 this.elements.splice(index, 1, Roo.get(replacement))
10827 * Removes all elements.
10829 clear : function(){
10830 this.elements = [];
10834 Roo.CompositeElement.createCall = function(proto, fnName){
10835 if(!proto[fnName]){
10836 proto[fnName] = function(){
10837 return this.invoke(fnName, arguments);
10841 for(var fnName in Roo.Element.prototype){
10842 if(typeof Roo.Element.prototype[fnName] == "function"){
10843 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10849 * Ext JS Library 1.1.1
10850 * Copyright(c) 2006-2007, Ext JS, LLC.
10852 * Originally Released Under LGPL - original licence link has changed is not relivant.
10855 * <script type="text/javascript">
10859 * @class Roo.CompositeElementLite
10860 * @extends Roo.CompositeElement
10861 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10863 var els = Roo.select("#some-el div.some-class");
10864 // or select directly from an existing element
10865 var el = Roo.get('some-el');
10866 el.select('div.some-class');
10868 els.setWidth(100); // all elements become 100 width
10869 els.hide(true); // all elements fade out and hide
10871 els.setWidth(100).hide(true);
10872 </code></pre><br><br>
10873 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10874 * actions will be performed on all the elements in this collection.</b>
10876 Roo.CompositeElementLite = function(els){
10877 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10878 this.el = new Roo.Element.Flyweight();
10880 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10881 addElements : function(els){
10883 if(els instanceof Array){
10884 this.elements = this.elements.concat(els);
10886 var yels = this.elements;
10887 var index = yels.length-1;
10888 for(var i = 0, len = els.length; i < len; i++) {
10889 yels[++index] = els[i];
10895 invoke : function(fn, args){
10896 var els = this.elements;
10898 for(var i = 0, len = els.length; i < len; i++) {
10900 Roo.Element.prototype[fn].apply(el, args);
10905 * Returns a flyweight Element of the dom element object at the specified index
10906 * @param {Number} index
10907 * @return {Roo.Element}
10909 item : function(index){
10910 if(!this.elements[index]){
10913 this.el.dom = this.elements[index];
10917 // fixes scope with flyweight
10918 addListener : function(eventName, handler, scope, opt){
10919 var els = this.elements;
10920 for(var i = 0, len = els.length; i < len; i++) {
10921 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10927 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10928 * passed is the flyweight (shared) Roo.Element instance, so if you require a
10929 * a reference to the dom node, use el.dom.</b>
10930 * @param {Function} fn The function to call
10931 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10932 * @return {CompositeElement} this
10934 each : function(fn, scope){
10935 var els = this.elements;
10937 for(var i = 0, len = els.length; i < len; i++){
10939 if(fn.call(scope || el, el, this, i) === false){
10946 indexOf : function(el){
10947 return this.elements.indexOf(Roo.getDom(el));
10950 replaceElement : function(el, replacement, domReplace){
10951 var index = typeof el == 'number' ? el : this.indexOf(el);
10953 replacement = Roo.getDom(replacement);
10955 var d = this.elements[index];
10956 d.parentNode.insertBefore(replacement, d);
10957 d.parentNode.removeChild(d);
10959 this.elements.splice(index, 1, replacement);
10964 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10968 * Ext JS Library 1.1.1
10969 * Copyright(c) 2006-2007, Ext JS, LLC.
10971 * Originally Released Under LGPL - original licence link has changed is not relivant.
10974 * <script type="text/javascript">
10980 * @class Roo.data.Connection
10981 * @extends Roo.util.Observable
10982 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
10983 * either to a configured URL, or to a URL specified at request time.<br><br>
10985 * Requests made by this class are asynchronous, and will return immediately. No data from
10986 * the server will be available to the statement immediately following the {@link #request} call.
10987 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
10989 * Note: If you are doing a file upload, you will not get a normal response object sent back to
10990 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
10991 * The response object is created using the innerHTML of the IFRAME's document as the responseText
10992 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
10993 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
10994 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
10995 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
10996 * standard DOM methods.
10998 * @param {Object} config a configuration object.
11000 Roo.data.Connection = function(config){
11001 Roo.apply(this, config);
11004 * @event beforerequest
11005 * Fires before a network request is made to retrieve a data object.
11006 * @param {Connection} conn This Connection object.
11007 * @param {Object} options The options config object passed to the {@link #request} method.
11009 "beforerequest" : true,
11011 * @event requestcomplete
11012 * Fires if the request was successfully completed.
11013 * @param {Connection} conn This Connection object.
11014 * @param {Object} response The XHR object containing the response data.
11015 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11016 * @param {Object} options The options config object passed to the {@link #request} method.
11018 "requestcomplete" : true,
11020 * @event requestexception
11021 * Fires if an error HTTP status was returned from the server.
11022 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11023 * @param {Connection} conn This Connection object.
11024 * @param {Object} response The XHR object containing the response data.
11025 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11026 * @param {Object} options The options config object passed to the {@link #request} method.
11028 "requestexception" : true
11030 Roo.data.Connection.superclass.constructor.call(this);
11033 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11035 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11038 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11039 * extra parameters to each request made by this object. (defaults to undefined)
11042 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11043 * to each request made by this object. (defaults to undefined)
11046 * @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)
11049 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11053 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11059 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11062 disableCaching: true,
11065 * Sends an HTTP request to a remote server.
11066 * @param {Object} options An object which may contain the following properties:<ul>
11067 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11068 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11069 * request, a url encoded string or a function to call to get either.</li>
11070 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11071 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11072 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11073 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11074 * <li>options {Object} The parameter to the request call.</li>
11075 * <li>success {Boolean} True if the request succeeded.</li>
11076 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11078 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11079 * The callback is passed the following parameters:<ul>
11080 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11081 * <li>options {Object} The parameter to the request call.</li>
11083 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11084 * The callback is passed the following parameters:<ul>
11085 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11086 * <li>options {Object} The parameter to the request call.</li>
11088 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11089 * for the callback function. Defaults to the browser window.</li>
11090 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11091 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11092 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11093 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11094 * params for the post data. Any params will be appended to the URL.</li>
11095 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11097 * @return {Number} transactionId
11099 request : function(o){
11100 if(this.fireEvent("beforerequest", this, o) !== false){
11103 if(typeof p == "function"){
11104 p = p.call(o.scope||window, o);
11106 if(typeof p == "object"){
11107 p = Roo.urlEncode(o.params);
11109 if(this.extraParams){
11110 var extras = Roo.urlEncode(this.extraParams);
11111 p = p ? (p + '&' + extras) : extras;
11114 var url = o.url || this.url;
11115 if(typeof url == 'function'){
11116 url = url.call(o.scope||window, o);
11120 var form = Roo.getDom(o.form);
11121 url = url || form.action;
11123 var enctype = form.getAttribute("enctype");
11124 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11125 return this.doFormUpload(o, p, url);
11127 var f = Roo.lib.Ajax.serializeForm(form);
11128 p = p ? (p + '&' + f) : f;
11131 var hs = o.headers;
11132 if(this.defaultHeaders){
11133 hs = Roo.apply(hs || {}, this.defaultHeaders);
11140 success: this.handleResponse,
11141 failure: this.handleFailure,
11143 argument: {options: o},
11144 timeout : this.timeout
11147 var method = o.method||this.method||(p ? "POST" : "GET");
11149 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11150 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11153 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11157 }else if(this.autoAbort !== false){
11161 if((method == 'GET' && p) || o.xmlData){
11162 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11165 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11166 return this.transId;
11168 Roo.callback(o.callback, o.scope, [o, null, null]);
11174 * Determine whether this object has a request outstanding.
11175 * @param {Number} transactionId (Optional) defaults to the last transaction
11176 * @return {Boolean} True if there is an outstanding request.
11178 isLoading : function(transId){
11180 return Roo.lib.Ajax.isCallInProgress(transId);
11182 return this.transId ? true : false;
11187 * Aborts any outstanding request.
11188 * @param {Number} transactionId (Optional) defaults to the last transaction
11190 abort : function(transId){
11191 if(transId || this.isLoading()){
11192 Roo.lib.Ajax.abort(transId || this.transId);
11197 handleResponse : function(response){
11198 this.transId = false;
11199 var options = response.argument.options;
11200 response.argument = options ? options.argument : null;
11201 this.fireEvent("requestcomplete", this, response, options);
11202 Roo.callback(options.success, options.scope, [response, options]);
11203 Roo.callback(options.callback, options.scope, [options, true, response]);
11207 handleFailure : function(response, e){
11208 this.transId = false;
11209 var options = response.argument.options;
11210 response.argument = options ? options.argument : null;
11211 this.fireEvent("requestexception", this, response, options, e);
11212 Roo.callback(options.failure, options.scope, [response, options]);
11213 Roo.callback(options.callback, options.scope, [options, false, response]);
11217 doFormUpload : function(o, ps, url){
11219 var frame = document.createElement('iframe');
11222 frame.className = 'x-hidden';
11224 frame.src = Roo.SSL_SECURE_URL;
11226 document.body.appendChild(frame);
11229 document.frames[id].name = id;
11232 var form = Roo.getDom(o.form);
11234 form.method = 'POST';
11235 form.enctype = form.encoding = 'multipart/form-data';
11241 if(ps){ // add dynamic params
11243 ps = Roo.urlDecode(ps, false);
11245 if(ps.hasOwnProperty(k)){
11246 hd = document.createElement('input');
11247 hd.type = 'hidden';
11250 form.appendChild(hd);
11257 var r = { // bogus response object
11262 r.argument = o ? o.argument : null;
11267 doc = frame.contentWindow.document;
11269 doc = (frame.contentDocument || window.frames[id].document);
11271 if(doc && doc.body){
11272 r.responseText = doc.body.innerHTML;
11274 if(doc && doc.XMLDocument){
11275 r.responseXML = doc.XMLDocument;
11277 r.responseXML = doc;
11284 Roo.EventManager.removeListener(frame, 'load', cb, this);
11286 this.fireEvent("requestcomplete", this, r, o);
11287 Roo.callback(o.success, o.scope, [r, o]);
11288 Roo.callback(o.callback, o.scope, [o, true, r]);
11290 setTimeout(function(){document.body.removeChild(frame);}, 100);
11293 Roo.EventManager.on(frame, 'load', cb, this);
11296 if(hiddens){ // remove dynamic params
11297 for(var i = 0, len = hiddens.length; i < len; i++){
11298 form.removeChild(hiddens[i]);
11306 * @extends Roo.data.Connection
11307 * Global Ajax request class.
11311 Roo.Ajax = new Roo.data.Connection({
11314 * @cfg {String} url @hide
11317 * @cfg {Object} extraParams @hide
11320 * @cfg {Object} defaultHeaders @hide
11323 * @cfg {String} method (Optional) @hide
11326 * @cfg {Number} timeout (Optional) @hide
11329 * @cfg {Boolean} autoAbort (Optional) @hide
11333 * @cfg {Boolean} disableCaching (Optional) @hide
11337 * @property disableCaching
11338 * True to add a unique cache-buster param to GET requests. (defaults to true)
11343 * The default URL to be used for requests to the server. (defaults to undefined)
11347 * @property extraParams
11348 * An object containing properties which are used as
11349 * extra parameters to each request made by this object. (defaults to undefined)
11353 * @property defaultHeaders
11354 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11359 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11363 * @property timeout
11364 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11369 * @property autoAbort
11370 * Whether a new request should abort any pending requests. (defaults to false)
11376 * Serialize the passed form into a url encoded string
11377 * @param {String/HTMLElement} form
11380 serializeForm : function(form){
11381 return Roo.lib.Ajax.serializeForm(form);
11385 * Ext JS Library 1.1.1
11386 * Copyright(c) 2006-2007, Ext JS, LLC.
11388 * Originally Released Under LGPL - original licence link has changed is not relivant.
11391 * <script type="text/javascript">
11396 * @extends Roo.data.Connection
11397 * Global Ajax request class.
11399 * @instanceOf Roo.data.Connection
11401 Roo.Ajax = new Roo.data.Connection({
11410 * @cfg {String} url @hide
11413 * @cfg {Object} extraParams @hide
11416 * @cfg {Object} defaultHeaders @hide
11419 * @cfg {String} method (Optional) @hide
11422 * @cfg {Number} timeout (Optional) @hide
11425 * @cfg {Boolean} autoAbort (Optional) @hide
11429 * @cfg {Boolean} disableCaching (Optional) @hide
11433 * @property disableCaching
11434 * True to add a unique cache-buster param to GET requests. (defaults to true)
11439 * The default URL to be used for requests to the server. (defaults to undefined)
11443 * @property extraParams
11444 * An object containing properties which are used as
11445 * extra parameters to each request made by this object. (defaults to undefined)
11449 * @property defaultHeaders
11450 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11455 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11459 * @property timeout
11460 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11465 * @property autoAbort
11466 * Whether a new request should abort any pending requests. (defaults to false)
11472 * Serialize the passed form into a url encoded string
11473 * @param {String/HTMLElement} form
11476 serializeForm : function(form){
11477 return Roo.lib.Ajax.serializeForm(form);
11481 * Ext JS Library 1.1.1
11482 * Copyright(c) 2006-2007, Ext JS, LLC.
11484 * Originally Released Under LGPL - original licence link has changed is not relivant.
11487 * <script type="text/javascript">
11492 * @class Roo.UpdateManager
11493 * @extends Roo.util.Observable
11494 * Provides AJAX-style update for Element object.<br><br>
11497 * // Get it from a Roo.Element object
11498 * var el = Roo.get("foo");
11499 * var mgr = el.getUpdateManager();
11500 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11502 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11504 * // or directly (returns the same UpdateManager instance)
11505 * var mgr = new Roo.UpdateManager("myElementId");
11506 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11507 * mgr.on("update", myFcnNeedsToKnow);
11509 // short handed call directly from the element object
11510 Roo.get("foo").load({
11514 text: "Loading Foo..."
11518 * Create new UpdateManager directly.
11519 * @param {String/HTMLElement/Roo.Element} el The element to update
11520 * @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).
11522 Roo.UpdateManager = function(el, forceNew){
11524 if(!forceNew && el.updateManager){
11525 return el.updateManager;
11528 * The Element object
11529 * @type Roo.Element
11533 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11536 this.defaultUrl = null;
11540 * @event beforeupdate
11541 * Fired before an update is made, return false from your handler and the update is cancelled.
11542 * @param {Roo.Element} el
11543 * @param {String/Object/Function} url
11544 * @param {String/Object} params
11546 "beforeupdate": true,
11549 * Fired after successful update is made.
11550 * @param {Roo.Element} el
11551 * @param {Object} oResponseObject The response Object
11556 * Fired on update failure.
11557 * @param {Roo.Element} el
11558 * @param {Object} oResponseObject The response Object
11562 var d = Roo.UpdateManager.defaults;
11564 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11567 this.sslBlankUrl = d.sslBlankUrl;
11569 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11572 this.disableCaching = d.disableCaching;
11574 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11577 this.indicatorText = d.indicatorText;
11579 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11582 this.showLoadIndicator = d.showLoadIndicator;
11584 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11587 this.timeout = d.timeout;
11590 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11593 this.loadScripts = d.loadScripts;
11596 * Transaction object of current executing transaction
11598 this.transaction = null;
11603 this.autoRefreshProcId = null;
11605 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11608 this.refreshDelegate = this.refresh.createDelegate(this);
11610 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11613 this.updateDelegate = this.update.createDelegate(this);
11615 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11618 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11622 this.successDelegate = this.processSuccess.createDelegate(this);
11626 this.failureDelegate = this.processFailure.createDelegate(this);
11628 if(!this.renderer){
11630 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11632 this.renderer = new Roo.UpdateManager.BasicRenderer();
11635 Roo.UpdateManager.superclass.constructor.call(this);
11638 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11640 * Get the Element this UpdateManager is bound to
11641 * @return {Roo.Element} The element
11643 getEl : function(){
11647 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11648 * @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:
11651 url: "your-url.php",<br/>
11652 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11653 callback: yourFunction,<br/>
11654 scope: yourObject, //(optional scope) <br/>
11655 discardUrl: false, <br/>
11656 nocache: false,<br/>
11657 text: "Loading...",<br/>
11659 scripts: false<br/>
11662 * The only required property is url. The optional properties nocache, text and scripts
11663 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11664 * @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}
11665 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11666 * @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.
11668 update : function(url, params, callback, discardUrl){
11669 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11670 var method = this.method, cfg;
11671 if(typeof url == "object"){ // must be config object
11674 params = params || cfg.params;
11675 callback = callback || cfg.callback;
11676 discardUrl = discardUrl || cfg.discardUrl;
11677 if(callback && cfg.scope){
11678 callback = callback.createDelegate(cfg.scope);
11680 if(typeof cfg.method != "undefined"){method = cfg.method;};
11681 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11682 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11683 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11684 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11686 this.showLoading();
11688 this.defaultUrl = url;
11690 if(typeof url == "function"){
11691 url = url.call(this);
11694 method = method || (params ? "POST" : "GET");
11695 if(method == "GET"){
11696 url = this.prepareUrl(url);
11699 var o = Roo.apply(cfg ||{}, {
11702 success: this.successDelegate,
11703 failure: this.failureDelegate,
11704 callback: undefined,
11705 timeout: (this.timeout*1000),
11706 argument: {"url": url, "form": null, "callback": callback, "params": params}
11709 this.transaction = Roo.Ajax.request(o);
11714 * 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.
11715 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11716 * @param {String/HTMLElement} form The form Id or form element
11717 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11718 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11719 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11721 formUpdate : function(form, url, reset, callback){
11722 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11723 if(typeof url == "function"){
11724 url = url.call(this);
11726 form = Roo.getDom(form);
11727 this.transaction = Roo.Ajax.request({
11730 success: this.successDelegate,
11731 failure: this.failureDelegate,
11732 timeout: (this.timeout*1000),
11733 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11735 this.showLoading.defer(1, this);
11740 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11741 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11743 refresh : function(callback){
11744 if(this.defaultUrl == null){
11747 this.update(this.defaultUrl, null, callback, true);
11751 * Set this element to auto refresh.
11752 * @param {Number} interval How often to update (in seconds).
11753 * @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)
11754 * @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}
11755 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11756 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11758 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11760 this.update(url || this.defaultUrl, params, callback, true);
11762 if(this.autoRefreshProcId){
11763 clearInterval(this.autoRefreshProcId);
11765 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11769 * Stop auto refresh on this element.
11771 stopAutoRefresh : function(){
11772 if(this.autoRefreshProcId){
11773 clearInterval(this.autoRefreshProcId);
11774 delete this.autoRefreshProcId;
11778 isAutoRefreshing : function(){
11779 return this.autoRefreshProcId ? true : false;
11782 * Called to update the element to "Loading" state. Override to perform custom action.
11784 showLoading : function(){
11785 if(this.showLoadIndicator){
11786 this.el.update(this.indicatorText);
11791 * Adds unique parameter to query string if disableCaching = true
11794 prepareUrl : function(url){
11795 if(this.disableCaching){
11796 var append = "_dc=" + (new Date().getTime());
11797 if(url.indexOf("?") !== -1){
11798 url += "&" + append;
11800 url += "?" + append;
11809 processSuccess : function(response){
11810 this.transaction = null;
11811 if(response.argument.form && response.argument.reset){
11812 try{ // put in try/catch since some older FF releases had problems with this
11813 response.argument.form.reset();
11816 if(this.loadScripts){
11817 this.renderer.render(this.el, response, this,
11818 this.updateComplete.createDelegate(this, [response]));
11820 this.renderer.render(this.el, response, this);
11821 this.updateComplete(response);
11825 updateComplete : function(response){
11826 this.fireEvent("update", this.el, response);
11827 if(typeof response.argument.callback == "function"){
11828 response.argument.callback(this.el, true, response);
11835 processFailure : function(response){
11836 this.transaction = null;
11837 this.fireEvent("failure", this.el, response);
11838 if(typeof response.argument.callback == "function"){
11839 response.argument.callback(this.el, false, response);
11844 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11845 * @param {Object} renderer The object implementing the render() method
11847 setRenderer : function(renderer){
11848 this.renderer = renderer;
11851 getRenderer : function(){
11852 return this.renderer;
11856 * Set the defaultUrl used for updates
11857 * @param {String/Function} defaultUrl The url or a function to call to get the url
11859 setDefaultUrl : function(defaultUrl){
11860 this.defaultUrl = defaultUrl;
11864 * Aborts the executing transaction
11866 abort : function(){
11867 if(this.transaction){
11868 Roo.Ajax.abort(this.transaction);
11873 * Returns true if an update is in progress
11874 * @return {Boolean}
11876 isUpdating : function(){
11877 if(this.transaction){
11878 return Roo.Ajax.isLoading(this.transaction);
11885 * @class Roo.UpdateManager.defaults
11886 * @static (not really - but it helps the doc tool)
11887 * The defaults collection enables customizing the default properties of UpdateManager
11889 Roo.UpdateManager.defaults = {
11891 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11897 * True to process scripts by default (Defaults to false).
11900 loadScripts : false,
11903 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11906 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11908 * Whether to append unique parameter on get request to disable caching (Defaults to false).
11911 disableCaching : false,
11913 * Whether to show indicatorText when loading (Defaults to true).
11916 showLoadIndicator : true,
11918 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
11921 indicatorText : '<div class="loading-indicator">Loading...</div>'
11925 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11927 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11928 * @param {String/HTMLElement/Roo.Element} el The element to update
11929 * @param {String} url The url
11930 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11931 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11934 * @member Roo.UpdateManager
11936 Roo.UpdateManager.updateElement = function(el, url, params, options){
11937 var um = Roo.get(el, true).getUpdateManager();
11938 Roo.apply(um, options);
11939 um.update(url, params, options ? options.callback : null);
11941 // alias for backwards compat
11942 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11944 * @class Roo.UpdateManager.BasicRenderer
11945 * Default Content renderer. Updates the elements innerHTML with the responseText.
11947 Roo.UpdateManager.BasicRenderer = function(){};
11949 Roo.UpdateManager.BasicRenderer.prototype = {
11951 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11952 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11953 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11954 * @param {Roo.Element} el The element being rendered
11955 * @param {Object} response The YUI Connect response object
11956 * @param {UpdateManager} updateManager The calling update manager
11957 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11959 render : function(el, response, updateManager, callback){
11960 el.update(response.responseText, updateManager.loadScripts, callback);
11965 * Ext JS Library 1.1.1
11966 * Copyright(c) 2006-2007, Ext JS, LLC.
11968 * Originally Released Under LGPL - original licence link has changed is not relivant.
11971 * <script type="text/javascript">
11975 * @class Roo.util.DelayedTask
11976 * Provides a convenient method of performing setTimeout where a new
11977 * timeout cancels the old timeout. An example would be performing validation on a keypress.
11978 * You can use this class to buffer
11979 * the keypress events for a certain number of milliseconds, and perform only if they stop
11980 * for that amount of time.
11981 * @constructor The parameters to this constructor serve as defaults and are not required.
11982 * @param {Function} fn (optional) The default function to timeout
11983 * @param {Object} scope (optional) The default scope of that timeout
11984 * @param {Array} args (optional) The default Array of arguments
11986 Roo.util.DelayedTask = function(fn, scope, args){
11987 var id = null, d, t;
11989 var call = function(){
11990 var now = new Date().getTime();
11994 fn.apply(scope, args || []);
11998 * Cancels any pending timeout and queues a new one
11999 * @param {Number} delay The milliseconds to delay
12000 * @param {Function} newFn (optional) Overrides function passed to constructor
12001 * @param {Object} newScope (optional) Overrides scope passed to constructor
12002 * @param {Array} newArgs (optional) Overrides args passed to constructor
12004 this.delay = function(delay, newFn, newScope, newArgs){
12005 if(id && delay != d){
12009 t = new Date().getTime();
12011 scope = newScope || scope;
12012 args = newArgs || args;
12014 id = setInterval(call, d);
12019 * Cancel the last queued timeout
12021 this.cancel = function(){
12029 * Ext JS Library 1.1.1
12030 * Copyright(c) 2006-2007, Ext JS, LLC.
12032 * Originally Released Under LGPL - original licence link has changed is not relivant.
12035 * <script type="text/javascript">
12039 Roo.util.TaskRunner = function(interval){
12040 interval = interval || 10;
12041 var tasks = [], removeQueue = [];
12043 var running = false;
12045 var stopThread = function(){
12051 var startThread = function(){
12054 id = setInterval(runTasks, interval);
12058 var removeTask = function(task){
12059 removeQueue.push(task);
12065 var runTasks = function(){
12066 if(removeQueue.length > 0){
12067 for(var i = 0, len = removeQueue.length; i < len; i++){
12068 tasks.remove(removeQueue[i]);
12071 if(tasks.length < 1){
12076 var now = new Date().getTime();
12077 for(var i = 0, len = tasks.length; i < len; ++i){
12079 var itime = now - t.taskRunTime;
12080 if(t.interval <= itime){
12081 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12082 t.taskRunTime = now;
12083 if(rt === false || t.taskRunCount === t.repeat){
12088 if(t.duration && t.duration <= (now - t.taskStartTime)){
12095 * Queues a new task.
12096 * @param {Object} task
12098 this.start = function(task){
12100 task.taskStartTime = new Date().getTime();
12101 task.taskRunTime = 0;
12102 task.taskRunCount = 0;
12107 this.stop = function(task){
12112 this.stopAll = function(){
12114 for(var i = 0, len = tasks.length; i < len; i++){
12115 if(tasks[i].onStop){
12124 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12126 * Ext JS Library 1.1.1
12127 * Copyright(c) 2006-2007, Ext JS, LLC.
12129 * Originally Released Under LGPL - original licence link has changed is not relivant.
12132 * <script type="text/javascript">
12137 * @class Roo.util.MixedCollection
12138 * @extends Roo.util.Observable
12139 * A Collection class that maintains both numeric indexes and keys and exposes events.
12141 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12142 * collection (defaults to false)
12143 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12144 * and return the key value for that item. This is used when available to look up the key on items that
12145 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12146 * equivalent to providing an implementation for the {@link #getKey} method.
12148 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12156 * Fires when the collection is cleared.
12161 * Fires when an item is added to the collection.
12162 * @param {Number} index The index at which the item was added.
12163 * @param {Object} o The item added.
12164 * @param {String} key The key associated with the added item.
12169 * Fires when an item is replaced in the collection.
12170 * @param {String} key he key associated with the new added.
12171 * @param {Object} old The item being replaced.
12172 * @param {Object} new The new item.
12177 * Fires when an item is removed from the collection.
12178 * @param {Object} o The item being removed.
12179 * @param {String} key (optional) The key associated with the removed item.
12184 this.allowFunctions = allowFunctions === true;
12186 this.getKey = keyFn;
12188 Roo.util.MixedCollection.superclass.constructor.call(this);
12191 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12192 allowFunctions : false,
12195 * Adds an item to the collection.
12196 * @param {String} key The key to associate with the item
12197 * @param {Object} o The item to add.
12198 * @return {Object} The item added.
12200 add : function(key, o){
12201 if(arguments.length == 1){
12203 key = this.getKey(o);
12205 if(typeof key == "undefined" || key === null){
12207 this.items.push(o);
12208 this.keys.push(null);
12210 var old = this.map[key];
12212 return this.replace(key, o);
12215 this.items.push(o);
12217 this.keys.push(key);
12219 this.fireEvent("add", this.length-1, o, key);
12224 * MixedCollection has a generic way to fetch keys if you implement getKey.
12227 var mc = new Roo.util.MixedCollection();
12228 mc.add(someEl.dom.id, someEl);
12229 mc.add(otherEl.dom.id, otherEl);
12233 var mc = new Roo.util.MixedCollection();
12234 mc.getKey = function(el){
12240 // or via the constructor
12241 var mc = new Roo.util.MixedCollection(false, function(el){
12247 * @param o {Object} The item for which to find the key.
12248 * @return {Object} The key for the passed item.
12250 getKey : function(o){
12255 * Replaces an item in the collection.
12256 * @param {String} key The key associated with the item to replace, or the item to replace.
12257 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12258 * @return {Object} The new item.
12260 replace : function(key, o){
12261 if(arguments.length == 1){
12263 key = this.getKey(o);
12265 var old = this.item(key);
12266 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12267 return this.add(key, o);
12269 var index = this.indexOfKey(key);
12270 this.items[index] = o;
12272 this.fireEvent("replace", key, old, o);
12277 * Adds all elements of an Array or an Object to the collection.
12278 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12279 * an Array of values, each of which are added to the collection.
12281 addAll : function(objs){
12282 if(arguments.length > 1 || objs instanceof Array){
12283 var args = arguments.length > 1 ? arguments : objs;
12284 for(var i = 0, len = args.length; i < len; i++){
12288 for(var key in objs){
12289 if(this.allowFunctions || typeof objs[key] != "function"){
12290 this.add(key, objs[key]);
12297 * Executes the specified function once for every item in the collection, passing each
12298 * item as the first and only parameter. returning false from the function will stop the iteration.
12299 * @param {Function} fn The function to execute for each item.
12300 * @param {Object} scope (optional) The scope in which to execute the function.
12302 each : function(fn, scope){
12303 var items = [].concat(this.items); // each safe for removal
12304 for(var i = 0, len = items.length; i < len; i++){
12305 if(fn.call(scope || items[i], items[i], i, len) === false){
12312 * Executes the specified function once for every key in the collection, passing each
12313 * key, and its associated item as the first two parameters.
12314 * @param {Function} fn The function to execute for each item.
12315 * @param {Object} scope (optional) The scope in which to execute the function.
12317 eachKey : function(fn, scope){
12318 for(var i = 0, len = this.keys.length; i < len; i++){
12319 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12324 * Returns the first item in the collection which elicits a true return value from the
12325 * passed selection function.
12326 * @param {Function} fn The selection function to execute for each item.
12327 * @param {Object} scope (optional) The scope in which to execute the function.
12328 * @return {Object} The first item in the collection which returned true from the selection function.
12330 find : function(fn, scope){
12331 for(var i = 0, len = this.items.length; i < len; i++){
12332 if(fn.call(scope || window, this.items[i], this.keys[i])){
12333 return this.items[i];
12340 * Inserts an item at the specified index in the collection.
12341 * @param {Number} index The index to insert the item at.
12342 * @param {String} key The key to associate with the new item, or the item itself.
12343 * @param {Object} o (optional) If the second parameter was a key, the new item.
12344 * @return {Object} The item inserted.
12346 insert : function(index, key, o){
12347 if(arguments.length == 2){
12349 key = this.getKey(o);
12351 if(index >= this.length){
12352 return this.add(key, o);
12355 this.items.splice(index, 0, o);
12356 if(typeof key != "undefined" && key != null){
12359 this.keys.splice(index, 0, key);
12360 this.fireEvent("add", index, o, key);
12365 * Removed an item from the collection.
12366 * @param {Object} o The item to remove.
12367 * @return {Object} The item removed.
12369 remove : function(o){
12370 return this.removeAt(this.indexOf(o));
12374 * Remove an item from a specified index in the collection.
12375 * @param {Number} index The index within the collection of the item to remove.
12377 removeAt : function(index){
12378 if(index < this.length && index >= 0){
12380 var o = this.items[index];
12381 this.items.splice(index, 1);
12382 var key = this.keys[index];
12383 if(typeof key != "undefined"){
12384 delete this.map[key];
12386 this.keys.splice(index, 1);
12387 this.fireEvent("remove", o, key);
12392 * Removed an item associated with the passed key fom the collection.
12393 * @param {String} key The key of the item to remove.
12395 removeKey : function(key){
12396 return this.removeAt(this.indexOfKey(key));
12400 * Returns the number of items in the collection.
12401 * @return {Number} the number of items in the collection.
12403 getCount : function(){
12404 return this.length;
12408 * Returns index within the collection of the passed Object.
12409 * @param {Object} o The item to find the index of.
12410 * @return {Number} index of the item.
12412 indexOf : function(o){
12413 if(!this.items.indexOf){
12414 for(var i = 0, len = this.items.length; i < len; i++){
12415 if(this.items[i] == o) return i;
12419 return this.items.indexOf(o);
12424 * Returns index within the collection of the passed key.
12425 * @param {String} key The key to find the index of.
12426 * @return {Number} index of the key.
12428 indexOfKey : function(key){
12429 if(!this.keys.indexOf){
12430 for(var i = 0, len = this.keys.length; i < len; i++){
12431 if(this.keys[i] == key) return i;
12435 return this.keys.indexOf(key);
12440 * Returns the item associated with the passed key OR index. Key has priority over index.
12441 * @param {String/Number} key The key or index of the item.
12442 * @return {Object} The item associated with the passed key.
12444 item : function(key){
12445 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12446 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12450 * Returns the item at the specified index.
12451 * @param {Number} index The index of the item.
12454 itemAt : function(index){
12455 return this.items[index];
12459 * Returns the item associated with the passed key.
12460 * @param {String/Number} key The key of the item.
12461 * @return {Object} The item associated with the passed key.
12463 key : function(key){
12464 return this.map[key];
12468 * Returns true if the collection contains the passed Object as an item.
12469 * @param {Object} o The Object to look for in the collection.
12470 * @return {Boolean} True if the collection contains the Object as an item.
12472 contains : function(o){
12473 return this.indexOf(o) != -1;
12477 * Returns true if the collection contains the passed Object as a key.
12478 * @param {String} key The key to look for in the collection.
12479 * @return {Boolean} True if the collection contains the Object as a key.
12481 containsKey : function(key){
12482 return typeof this.map[key] != "undefined";
12486 * Removes all items from the collection.
12488 clear : function(){
12493 this.fireEvent("clear");
12497 * Returns the first item in the collection.
12498 * @return {Object} the first item in the collection..
12500 first : function(){
12501 return this.items[0];
12505 * Returns the last item in the collection.
12506 * @return {Object} the last item in the collection..
12509 return this.items[this.length-1];
12512 _sort : function(property, dir, fn){
12513 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12514 fn = fn || function(a, b){
12517 var c = [], k = this.keys, items = this.items;
12518 for(var i = 0, len = items.length; i < len; i++){
12519 c[c.length] = {key: k[i], value: items[i], index: i};
12521 c.sort(function(a, b){
12522 var v = fn(a[property], b[property]) * dsc;
12524 v = (a.index < b.index ? -1 : 1);
12528 for(var i = 0, len = c.length; i < len; i++){
12529 items[i] = c[i].value;
12532 this.fireEvent("sort", this);
12536 * Sorts this collection with the passed comparison function
12537 * @param {String} direction (optional) "ASC" or "DESC"
12538 * @param {Function} fn (optional) comparison function
12540 sort : function(dir, fn){
12541 this._sort("value", dir, fn);
12545 * Sorts this collection by keys
12546 * @param {String} direction (optional) "ASC" or "DESC"
12547 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12549 keySort : function(dir, fn){
12550 this._sort("key", dir, fn || function(a, b){
12551 return String(a).toUpperCase()-String(b).toUpperCase();
12556 * Returns a range of items in this collection
12557 * @param {Number} startIndex (optional) defaults to 0
12558 * @param {Number} endIndex (optional) default to the last item
12559 * @return {Array} An array of items
12561 getRange : function(start, end){
12562 var items = this.items;
12563 if(items.length < 1){
12566 start = start || 0;
12567 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12570 for(var i = start; i <= end; i++) {
12571 r[r.length] = items[i];
12574 for(var i = start; i >= end; i--) {
12575 r[r.length] = items[i];
12582 * Filter the <i>objects</i> in this collection by a specific property.
12583 * Returns a new collection that has been filtered.
12584 * @param {String} property A property on your objects
12585 * @param {String/RegExp} value Either string that the property values
12586 * should start with or a RegExp to test against the property
12587 * @return {MixedCollection} The new filtered collection
12589 filter : function(property, value){
12590 if(!value.exec){ // not a regex
12591 value = String(value);
12592 if(value.length == 0){
12593 return this.clone();
12595 value = new RegExp("^" + Roo.escapeRe(value), "i");
12597 return this.filterBy(function(o){
12598 return o && value.test(o[property]);
12603 * Filter by a function. * Returns a new collection that has been filtered.
12604 * The passed function will be called with each
12605 * object in the collection. If the function returns true, the value is included
12606 * otherwise it is filtered.
12607 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12608 * @param {Object} scope (optional) The scope of the function (defaults to this)
12609 * @return {MixedCollection} The new filtered collection
12611 filterBy : function(fn, scope){
12612 var r = new Roo.util.MixedCollection();
12613 r.getKey = this.getKey;
12614 var k = this.keys, it = this.items;
12615 for(var i = 0, len = it.length; i < len; i++){
12616 if(fn.call(scope||this, it[i], k[i])){
12617 r.add(k[i], it[i]);
12624 * Creates a duplicate of this collection
12625 * @return {MixedCollection}
12627 clone : function(){
12628 var r = new Roo.util.MixedCollection();
12629 var k = this.keys, it = this.items;
12630 for(var i = 0, len = it.length; i < len; i++){
12631 r.add(k[i], it[i]);
12633 r.getKey = this.getKey;
12638 * Returns the item associated with the passed key or index.
12640 * @param {String/Number} key The key or index of the item.
12641 * @return {Object} The item associated with the passed key.
12643 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12645 * Ext JS Library 1.1.1
12646 * Copyright(c) 2006-2007, Ext JS, LLC.
12648 * Originally Released Under LGPL - original licence link has changed is not relivant.
12651 * <script type="text/javascript">
12654 * @class Roo.util.JSON
12655 * Modified version of Douglas Crockford"s json.js that doesn"t
12656 * mess with the Object prototype
12657 * http://www.json.org/js.html
12660 Roo.util.JSON = new (function(){
12661 var useHasOwn = {}.hasOwnProperty ? true : false;
12663 // crashes Safari in some instances
12664 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12666 var pad = function(n) {
12667 return n < 10 ? "0" + n : n;
12680 var encodeString = function(s){
12681 if (/["\\\x00-\x1f]/.test(s)) {
12682 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12687 c = b.charCodeAt();
12689 Math.floor(c / 16).toString(16) +
12690 (c % 16).toString(16);
12693 return '"' + s + '"';
12696 var encodeArray = function(o){
12697 var a = ["["], b, i, l = o.length, v;
12698 for (i = 0; i < l; i += 1) {
12700 switch (typeof v) {
12709 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12717 var encodeDate = function(o){
12718 return '"' + o.getFullYear() + "-" +
12719 pad(o.getMonth() + 1) + "-" +
12720 pad(o.getDate()) + "T" +
12721 pad(o.getHours()) + ":" +
12722 pad(o.getMinutes()) + ":" +
12723 pad(o.getSeconds()) + '"';
12727 * Encodes an Object, Array or other value
12728 * @param {Mixed} o The variable to encode
12729 * @return {String} The JSON string
12731 this.encode = function(o){
12732 if(typeof o == "undefined" || o === null){
12734 }else if(o instanceof Array){
12735 return encodeArray(o);
12736 }else if(o instanceof Date){
12737 return encodeDate(o);
12738 }else if(typeof o == "string"){
12739 return encodeString(o);
12740 }else if(typeof o == "number"){
12741 return isFinite(o) ? String(o) : "null";
12742 }else if(typeof o == "boolean"){
12745 var a = ["{"], b, i, v;
12747 if(!useHasOwn || o.hasOwnProperty(i)) {
12749 switch (typeof v) {
12758 a.push(this.encode(i), ":",
12759 v === null ? "null" : this.encode(v));
12770 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12771 * @param {String} json The JSON string
12772 * @return {Object} The resulting object
12774 this.decode = function(json){
12778 return eval("(" + json + ')');
12782 * Shorthand for {@link Roo.util.JSON#encode}
12783 * @member Roo encode
12785 Roo.encode = Roo.util.JSON.encode;
12787 * Shorthand for {@link Roo.util.JSON#decode}
12788 * @member Roo decode
12790 Roo.decode = Roo.util.JSON.decode;
12793 * Ext JS Library 1.1.1
12794 * Copyright(c) 2006-2007, Ext JS, LLC.
12796 * Originally Released Under LGPL - original licence link has changed is not relivant.
12799 * <script type="text/javascript">
12803 * @class Roo.util.Format
12804 * Reusable data formatting functions
12807 Roo.util.Format = function(){
12808 var trimRe = /^\s+|\s+$/g;
12811 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12812 * @param {String} value The string to truncate
12813 * @param {Number} length The maximum length to allow before truncating
12814 * @return {String} The converted text
12816 ellipsis : function(value, len){
12817 if(value && value.length > len){
12818 return value.substr(0, len-3)+"...";
12824 * Checks a reference and converts it to empty string if it is undefined
12825 * @param {Mixed} value Reference to check
12826 * @return {Mixed} Empty string if converted, otherwise the original value
12828 undef : function(value){
12829 return typeof value != "undefined" ? value : "";
12833 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12834 * @param {String} value The string to encode
12835 * @return {String} The encoded text
12837 htmlEncode : function(value){
12838 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12842 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12843 * @param {String} value The string to decode
12844 * @return {String} The decoded text
12846 htmlDecode : function(value){
12847 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12851 * Trims any whitespace from either side of a string
12852 * @param {String} value The text to trim
12853 * @return {String} The trimmed text
12855 trim : function(value){
12856 return String(value).replace(trimRe, "");
12860 * Returns a substring from within an original string
12861 * @param {String} value The original text
12862 * @param {Number} start The start index of the substring
12863 * @param {Number} length The length of the substring
12864 * @return {String} The substring
12866 substr : function(value, start, length){
12867 return String(value).substr(start, length);
12871 * Converts a string to all lower case letters
12872 * @param {String} value The text to convert
12873 * @return {String} The converted text
12875 lowercase : function(value){
12876 return String(value).toLowerCase();
12880 * Converts a string to all upper case letters
12881 * @param {String} value The text to convert
12882 * @return {String} The converted text
12884 uppercase : function(value){
12885 return String(value).toUpperCase();
12889 * Converts the first character only of a string to upper case
12890 * @param {String} value The text to convert
12891 * @return {String} The converted text
12893 capitalize : function(value){
12894 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12898 call : function(value, fn){
12899 if(arguments.length > 2){
12900 var args = Array.prototype.slice.call(arguments, 2);
12901 args.unshift(value);
12903 return /** eval:var:value */ eval(fn).apply(window, args);
12905 /** eval:var:value */
12906 return /** eval:var:value */ eval(fn).call(window, value);
12911 * Format a number as US currency
12912 * @param {Number/String} value The numeric value to format
12913 * @return {String} The formatted currency string
12915 usMoney : function(v){
12916 v = (Math.round((v-0)*100))/100;
12917 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12919 var ps = v.split('.');
12921 var sub = ps[1] ? '.'+ ps[1] : '.00';
12922 var r = /(\d+)(\d{3})/;
12923 while (r.test(whole)) {
12924 whole = whole.replace(r, '$1' + ',' + '$2');
12926 return "$" + whole + sub ;
12930 * Parse a value into a formatted date using the specified format pattern.
12931 * @param {Mixed} value The value to format
12932 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12933 * @return {String} The formatted date string
12935 date : function(v, format){
12939 if(!(v instanceof Date)){
12940 v = new Date(Date.parse(v));
12942 return v.dateFormat(format || "m/d/Y");
12946 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12947 * @param {String} format Any valid date format string
12948 * @return {Function} The date formatting function
12950 dateRenderer : function(format){
12951 return function(v){
12952 return Roo.util.Format.date(v, format);
12957 stripTagsRE : /<\/?[^>]+>/gi,
12960 * Strips all HTML tags
12961 * @param {Mixed} value The text from which to strip tags
12962 * @return {String} The stripped text
12964 stripTags : function(v){
12965 return !v ? v : String(v).replace(this.stripTagsRE, "");
12970 * Ext JS Library 1.1.1
12971 * Copyright(c) 2006-2007, Ext JS, LLC.
12973 * Originally Released Under LGPL - original licence link has changed is not relivant.
12976 * <script type="text/javascript">
12983 * @class Roo.MasterTemplate
12984 * @extends Roo.Template
12985 * Provides a template that can have child templates. The syntax is:
12987 var t = new Roo.MasterTemplate(
12988 '<select name="{name}">',
12989 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
12992 t.add('options', {value: 'foo', text: 'bar'});
12993 // or you can add multiple child elements in one shot
12994 t.addAll('options', [
12995 {value: 'foo', text: 'bar'},
12996 {value: 'foo2', text: 'bar2'},
12997 {value: 'foo3', text: 'bar3'}
12999 // then append, applying the master template values
13000 t.append('my-form', {name: 'my-select'});
13002 * A name attribute for the child template is not required if you have only one child
13003 * template or you want to refer to them by index.
13005 Roo.MasterTemplate = function(){
13006 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13007 this.originalHtml = this.html;
13009 var m, re = this.subTemplateRe;
13012 while(m = re.exec(this.html)){
13013 var name = m[1], content = m[2];
13018 tpl : new Roo.Template(content)
13021 st[name] = st[subIndex];
13023 st[subIndex].tpl.compile();
13024 st[subIndex].tpl.call = this.call.createDelegate(this);
13027 this.subCount = subIndex;
13030 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13032 * The regular expression used to match sub templates
13036 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13039 * Applies the passed values to a child template.
13040 * @param {String/Number} name (optional) The name or index of the child template
13041 * @param {Array/Object} values The values to be applied to the template
13042 * @return {MasterTemplate} this
13044 add : function(name, values){
13045 if(arguments.length == 1){
13046 values = arguments[0];
13049 var s = this.subs[name];
13050 s.buffer[s.buffer.length] = s.tpl.apply(values);
13055 * Applies all the passed values to a child template.
13056 * @param {String/Number} name (optional) The name or index of the child template
13057 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13058 * @param {Boolean} reset (optional) True to reset the template first
13059 * @return {MasterTemplate} this
13061 fill : function(name, values, reset){
13063 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13071 for(var i = 0, len = values.length; i < len; i++){
13072 this.add(name, values[i]);
13078 * Resets the template for reuse
13079 * @return {MasterTemplate} this
13081 reset : function(){
13083 for(var i = 0; i < this.subCount; i++){
13089 applyTemplate : function(values){
13091 var replaceIndex = -1;
13092 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13093 return s[++replaceIndex].buffer.join("");
13095 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13098 apply : function(){
13099 return this.applyTemplate.apply(this, arguments);
13102 compile : function(){return this;}
13106 * Alias for fill().
13109 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13111 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13112 * var tpl = Roo.MasterTemplate.from('element-id');
13113 * @param {String/HTMLElement} el
13114 * @param {Object} config
13117 Roo.MasterTemplate.from = function(el, config){
13118 el = Roo.getDom(el);
13119 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13122 * Ext JS Library 1.1.1
13123 * Copyright(c) 2006-2007, Ext JS, LLC.
13125 * Originally Released Under LGPL - original licence link has changed is not relivant.
13128 * <script type="text/javascript">
13133 * @class Roo.util.CSS
13134 * Utility class for manipulating CSS rules
13137 Roo.util.CSS = function(){
13139 var doc = document;
13141 var camelRe = /(-[a-z])/gi;
13142 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13146 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13147 * tag and appended to the HEAD of the document.
13148 * @param {String} cssText The text containing the css rules
13149 * @param {String} id An id to add to the stylesheet for later removal
13150 * @return {StyleSheet}
13152 createStyleSheet : function(cssText, id){
13154 var head = doc.getElementsByTagName("head")[0];
13155 var rules = doc.createElement("style");
13156 rules.setAttribute("type", "text/css");
13158 rules.setAttribute("id", id);
13161 head.appendChild(rules);
13162 ss = rules.styleSheet;
13163 ss.cssText = cssText;
13166 rules.appendChild(doc.createTextNode(cssText));
13168 rules.cssText = cssText;
13170 head.appendChild(rules);
13171 ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13173 this.cacheStyleSheet(ss);
13178 * Removes a style or link tag by id
13179 * @param {String} id The id of the tag
13181 removeStyleSheet : function(id){
13182 var existing = doc.getElementById(id);
13184 existing.parentNode.removeChild(existing);
13189 * Dynamically swaps an existing stylesheet reference for a new one
13190 * @param {String} id The id of an existing link tag to remove
13191 * @param {String} url The href of the new stylesheet to include
13193 swapStyleSheet : function(id, url){
13194 this.removeStyleSheet(id);
13195 var ss = doc.createElement("link");
13196 ss.setAttribute("rel", "stylesheet");
13197 ss.setAttribute("type", "text/css");
13198 ss.setAttribute("id", id);
13199 ss.setAttribute("href", url);
13200 doc.getElementsByTagName("head")[0].appendChild(ss);
13204 * Refresh the rule cache if you have dynamically added stylesheets
13205 * @return {Object} An object (hash) of rules indexed by selector
13207 refreshCache : function(){
13208 return this.getRules(true);
13212 cacheStyleSheet : function(ss){
13216 try{// try catch for cross domain access issue
13217 var ssRules = ss.cssRules || ss.rules;
13218 for(var j = ssRules.length-1; j >= 0; --j){
13219 rules[ssRules[j].selectorText] = ssRules[j];
13225 * Gets all css rules for the document
13226 * @param {Boolean} refreshCache true to refresh the internal cache
13227 * @return {Object} An object (hash) of rules indexed by selector
13229 getRules : function(refreshCache){
13230 if(rules == null || refreshCache){
13232 var ds = doc.styleSheets;
13233 for(var i =0, len = ds.length; i < len; i++){
13235 this.cacheStyleSheet(ds[i]);
13243 * Gets an an individual CSS rule by selector(s)
13244 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13245 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13246 * @return {CSSRule} The CSS rule or null if one is not found
13248 getRule : function(selector, refreshCache){
13249 var rs = this.getRules(refreshCache);
13250 if(!(selector instanceof Array)){
13251 return rs[selector];
13253 for(var i = 0; i < selector.length; i++){
13254 if(rs[selector[i]]){
13255 return rs[selector[i]];
13263 * Updates a rule property
13264 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13265 * @param {String} property The css property
13266 * @param {String} value The new value for the property
13267 * @return {Boolean} true If a rule was found and updated
13269 updateRule : function(selector, property, value){
13270 if(!(selector instanceof Array)){
13271 var rule = this.getRule(selector);
13273 rule.style[property.replace(camelRe, camelFn)] = value;
13277 for(var i = 0; i < selector.length; i++){
13278 if(this.updateRule(selector[i], property, value)){
13288 * Ext JS Library 1.1.1
13289 * Copyright(c) 2006-2007, Ext JS, LLC.
13291 * Originally Released Under LGPL - original licence link has changed is not relivant.
13294 * <script type="text/javascript">
13300 * @class Roo.util.ClickRepeater
13301 * @extends Roo.util.Observable
13303 * A wrapper class which can be applied to any element. Fires a "click" event while the
13304 * mouse is pressed. The interval between firings may be specified in the config but
13305 * defaults to 10 milliseconds.
13307 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13309 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13310 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13311 * Similar to an autorepeat key delay.
13312 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13313 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13314 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13315 * "interval" and "delay" are ignored. "immediate" is honored.
13316 * @cfg {Boolean} preventDefault True to prevent the default click event
13317 * @cfg {Boolean} stopDefault True to stop the default click event
13320 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13321 * 2007-02-02 jvs Renamed to ClickRepeater
13322 * 2007-02-03 jvs Modifications for FF Mac and Safari
13325 * @param {String/HTMLElement/Element} el The element to listen on
13326 * @param {Object} config
13328 Roo.util.ClickRepeater = function(el, config)
13330 this.el = Roo.get(el);
13331 this.el.unselectable();
13333 Roo.apply(this, config);
13338 * Fires when the mouse button is depressed.
13339 * @param {Roo.util.ClickRepeater} this
13341 "mousedown" : true,
13344 * Fires on a specified interval during the time the element is pressed.
13345 * @param {Roo.util.ClickRepeater} this
13350 * Fires when the mouse key is released.
13351 * @param {Roo.util.ClickRepeater} this
13356 this.el.on("mousedown", this.handleMouseDown, this);
13357 if(this.preventDefault || this.stopDefault){
13358 this.el.on("click", function(e){
13359 if(this.preventDefault){
13360 e.preventDefault();
13362 if(this.stopDefault){
13368 // allow inline handler
13370 this.on("click", this.handler, this.scope || this);
13373 Roo.util.ClickRepeater.superclass.constructor.call(this);
13376 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13379 preventDefault : true,
13380 stopDefault : false,
13384 handleMouseDown : function(){
13385 clearTimeout(this.timer);
13387 if(this.pressClass){
13388 this.el.addClass(this.pressClass);
13390 this.mousedownTime = new Date();
13392 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13393 this.el.on("mouseout", this.handleMouseOut, this);
13395 this.fireEvent("mousedown", this);
13396 this.fireEvent("click", this);
13398 this.timer = this.click.defer(this.delay || this.interval, this);
13402 click : function(){
13403 this.fireEvent("click", this);
13404 this.timer = this.click.defer(this.getInterval(), this);
13408 getInterval: function(){
13409 if(!this.accelerate){
13410 return this.interval;
13412 var pressTime = this.mousedownTime.getElapsed();
13413 if(pressTime < 500){
13415 }else if(pressTime < 1700){
13417 }else if(pressTime < 2600){
13419 }else if(pressTime < 3500){
13421 }else if(pressTime < 4400){
13423 }else if(pressTime < 5300){
13425 }else if(pressTime < 6200){
13433 handleMouseOut : function(){
13434 clearTimeout(this.timer);
13435 if(this.pressClass){
13436 this.el.removeClass(this.pressClass);
13438 this.el.on("mouseover", this.handleMouseReturn, this);
13442 handleMouseReturn : function(){
13443 this.el.un("mouseover", this.handleMouseReturn);
13444 if(this.pressClass){
13445 this.el.addClass(this.pressClass);
13451 handleMouseUp : function(){
13452 clearTimeout(this.timer);
13453 this.el.un("mouseover", this.handleMouseReturn);
13454 this.el.un("mouseout", this.handleMouseOut);
13455 Roo.get(document).un("mouseup", this.handleMouseUp);
13456 this.el.removeClass(this.pressClass);
13457 this.fireEvent("mouseup", this);
13461 * Ext JS Library 1.1.1
13462 * Copyright(c) 2006-2007, Ext JS, LLC.
13464 * Originally Released Under LGPL - original licence link has changed is not relivant.
13467 * <script type="text/javascript">
13472 * @class Roo.KeyNav
13473 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13474 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13475 * way to implement custom navigation schemes for any UI component.</p>
13476 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13477 * pageUp, pageDown, del, home, end. Usage:</p>
13479 var nav = new Roo.KeyNav("my-element", {
13480 "left" : function(e){
13481 this.moveLeft(e.ctrlKey);
13483 "right" : function(e){
13484 this.moveRight(e.ctrlKey);
13486 "enter" : function(e){
13493 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13494 * @param {Object} config The config
13496 Roo.KeyNav = function(el, config){
13497 this.el = Roo.get(el);
13498 Roo.apply(this, config);
13499 if(!this.disabled){
13500 this.disabled = true;
13505 Roo.KeyNav.prototype = {
13507 * @cfg {Boolean} disabled
13508 * True to disable this KeyNav instance (defaults to false)
13512 * @cfg {String} defaultEventAction
13513 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13514 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13515 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13517 defaultEventAction: "stopEvent",
13519 * @cfg {Boolean} forceKeyDown
13520 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13521 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13522 * handle keydown instead of keypress.
13524 forceKeyDown : false,
13527 prepareEvent : function(e){
13528 var k = e.getKey();
13529 var h = this.keyToHandler[k];
13530 //if(h && this[h]){
13531 // e.stopPropagation();
13533 if(Roo.isSafari && h && k >= 37 && k <= 40){
13539 relay : function(e){
13540 var k = e.getKey();
13541 var h = this.keyToHandler[k];
13543 if(this.doRelay(e, this[h], h) !== true){
13544 e[this.defaultEventAction]();
13550 doRelay : function(e, h, hname){
13551 return h.call(this.scope || this, e);
13554 // possible handlers
13568 // quick lookup hash
13585 * Enable this KeyNav
13587 enable: function(){
13589 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13590 // the EventObject will normalize Safari automatically
13591 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13592 this.el.on("keydown", this.relay, this);
13594 this.el.on("keydown", this.prepareEvent, this);
13595 this.el.on("keypress", this.relay, this);
13597 this.disabled = false;
13602 * Disable this KeyNav
13604 disable: function(){
13605 if(!this.disabled){
13606 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13607 this.el.un("keydown", this.relay);
13609 this.el.un("keydown", this.prepareEvent);
13610 this.el.un("keypress", this.relay);
13612 this.disabled = true;
13617 * Ext JS Library 1.1.1
13618 * Copyright(c) 2006-2007, Ext JS, LLC.
13620 * Originally Released Under LGPL - original licence link has changed is not relivant.
13623 * <script type="text/javascript">
13628 * @class Roo.KeyMap
13629 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13630 * The constructor accepts the same config object as defined by {@link #addBinding}.
13631 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13632 * combination it will call the function with this signature (if the match is a multi-key
13633 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13634 * A KeyMap can also handle a string representation of keys.<br />
13637 // map one key by key code
13638 var map = new Roo.KeyMap("my-element", {
13639 key: 13, // or Roo.EventObject.ENTER
13644 // map multiple keys to one action by string
13645 var map = new Roo.KeyMap("my-element", {
13651 // map multiple keys to multiple actions by strings and array of codes
13652 var map = new Roo.KeyMap("my-element", [
13655 fn: function(){ alert("Return was pressed"); }
13658 fn: function(){ alert('a, b or c was pressed'); }
13663 fn: function(){ alert('Control + shift + tab was pressed.'); }
13667 * <b>Note: A KeyMap starts enabled</b>
13669 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13670 * @param {Object} config The config (see {@link #addBinding})
13671 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13673 Roo.KeyMap = function(el, config, eventName){
13674 this.el = Roo.get(el);
13675 this.eventName = eventName || "keydown";
13676 this.bindings = [];
13678 this.addBinding(config);
13683 Roo.KeyMap.prototype = {
13685 * True to stop the event from bubbling and prevent the default browser action if the
13686 * key was handled by the KeyMap (defaults to false)
13692 * Add a new binding to this KeyMap. The following config object properties are supported:
13694 Property Type Description
13695 ---------- --------------- ----------------------------------------------------------------------
13696 key String/Array A single keycode or an array of keycodes to handle
13697 shift Boolean True to handle key only when shift is pressed (defaults to false)
13698 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13699 alt Boolean True to handle key only when alt is pressed (defaults to false)
13700 fn Function The function to call when KeyMap finds the expected key combination
13701 scope Object The scope of the callback function
13707 var map = new Roo.KeyMap(document, {
13708 key: Roo.EventObject.ENTER,
13713 //Add a new binding to the existing KeyMap later
13721 * @param {Object/Array} config A single KeyMap config or an array of configs
13723 addBinding : function(config){
13724 if(config instanceof Array){
13725 for(var i = 0, len = config.length; i < len; i++){
13726 this.addBinding(config[i]);
13730 var keyCode = config.key,
13731 shift = config.shift,
13732 ctrl = config.ctrl,
13735 scope = config.scope;
13736 if(typeof keyCode == "string"){
13738 var keyString = keyCode.toUpperCase();
13739 for(var j = 0, len = keyString.length; j < len; j++){
13740 ks.push(keyString.charCodeAt(j));
13744 var keyArray = keyCode instanceof Array;
13745 var handler = function(e){
13746 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13747 var k = e.getKey();
13749 for(var i = 0, len = keyCode.length; i < len; i++){
13750 if(keyCode[i] == k){
13751 if(this.stopEvent){
13754 fn.call(scope || window, k, e);
13760 if(this.stopEvent){
13763 fn.call(scope || window, k, e);
13768 this.bindings.push(handler);
13772 * Shorthand for adding a single key listener
13773 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13774 * following options:
13775 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13776 * @param {Function} fn The function to call
13777 * @param {Object} scope (optional) The scope of the function
13779 on : function(key, fn, scope){
13780 var keyCode, shift, ctrl, alt;
13781 if(typeof key == "object" && !(key instanceof Array)){
13800 handleKeyDown : function(e){
13801 if(this.enabled){ //just in case
13802 var b = this.bindings;
13803 for(var i = 0, len = b.length; i < len; i++){
13804 b[i].call(this, e);
13810 * Returns true if this KeyMap is enabled
13811 * @return {Boolean}
13813 isEnabled : function(){
13814 return this.enabled;
13818 * Enables this KeyMap
13820 enable: function(){
13822 this.el.on(this.eventName, this.handleKeyDown, this);
13823 this.enabled = true;
13828 * Disable this KeyMap
13830 disable: function(){
13832 this.el.removeListener(this.eventName, this.handleKeyDown, this);
13833 this.enabled = false;
13838 * Ext JS Library 1.1.1
13839 * Copyright(c) 2006-2007, Ext JS, LLC.
13841 * Originally Released Under LGPL - original licence link has changed is not relivant.
13844 * <script type="text/javascript">
13849 * @class Roo.util.TextMetrics
13850 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13851 * wide, in pixels, a given block of text will be.
13854 Roo.util.TextMetrics = function(){
13858 * Measures the size of the specified text
13859 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13860 * that can affect the size of the rendered text
13861 * @param {String} text The text to measure
13862 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13863 * in order to accurately measure the text height
13864 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13866 measure : function(el, text, fixedWidth){
13868 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13871 shared.setFixedWidth(fixedWidth || 'auto');
13872 return shared.getSize(text);
13876 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13877 * the overhead of multiple calls to initialize the style properties on each measurement.
13878 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13879 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13880 * in order to accurately measure the text height
13881 * @return {Roo.util.TextMetrics.Instance} instance The new instance
13883 createInstance : function(el, fixedWidth){
13884 return Roo.util.TextMetrics.Instance(el, fixedWidth);
13891 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13892 var ml = new Roo.Element(document.createElement('div'));
13893 document.body.appendChild(ml.dom);
13894 ml.position('absolute');
13895 ml.setLeftTop(-1000, -1000);
13899 ml.setWidth(fixedWidth);
13904 * Returns the size of the specified text based on the internal element's style and width properties
13905 * @memberOf Roo.util.TextMetrics.Instance#
13906 * @param {String} text The text to measure
13907 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13909 getSize : function(text){
13911 var s = ml.getSize();
13917 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13918 * that can affect the size of the rendered text
13919 * @memberOf Roo.util.TextMetrics.Instance#
13920 * @param {String/HTMLElement} el The element, dom node or id
13922 bind : function(el){
13924 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13929 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
13930 * to set a fixed width in order to accurately measure the text height.
13931 * @memberOf Roo.util.TextMetrics.Instance#
13932 * @param {Number} width The width to set on the element
13934 setFixedWidth : function(width){
13935 ml.setWidth(width);
13939 * Returns the measured width of the specified text
13940 * @memberOf Roo.util.TextMetrics.Instance#
13941 * @param {String} text The text to measure
13942 * @return {Number} width The width in pixels
13944 getWidth : function(text){
13945 ml.dom.style.width = 'auto';
13946 return this.getSize(text).width;
13950 * Returns the measured height of the specified text. For multiline text, be sure to call
13951 * {@link #setFixedWidth} if necessary.
13952 * @memberOf Roo.util.TextMetrics.Instance#
13953 * @param {String} text The text to measure
13954 * @return {Number} height The height in pixels
13956 getHeight : function(text){
13957 return this.getSize(text).height;
13961 instance.bind(bindTo);
13966 // backwards compat
13967 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13969 * Ext JS Library 1.1.1
13970 * Copyright(c) 2006-2007, Ext JS, LLC.
13972 * Originally Released Under LGPL - original licence link has changed is not relivant.
13975 * <script type="text/javascript">
13979 * @class Roo.state.Provider
13980 * Abstract base class for state provider implementations. This class provides methods
13981 * for encoding and decoding <b>typed</b> variables including dates and defines the
13982 * Provider interface.
13984 Roo.state.Provider = function(){
13986 * @event statechange
13987 * Fires when a state change occurs.
13988 * @param {Provider} this This state provider
13989 * @param {String} key The state key which was changed
13990 * @param {String} value The encoded value for the state
13993 "statechange": true
13996 Roo.state.Provider.superclass.constructor.call(this);
13998 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14000 * Returns the current value for a key
14001 * @param {String} name The key name
14002 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14003 * @return {Mixed} The state data
14005 get : function(name, defaultValue){
14006 return typeof this.state[name] == "undefined" ?
14007 defaultValue : this.state[name];
14011 * Clears a value from the state
14012 * @param {String} name The key name
14014 clear : function(name){
14015 delete this.state[name];
14016 this.fireEvent("statechange", this, name, null);
14020 * Sets the value for a key
14021 * @param {String} name The key name
14022 * @param {Mixed} value The value to set
14024 set : function(name, value){
14025 this.state[name] = value;
14026 this.fireEvent("statechange", this, name, value);
14030 * Decodes a string previously encoded with {@link #encodeValue}.
14031 * @param {String} value The value to decode
14032 * @return {Mixed} The decoded value
14034 decodeValue : function(cookie){
14035 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14036 var matches = re.exec(unescape(cookie));
14037 if(!matches || !matches[1]) return; // non state cookie
14038 var type = matches[1];
14039 var v = matches[2];
14042 return parseFloat(v);
14044 return new Date(Date.parse(v));
14049 var values = v.split("^");
14050 for(var i = 0, len = values.length; i < len; i++){
14051 all.push(this.decodeValue(values[i]));
14056 var values = v.split("^");
14057 for(var i = 0, len = values.length; i < len; i++){
14058 var kv = values[i].split("=");
14059 all[kv[0]] = this.decodeValue(kv[1]);
14068 * Encodes a value including type information. Decode with {@link #decodeValue}.
14069 * @param {Mixed} value The value to encode
14070 * @return {String} The encoded value
14072 encodeValue : function(v){
14074 if(typeof v == "number"){
14076 }else if(typeof v == "boolean"){
14077 enc = "b:" + (v ? "1" : "0");
14078 }else if(v instanceof Date){
14079 enc = "d:" + v.toGMTString();
14080 }else if(v instanceof Array){
14082 for(var i = 0, len = v.length; i < len; i++){
14083 flat += this.encodeValue(v[i]);
14084 if(i != len-1) flat += "^";
14087 }else if(typeof v == "object"){
14090 if(typeof v[key] != "function"){
14091 flat += key + "=" + this.encodeValue(v[key]) + "^";
14094 enc = "o:" + flat.substring(0, flat.length-1);
14098 return escape(enc);
14104 * Ext JS Library 1.1.1
14105 * Copyright(c) 2006-2007, Ext JS, LLC.
14107 * Originally Released Under LGPL - original licence link has changed is not relivant.
14110 * <script type="text/javascript">
14113 * @class Roo.state.Manager
14114 * This is the global state manager. By default all components that are "state aware" check this class
14115 * for state information if you don't pass them a custom state provider. In order for this class
14116 * to be useful, it must be initialized with a provider when your application initializes.
14118 // in your initialization function
14120 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14122 // supposed you have a {@link Roo.BorderLayout}
14123 var layout = new Roo.BorderLayout(...);
14124 layout.restoreState();
14125 // or a {Roo.BasicDialog}
14126 var dialog = new Roo.BasicDialog(...);
14127 dialog.restoreState();
14131 Roo.state.Manager = function(){
14132 var provider = new Roo.state.Provider();
14136 * Configures the default state provider for your application
14137 * @param {Provider} stateProvider The state provider to set
14139 setProvider : function(stateProvider){
14140 provider = stateProvider;
14144 * Returns the current value for a key
14145 * @param {String} name The key name
14146 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14147 * @return {Mixed} The state data
14149 get : function(key, defaultValue){
14150 return provider.get(key, defaultValue);
14154 * Sets the value for a key
14155 * @param {String} name The key name
14156 * @param {Mixed} value The state data
14158 set : function(key, value){
14159 provider.set(key, value);
14163 * Clears a value from the state
14164 * @param {String} name The key name
14166 clear : function(key){
14167 provider.clear(key);
14171 * Gets the currently configured state provider
14172 * @return {Provider} The state provider
14174 getProvider : function(){
14181 * Ext JS Library 1.1.1
14182 * Copyright(c) 2006-2007, Ext JS, LLC.
14184 * Originally Released Under LGPL - original licence link has changed is not relivant.
14187 * <script type="text/javascript">
14190 * @class Roo.state.CookieProvider
14191 * @extends Roo.state.Provider
14192 * The default Provider implementation which saves state via cookies.
14195 var cp = new Roo.state.CookieProvider({
14197 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14198 domain: "roojs.com"
14200 Roo.state.Manager.setProvider(cp);
14202 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14203 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14204 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14205 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14206 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14207 * domain the page is running on including the 'www' like 'www.roojs.com')
14208 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14210 * Create a new CookieProvider
14211 * @param {Object} config The configuration object
14213 Roo.state.CookieProvider = function(config){
14214 Roo.state.CookieProvider.superclass.constructor.call(this);
14216 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14217 this.domain = null;
14218 this.secure = false;
14219 Roo.apply(this, config);
14220 this.state = this.readCookies();
14223 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14225 set : function(name, value){
14226 if(typeof value == "undefined" || value === null){
14230 this.setCookie(name, value);
14231 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14235 clear : function(name){
14236 this.clearCookie(name);
14237 Roo.state.CookieProvider.superclass.clear.call(this, name);
14241 readCookies : function(){
14243 var c = document.cookie + ";";
14244 var re = /\s?(.*?)=(.*?);/g;
14246 while((matches = re.exec(c)) != null){
14247 var name = matches[1];
14248 var value = matches[2];
14249 if(name && name.substring(0,3) == "ys-"){
14250 cookies[name.substr(3)] = this.decodeValue(value);
14257 setCookie : function(name, value){
14258 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14259 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14260 ((this.path == null) ? "" : ("; path=" + this.path)) +
14261 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14262 ((this.secure == true) ? "; secure" : "");
14266 clearCookie : function(name){
14267 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14268 ((this.path == null) ? "" : ("; path=" + this.path)) +
14269 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14270 ((this.secure == true) ? "; secure" : "");
14274 * Ext JS Library 1.1.1
14275 * Copyright(c) 2006-2007, Ext JS, LLC.
14277 * Originally Released Under LGPL - original licence link has changed is not relivant.
14280 * <script type="text/javascript">
14286 * These classes are derivatives of the similarly named classes in the YUI Library.
14287 * The original license:
14288 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14289 * Code licensed under the BSD License:
14290 * http://developer.yahoo.net/yui/license.txt
14295 var Event=Roo.EventManager;
14296 var Dom=Roo.lib.Dom;
14299 * @class Roo.dd.DragDrop
14300 * Defines the interface and base operation of items that that can be
14301 * dragged or can be drop targets. It was designed to be extended, overriding
14302 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14303 * Up to three html elements can be associated with a DragDrop instance:
14305 * <li>linked element: the element that is passed into the constructor.
14306 * This is the element which defines the boundaries for interaction with
14307 * other DragDrop objects.</li>
14308 * <li>handle element(s): The drag operation only occurs if the element that
14309 * was clicked matches a handle element. By default this is the linked
14310 * element, but there are times that you will want only a portion of the
14311 * linked element to initiate the drag operation, and the setHandleElId()
14312 * method provides a way to define this.</li>
14313 * <li>drag element: this represents the element that would be moved along
14314 * with the cursor during a drag operation. By default, this is the linked
14315 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14316 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14319 * This class should not be instantiated until the onload event to ensure that
14320 * the associated elements are available.
14321 * The following would define a DragDrop obj that would interact with any
14322 * other DragDrop obj in the "group1" group:
14324 * dd = new Roo.dd.DragDrop("div1", "group1");
14326 * Since none of the event handlers have been implemented, nothing would
14327 * actually happen if you were to run the code above. Normally you would
14328 * override this class or one of the default implementations, but you can
14329 * also override the methods you want on an instance of the class...
14331 * dd.onDragDrop = function(e, id) {
14332 * alert("dd was dropped on " + id);
14336 * @param {String} id of the element that is linked to this instance
14337 * @param {String} sGroup the group of related DragDrop objects
14338 * @param {object} config an object containing configurable attributes
14339 * Valid properties for DragDrop:
14340 * padding, isTarget, maintainOffset, primaryButtonOnly
14342 Roo.dd.DragDrop = function(id, sGroup, config) {
14344 this.init(id, sGroup, config);
14348 Roo.dd.DragDrop.prototype = {
14351 * The id of the element associated with this object. This is what we
14352 * refer to as the "linked element" because the size and position of
14353 * this element is used to determine when the drag and drop objects have
14361 * Configuration attributes passed into the constructor
14368 * The id of the element that will be dragged. By default this is same
14369 * as the linked element , but could be changed to another element. Ex:
14371 * @property dragElId
14378 * the id of the element that initiates the drag operation. By default
14379 * this is the linked element, but could be changed to be a child of this
14380 * element. This lets us do things like only starting the drag when the
14381 * header element within the linked html element is clicked.
14382 * @property handleElId
14389 * An associative array of HTML tags that will be ignored if clicked.
14390 * @property invalidHandleTypes
14391 * @type {string: string}
14393 invalidHandleTypes: null,
14396 * An associative array of ids for elements that will be ignored if clicked
14397 * @property invalidHandleIds
14398 * @type {string: string}
14400 invalidHandleIds: null,
14403 * An indexted array of css class names for elements that will be ignored
14405 * @property invalidHandleClasses
14408 invalidHandleClasses: null,
14411 * The linked element's absolute X position at the time the drag was
14413 * @property startPageX
14420 * The linked element's absolute X position at the time the drag was
14422 * @property startPageY
14429 * The group defines a logical collection of DragDrop objects that are
14430 * related. Instances only get events when interacting with other
14431 * DragDrop object in the same group. This lets us define multiple
14432 * groups using a single DragDrop subclass if we want.
14434 * @type {string: string}
14439 * Individual drag/drop instances can be locked. This will prevent
14440 * onmousedown start drag.
14448 * Lock this instance
14451 lock: function() { this.locked = true; },
14454 * Unlock this instace
14457 unlock: function() { this.locked = false; },
14460 * By default, all insances can be a drop target. This can be disabled by
14461 * setting isTarget to false.
14468 * The padding configured for this drag and drop object for calculating
14469 * the drop zone intersection with this object.
14476 * Cached reference to the linked element
14477 * @property _domRef
14483 * Internal typeof flag
14484 * @property __ygDragDrop
14487 __ygDragDrop: true,
14490 * Set to true when horizontal contraints are applied
14491 * @property constrainX
14498 * Set to true when vertical contraints are applied
14499 * @property constrainY
14506 * The left constraint
14514 * The right constraint
14522 * The up constraint
14531 * The down constraint
14539 * Maintain offsets when we resetconstraints. Set to true when you want
14540 * the position of the element relative to its parent to stay the same
14541 * when the page changes
14543 * @property maintainOffset
14546 maintainOffset: false,
14549 * Array of pixel locations the element will snap to if we specified a
14550 * horizontal graduation/interval. This array is generated automatically
14551 * when you define a tick interval.
14558 * Array of pixel locations the element will snap to if we specified a
14559 * vertical graduation/interval. This array is generated automatically
14560 * when you define a tick interval.
14567 * By default the drag and drop instance will only respond to the primary
14568 * button click (left button for a right-handed mouse). Set to true to
14569 * allow drag and drop to start with any mouse click that is propogated
14571 * @property primaryButtonOnly
14574 primaryButtonOnly: true,
14577 * The availabe property is false until the linked dom element is accessible.
14578 * @property available
14584 * By default, drags can only be initiated if the mousedown occurs in the
14585 * region the linked element is. This is done in part to work around a
14586 * bug in some browsers that mis-report the mousedown if the previous
14587 * mouseup happened outside of the window. This property is set to true
14588 * if outer handles are defined.
14590 * @property hasOuterHandles
14594 hasOuterHandles: false,
14597 * Code that executes immediately before the startDrag event
14598 * @method b4StartDrag
14601 b4StartDrag: function(x, y) { },
14604 * Abstract method called after a drag/drop object is clicked
14605 * and the drag or mousedown time thresholds have beeen met.
14606 * @method startDrag
14607 * @param {int} X click location
14608 * @param {int} Y click location
14610 startDrag: function(x, y) { /* override this */ },
14613 * Code that executes immediately before the onDrag event
14617 b4Drag: function(e) { },
14620 * Abstract method called during the onMouseMove event while dragging an
14623 * @param {Event} e the mousemove event
14625 onDrag: function(e) { /* override this */ },
14628 * Abstract method called when this element fist begins hovering over
14629 * another DragDrop obj
14630 * @method onDragEnter
14631 * @param {Event} e the mousemove event
14632 * @param {String|DragDrop[]} id In POINT mode, the element
14633 * id this is hovering over. In INTERSECT mode, an array of one or more
14634 * dragdrop items being hovered over.
14636 onDragEnter: function(e, id) { /* override this */ },
14639 * Code that executes immediately before the onDragOver event
14640 * @method b4DragOver
14643 b4DragOver: function(e) { },
14646 * Abstract method called when this element is hovering over another
14648 * @method onDragOver
14649 * @param {Event} e the mousemove event
14650 * @param {String|DragDrop[]} id In POINT mode, the element
14651 * id this is hovering over. In INTERSECT mode, an array of dd items
14652 * being hovered over.
14654 onDragOver: function(e, id) { /* override this */ },
14657 * Code that executes immediately before the onDragOut event
14658 * @method b4DragOut
14661 b4DragOut: function(e) { },
14664 * Abstract method called when we are no longer hovering over an element
14665 * @method onDragOut
14666 * @param {Event} e the mousemove event
14667 * @param {String|DragDrop[]} id In POINT mode, the element
14668 * id this was hovering over. In INTERSECT mode, an array of dd items
14669 * that the mouse is no longer over.
14671 onDragOut: function(e, id) { /* override this */ },
14674 * Code that executes immediately before the onDragDrop event
14675 * @method b4DragDrop
14678 b4DragDrop: function(e) { },
14681 * Abstract method called when this item is dropped on another DragDrop
14683 * @method onDragDrop
14684 * @param {Event} e the mouseup event
14685 * @param {String|DragDrop[]} id In POINT mode, the element
14686 * id this was dropped on. In INTERSECT mode, an array of dd items this
14689 onDragDrop: function(e, id) { /* override this */ },
14692 * Abstract method called when this item is dropped on an area with no
14694 * @method onInvalidDrop
14695 * @param {Event} e the mouseup event
14697 onInvalidDrop: function(e) { /* override this */ },
14700 * Code that executes immediately before the endDrag event
14701 * @method b4EndDrag
14704 b4EndDrag: function(e) { },
14707 * Fired when we are done dragging the object
14709 * @param {Event} e the mouseup event
14711 endDrag: function(e) { /* override this */ },
14714 * Code executed immediately before the onMouseDown event
14715 * @method b4MouseDown
14716 * @param {Event} e the mousedown event
14719 b4MouseDown: function(e) { },
14722 * Event handler that fires when a drag/drop obj gets a mousedown
14723 * @method onMouseDown
14724 * @param {Event} e the mousedown event
14726 onMouseDown: function(e) { /* override this */ },
14729 * Event handler that fires when a drag/drop obj gets a mouseup
14730 * @method onMouseUp
14731 * @param {Event} e the mouseup event
14733 onMouseUp: function(e) { /* override this */ },
14736 * Override the onAvailable method to do what is needed after the initial
14737 * position was determined.
14738 * @method onAvailable
14740 onAvailable: function () {
14744 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14747 defaultPadding : {left:0, right:0, top:0, bottom:0},
14750 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14754 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14755 { dragElId: "existingProxyDiv" });
14756 dd.startDrag = function(){
14757 this.constrainTo("parent-id");
14760 * Or you can initalize it using the {@link Roo.Element} object:
14762 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14763 startDrag : function(){
14764 this.constrainTo("parent-id");
14768 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14769 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14770 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14771 * an object containing the sides to pad. For example: {right:10, bottom:10}
14772 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14774 constrainTo : function(constrainTo, pad, inContent){
14775 if(typeof pad == "number"){
14776 pad = {left: pad, right:pad, top:pad, bottom:pad};
14778 pad = pad || this.defaultPadding;
14779 var b = Roo.get(this.getEl()).getBox();
14780 var ce = Roo.get(constrainTo);
14781 var s = ce.getScroll();
14782 var c, cd = ce.dom;
14783 if(cd == document.body){
14784 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14787 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14791 var topSpace = b.y - c.y;
14792 var leftSpace = b.x - c.x;
14794 this.resetConstraints();
14795 this.setXConstraint(leftSpace - (pad.left||0), // left
14796 c.width - leftSpace - b.width - (pad.right||0) //right
14798 this.setYConstraint(topSpace - (pad.top||0), //top
14799 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14804 * Returns a reference to the linked element
14806 * @return {HTMLElement} the html element
14808 getEl: function() {
14809 if (!this._domRef) {
14810 this._domRef = Roo.getDom(this.id);
14813 return this._domRef;
14817 * Returns a reference to the actual element to drag. By default this is
14818 * the same as the html element, but it can be assigned to another
14819 * element. An example of this can be found in Roo.dd.DDProxy
14820 * @method getDragEl
14821 * @return {HTMLElement} the html element
14823 getDragEl: function() {
14824 return Roo.getDom(this.dragElId);
14828 * Sets up the DragDrop object. Must be called in the constructor of any
14829 * Roo.dd.DragDrop subclass
14831 * @param id the id of the linked element
14832 * @param {String} sGroup the group of related items
14833 * @param {object} config configuration attributes
14835 init: function(id, sGroup, config) {
14836 this.initTarget(id, sGroup, config);
14837 Event.on(this.id, "mousedown", this.handleMouseDown, this);
14838 // Event.on(this.id, "selectstart", Event.preventDefault);
14842 * Initializes Targeting functionality only... the object does not
14843 * get a mousedown handler.
14844 * @method initTarget
14845 * @param id the id of the linked element
14846 * @param {String} sGroup the group of related items
14847 * @param {object} config configuration attributes
14849 initTarget: function(id, sGroup, config) {
14851 // configuration attributes
14852 this.config = config || {};
14854 // create a local reference to the drag and drop manager
14855 this.DDM = Roo.dd.DDM;
14856 // initialize the groups array
14859 // assume that we have an element reference instead of an id if the
14860 // parameter is not a string
14861 if (typeof id !== "string") {
14868 // add to an interaction group
14869 this.addToGroup((sGroup) ? sGroup : "default");
14871 // We don't want to register this as the handle with the manager
14872 // so we just set the id rather than calling the setter.
14873 this.handleElId = id;
14875 // the linked element is the element that gets dragged by default
14876 this.setDragElId(id);
14878 // by default, clicked anchors will not start drag operations.
14879 this.invalidHandleTypes = { A: "A" };
14880 this.invalidHandleIds = {};
14881 this.invalidHandleClasses = [];
14883 this.applyConfig();
14885 this.handleOnAvailable();
14889 * Applies the configuration parameters that were passed into the constructor.
14890 * This is supposed to happen at each level through the inheritance chain. So
14891 * a DDProxy implentation will execute apply config on DDProxy, DD, and
14892 * DragDrop in order to get all of the parameters that are available in
14894 * @method applyConfig
14896 applyConfig: function() {
14898 // configurable properties:
14899 // padding, isTarget, maintainOffset, primaryButtonOnly
14900 this.padding = this.config.padding || [0, 0, 0, 0];
14901 this.isTarget = (this.config.isTarget !== false);
14902 this.maintainOffset = (this.config.maintainOffset);
14903 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
14908 * Executed when the linked element is available
14909 * @method handleOnAvailable
14912 handleOnAvailable: function() {
14913 this.available = true;
14914 this.resetConstraints();
14915 this.onAvailable();
14919 * Configures the padding for the target zone in px. Effectively expands
14920 * (or reduces) the virtual object size for targeting calculations.
14921 * Supports css-style shorthand; if only one parameter is passed, all sides
14922 * will have that padding, and if only two are passed, the top and bottom
14923 * will have the first param, the left and right the second.
14924 * @method setPadding
14925 * @param {int} iTop Top pad
14926 * @param {int} iRight Right pad
14927 * @param {int} iBot Bot pad
14928 * @param {int} iLeft Left pad
14930 setPadding: function(iTop, iRight, iBot, iLeft) {
14931 // this.padding = [iLeft, iRight, iTop, iBot];
14932 if (!iRight && 0 !== iRight) {
14933 this.padding = [iTop, iTop, iTop, iTop];
14934 } else if (!iBot && 0 !== iBot) {
14935 this.padding = [iTop, iRight, iTop, iRight];
14937 this.padding = [iTop, iRight, iBot, iLeft];
14942 * Stores the initial placement of the linked element.
14943 * @method setInitialPosition
14944 * @param {int} diffX the X offset, default 0
14945 * @param {int} diffY the Y offset, default 0
14947 setInitPosition: function(diffX, diffY) {
14948 var el = this.getEl();
14950 if (!this.DDM.verifyEl(el)) {
14954 var dx = diffX || 0;
14955 var dy = diffY || 0;
14957 var p = Dom.getXY( el );
14959 this.initPageX = p[0] - dx;
14960 this.initPageY = p[1] - dy;
14962 this.lastPageX = p[0];
14963 this.lastPageY = p[1];
14966 this.setStartPosition(p);
14970 * Sets the start position of the element. This is set when the obj
14971 * is initialized, the reset when a drag is started.
14972 * @method setStartPosition
14973 * @param pos current position (from previous lookup)
14976 setStartPosition: function(pos) {
14977 var p = pos || Dom.getXY( this.getEl() );
14978 this.deltaSetXY = null;
14980 this.startPageX = p[0];
14981 this.startPageY = p[1];
14985 * Add this instance to a group of related drag/drop objects. All
14986 * instances belong to at least one group, and can belong to as many
14987 * groups as needed.
14988 * @method addToGroup
14989 * @param sGroup {string} the name of the group
14991 addToGroup: function(sGroup) {
14992 this.groups[sGroup] = true;
14993 this.DDM.regDragDrop(this, sGroup);
14997 * Remove's this instance from the supplied interaction group
14998 * @method removeFromGroup
14999 * @param {string} sGroup The group to drop
15001 removeFromGroup: function(sGroup) {
15002 if (this.groups[sGroup]) {
15003 delete this.groups[sGroup];
15006 this.DDM.removeDDFromGroup(this, sGroup);
15010 * Allows you to specify that an element other than the linked element
15011 * will be moved with the cursor during a drag
15012 * @method setDragElId
15013 * @param id {string} the id of the element that will be used to initiate the drag
15015 setDragElId: function(id) {
15016 this.dragElId = id;
15020 * Allows you to specify a child of the linked element that should be
15021 * used to initiate the drag operation. An example of this would be if
15022 * you have a content div with text and links. Clicking anywhere in the
15023 * content area would normally start the drag operation. Use this method
15024 * to specify that an element inside of the content div is the element
15025 * that starts the drag operation.
15026 * @method setHandleElId
15027 * @param id {string} the id of the element that will be used to
15028 * initiate the drag.
15030 setHandleElId: function(id) {
15031 if (typeof id !== "string") {
15034 this.handleElId = id;
15035 this.DDM.regHandle(this.id, id);
15039 * Allows you to set an element outside of the linked element as a drag
15041 * @method setOuterHandleElId
15042 * @param id the id of the element that will be used to initiate the drag
15044 setOuterHandleElId: function(id) {
15045 if (typeof id !== "string") {
15048 Event.on(id, "mousedown",
15049 this.handleMouseDown, this);
15050 this.setHandleElId(id);
15052 this.hasOuterHandles = true;
15056 * Remove all drag and drop hooks for this element
15059 unreg: function() {
15060 Event.un(this.id, "mousedown",
15061 this.handleMouseDown);
15062 this._domRef = null;
15063 this.DDM._remove(this);
15066 destroy : function(){
15071 * Returns true if this instance is locked, or the drag drop mgr is locked
15072 * (meaning that all drag/drop is disabled on the page.)
15074 * @return {boolean} true if this obj or all drag/drop is locked, else
15077 isLocked: function() {
15078 return (this.DDM.isLocked() || this.locked);
15082 * Fired when this object is clicked
15083 * @method handleMouseDown
15085 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15088 handleMouseDown: function(e, oDD){
15089 if (this.primaryButtonOnly && e.button != 0) {
15093 if (this.isLocked()) {
15097 this.DDM.refreshCache(this.groups);
15099 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15100 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15102 if (this.clickValidator(e)) {
15104 // set the initial element position
15105 this.setStartPosition();
15108 this.b4MouseDown(e);
15109 this.onMouseDown(e);
15111 this.DDM.handleMouseDown(e, this);
15113 this.DDM.stopEvent(e);
15121 clickValidator: function(e) {
15122 var target = e.getTarget();
15123 return ( this.isValidHandleChild(target) &&
15124 (this.id == this.handleElId ||
15125 this.DDM.handleWasClicked(target, this.id)) );
15129 * Allows you to specify a tag name that should not start a drag operation
15130 * when clicked. This is designed to facilitate embedding links within a
15131 * drag handle that do something other than start the drag.
15132 * @method addInvalidHandleType
15133 * @param {string} tagName the type of element to exclude
15135 addInvalidHandleType: function(tagName) {
15136 var type = tagName.toUpperCase();
15137 this.invalidHandleTypes[type] = type;
15141 * Lets you to specify an element id for a child of a drag handle
15142 * that should not initiate a drag
15143 * @method addInvalidHandleId
15144 * @param {string} id the element id of the element you wish to ignore
15146 addInvalidHandleId: function(id) {
15147 if (typeof id !== "string") {
15150 this.invalidHandleIds[id] = id;
15154 * Lets you specify a css class of elements that will not initiate a drag
15155 * @method addInvalidHandleClass
15156 * @param {string} cssClass the class of the elements you wish to ignore
15158 addInvalidHandleClass: function(cssClass) {
15159 this.invalidHandleClasses.push(cssClass);
15163 * Unsets an excluded tag name set by addInvalidHandleType
15164 * @method removeInvalidHandleType
15165 * @param {string} tagName the type of element to unexclude
15167 removeInvalidHandleType: function(tagName) {
15168 var type = tagName.toUpperCase();
15169 // this.invalidHandleTypes[type] = null;
15170 delete this.invalidHandleTypes[type];
15174 * Unsets an invalid handle id
15175 * @method removeInvalidHandleId
15176 * @param {string} id the id of the element to re-enable
15178 removeInvalidHandleId: function(id) {
15179 if (typeof id !== "string") {
15182 delete this.invalidHandleIds[id];
15186 * Unsets an invalid css class
15187 * @method removeInvalidHandleClass
15188 * @param {string} cssClass the class of the element(s) you wish to
15191 removeInvalidHandleClass: function(cssClass) {
15192 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15193 if (this.invalidHandleClasses[i] == cssClass) {
15194 delete this.invalidHandleClasses[i];
15200 * Checks the tag exclusion list to see if this click should be ignored
15201 * @method isValidHandleChild
15202 * @param {HTMLElement} node the HTMLElement to evaluate
15203 * @return {boolean} true if this is a valid tag type, false if not
15205 isValidHandleChild: function(node) {
15208 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15211 nodeName = node.nodeName.toUpperCase();
15213 nodeName = node.nodeName;
15215 valid = valid && !this.invalidHandleTypes[nodeName];
15216 valid = valid && !this.invalidHandleIds[node.id];
15218 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15219 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15228 * Create the array of horizontal tick marks if an interval was specified
15229 * in setXConstraint().
15230 * @method setXTicks
15233 setXTicks: function(iStartX, iTickSize) {
15235 this.xTickSize = iTickSize;
15239 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15241 this.xTicks[this.xTicks.length] = i;
15246 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15248 this.xTicks[this.xTicks.length] = i;
15253 this.xTicks.sort(this.DDM.numericSort) ;
15257 * Create the array of vertical tick marks if an interval was specified in
15258 * setYConstraint().
15259 * @method setYTicks
15262 setYTicks: function(iStartY, iTickSize) {
15264 this.yTickSize = iTickSize;
15268 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15270 this.yTicks[this.yTicks.length] = i;
15275 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15277 this.yTicks[this.yTicks.length] = i;
15282 this.yTicks.sort(this.DDM.numericSort) ;
15286 * By default, the element can be dragged any place on the screen. Use
15287 * this method to limit the horizontal travel of the element. Pass in
15288 * 0,0 for the parameters if you want to lock the drag to the y axis.
15289 * @method setXConstraint
15290 * @param {int} iLeft the number of pixels the element can move to the left
15291 * @param {int} iRight the number of pixels the element can move to the
15293 * @param {int} iTickSize optional parameter for specifying that the
15295 * should move iTickSize pixels at a time.
15297 setXConstraint: function(iLeft, iRight, iTickSize) {
15298 this.leftConstraint = iLeft;
15299 this.rightConstraint = iRight;
15301 this.minX = this.initPageX - iLeft;
15302 this.maxX = this.initPageX + iRight;
15303 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15305 this.constrainX = true;
15309 * Clears any constraints applied to this instance. Also clears ticks
15310 * since they can't exist independent of a constraint at this time.
15311 * @method clearConstraints
15313 clearConstraints: function() {
15314 this.constrainX = false;
15315 this.constrainY = false;
15320 * Clears any tick interval defined for this instance
15321 * @method clearTicks
15323 clearTicks: function() {
15324 this.xTicks = null;
15325 this.yTicks = null;
15326 this.xTickSize = 0;
15327 this.yTickSize = 0;
15331 * By default, the element can be dragged any place on the screen. Set
15332 * this to limit the vertical travel of the element. Pass in 0,0 for the
15333 * parameters if you want to lock the drag to the x axis.
15334 * @method setYConstraint
15335 * @param {int} iUp the number of pixels the element can move up
15336 * @param {int} iDown the number of pixels the element can move down
15337 * @param {int} iTickSize optional parameter for specifying that the
15338 * element should move iTickSize pixels at a time.
15340 setYConstraint: function(iUp, iDown, iTickSize) {
15341 this.topConstraint = iUp;
15342 this.bottomConstraint = iDown;
15344 this.minY = this.initPageY - iUp;
15345 this.maxY = this.initPageY + iDown;
15346 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15348 this.constrainY = true;
15353 * resetConstraints must be called if you manually reposition a dd element.
15354 * @method resetConstraints
15355 * @param {boolean} maintainOffset
15357 resetConstraints: function() {
15360 // Maintain offsets if necessary
15361 if (this.initPageX || this.initPageX === 0) {
15362 // figure out how much this thing has moved
15363 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15364 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15366 this.setInitPosition(dx, dy);
15368 // This is the first time we have detected the element's position
15370 this.setInitPosition();
15373 if (this.constrainX) {
15374 this.setXConstraint( this.leftConstraint,
15375 this.rightConstraint,
15379 if (this.constrainY) {
15380 this.setYConstraint( this.topConstraint,
15381 this.bottomConstraint,
15387 * Normally the drag element is moved pixel by pixel, but we can specify
15388 * that it move a number of pixels at a time. This method resolves the
15389 * location when we have it set up like this.
15391 * @param {int} val where we want to place the object
15392 * @param {int[]} tickArray sorted array of valid points
15393 * @return {int} the closest tick
15396 getTick: function(val, tickArray) {
15399 // If tick interval is not defined, it is effectively 1 pixel,
15400 // so we return the value passed to us.
15402 } else if (tickArray[0] >= val) {
15403 // The value is lower than the first tick, so we return the first
15405 return tickArray[0];
15407 for (var i=0, len=tickArray.length; i<len; ++i) {
15409 if (tickArray[next] && tickArray[next] >= val) {
15410 var diff1 = val - tickArray[i];
15411 var diff2 = tickArray[next] - val;
15412 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15416 // The value is larger than the last tick, so we return the last
15418 return tickArray[tickArray.length - 1];
15425 * @return {string} string representation of the dd obj
15427 toString: function() {
15428 return ("DragDrop " + this.id);
15436 * Ext JS Library 1.1.1
15437 * Copyright(c) 2006-2007, Ext JS, LLC.
15439 * Originally Released Under LGPL - original licence link has changed is not relivant.
15442 * <script type="text/javascript">
15447 * The drag and drop utility provides a framework for building drag and drop
15448 * applications. In addition to enabling drag and drop for specific elements,
15449 * the drag and drop elements are tracked by the manager class, and the
15450 * interactions between the various elements are tracked during the drag and
15451 * the implementing code is notified about these important moments.
15454 // Only load the library once. Rewriting the manager class would orphan
15455 // existing drag and drop instances.
15456 if (!Roo.dd.DragDropMgr) {
15459 * @class Roo.dd.DragDropMgr
15460 * DragDropMgr is a singleton that tracks the element interaction for
15461 * all DragDrop items in the window. Generally, you will not call
15462 * this class directly, but it does have helper methods that could
15463 * be useful in your DragDrop implementations.
15466 Roo.dd.DragDropMgr = function() {
15468 var Event = Roo.EventManager;
15473 * Two dimensional Array of registered DragDrop objects. The first
15474 * dimension is the DragDrop item group, the second the DragDrop
15477 * @type {string: string}
15484 * Array of element ids defined as drag handles. Used to determine
15485 * if the element that generated the mousedown event is actually the
15486 * handle and not the html element itself.
15487 * @property handleIds
15488 * @type {string: string}
15495 * the DragDrop object that is currently being dragged
15496 * @property dragCurrent
15504 * the DragDrop object(s) that are being hovered over
15505 * @property dragOvers
15513 * the X distance between the cursor and the object being dragged
15522 * the Y distance between the cursor and the object being dragged
15531 * Flag to determine if we should prevent the default behavior of the
15532 * events we define. By default this is true, but this can be set to
15533 * false if you need the default behavior (not recommended)
15534 * @property preventDefault
15538 preventDefault: true,
15541 * Flag to determine if we should stop the propagation of the events
15542 * we generate. This is true by default but you may want to set it to
15543 * false if the html element contains other features that require the
15545 * @property stopPropagation
15549 stopPropagation: true,
15552 * Internal flag that is set to true when drag and drop has been
15554 * @property initialized
15561 * All drag and drop can be disabled.
15569 * Called the first time an element is registered.
15575 this.initialized = true;
15579 * In point mode, drag and drop interaction is defined by the
15580 * location of the cursor during the drag/drop
15588 * In intersect mode, drag and drop interactio nis defined by the
15589 * overlap of two or more drag and drop objects.
15590 * @property INTERSECT
15597 * The current drag and drop mode. Default: POINT
15605 * Runs method on all drag and drop objects
15606 * @method _execOnAll
15610 _execOnAll: function(sMethod, args) {
15611 for (var i in this.ids) {
15612 for (var j in this.ids[i]) {
15613 var oDD = this.ids[i][j];
15614 if (! this.isTypeOfDD(oDD)) {
15617 oDD[sMethod].apply(oDD, args);
15623 * Drag and drop initialization. Sets up the global event handlers
15628 _onLoad: function() {
15633 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15634 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15635 Event.on(window, "unload", this._onUnload, this, true);
15636 Event.on(window, "resize", this._onResize, this, true);
15637 // Event.on(window, "mouseout", this._test);
15642 * Reset constraints on all drag and drop objs
15643 * @method _onResize
15647 _onResize: function(e) {
15648 this._execOnAll("resetConstraints", []);
15652 * Lock all drag and drop functionality
15656 lock: function() { this.locked = true; },
15659 * Unlock all drag and drop functionality
15663 unlock: function() { this.locked = false; },
15666 * Is drag and drop locked?
15668 * @return {boolean} True if drag and drop is locked, false otherwise.
15671 isLocked: function() { return this.locked; },
15674 * Location cache that is set for all drag drop objects when a drag is
15675 * initiated, cleared when the drag is finished.
15676 * @property locationCache
15683 * Set useCache to false if you want to force object the lookup of each
15684 * drag and drop linked element constantly during a drag.
15685 * @property useCache
15692 * The number of pixels that the mouse needs to move after the
15693 * mousedown before the drag is initiated. Default=3;
15694 * @property clickPixelThresh
15698 clickPixelThresh: 3,
15701 * The number of milliseconds after the mousedown event to initiate the
15702 * drag if we don't get a mouseup event. Default=1000
15703 * @property clickTimeThresh
15707 clickTimeThresh: 350,
15710 * Flag that indicates that either the drag pixel threshold or the
15711 * mousdown time threshold has been met
15712 * @property dragThreshMet
15717 dragThreshMet: false,
15720 * Timeout used for the click time threshold
15721 * @property clickTimeout
15726 clickTimeout: null,
15729 * The X position of the mousedown event stored for later use when a
15730 * drag threshold is met.
15739 * The Y position of the mousedown event stored for later use when a
15740 * drag threshold is met.
15749 * Each DragDrop instance must be registered with the DragDropMgr.
15750 * This is executed in DragDrop.init()
15751 * @method regDragDrop
15752 * @param {DragDrop} oDD the DragDrop object to register
15753 * @param {String} sGroup the name of the group this element belongs to
15756 regDragDrop: function(oDD, sGroup) {
15757 if (!this.initialized) { this.init(); }
15759 if (!this.ids[sGroup]) {
15760 this.ids[sGroup] = {};
15762 this.ids[sGroup][oDD.id] = oDD;
15766 * Removes the supplied dd instance from the supplied group. Executed
15767 * by DragDrop.removeFromGroup, so don't call this function directly.
15768 * @method removeDDFromGroup
15772 removeDDFromGroup: function(oDD, sGroup) {
15773 if (!this.ids[sGroup]) {
15774 this.ids[sGroup] = {};
15777 var obj = this.ids[sGroup];
15778 if (obj && obj[oDD.id]) {
15779 delete obj[oDD.id];
15784 * Unregisters a drag and drop item. This is executed in
15785 * DragDrop.unreg, use that method instead of calling this directly.
15790 _remove: function(oDD) {
15791 for (var g in oDD.groups) {
15792 if (g && this.ids[g][oDD.id]) {
15793 delete this.ids[g][oDD.id];
15796 delete this.handleIds[oDD.id];
15800 * Each DragDrop handle element must be registered. This is done
15801 * automatically when executing DragDrop.setHandleElId()
15802 * @method regHandle
15803 * @param {String} sDDId the DragDrop id this element is a handle for
15804 * @param {String} sHandleId the id of the element that is the drag
15808 regHandle: function(sDDId, sHandleId) {
15809 if (!this.handleIds[sDDId]) {
15810 this.handleIds[sDDId] = {};
15812 this.handleIds[sDDId][sHandleId] = sHandleId;
15816 * Utility function to determine if a given element has been
15817 * registered as a drag drop item.
15818 * @method isDragDrop
15819 * @param {String} id the element id to check
15820 * @return {boolean} true if this element is a DragDrop item,
15824 isDragDrop: function(id) {
15825 return ( this.getDDById(id) ) ? true : false;
15829 * Returns the drag and drop instances that are in all groups the
15830 * passed in instance belongs to.
15831 * @method getRelated
15832 * @param {DragDrop} p_oDD the obj to get related data for
15833 * @param {boolean} bTargetsOnly if true, only return targetable objs
15834 * @return {DragDrop[]} the related instances
15837 getRelated: function(p_oDD, bTargetsOnly) {
15839 for (var i in p_oDD.groups) {
15840 for (j in this.ids[i]) {
15841 var dd = this.ids[i][j];
15842 if (! this.isTypeOfDD(dd)) {
15845 if (!bTargetsOnly || dd.isTarget) {
15846 oDDs[oDDs.length] = dd;
15855 * Returns true if the specified dd target is a legal target for
15856 * the specifice drag obj
15857 * @method isLegalTarget
15858 * @param {DragDrop} the drag obj
15859 * @param {DragDrop} the target
15860 * @return {boolean} true if the target is a legal target for the
15864 isLegalTarget: function (oDD, oTargetDD) {
15865 var targets = this.getRelated(oDD, true);
15866 for (var i=0, len=targets.length;i<len;++i) {
15867 if (targets[i].id == oTargetDD.id) {
15876 * My goal is to be able to transparently determine if an object is
15877 * typeof DragDrop, and the exact subclass of DragDrop. typeof
15878 * returns "object", oDD.constructor.toString() always returns
15879 * "DragDrop" and not the name of the subclass. So for now it just
15880 * evaluates a well-known variable in DragDrop.
15881 * @method isTypeOfDD
15882 * @param {Object} the object to evaluate
15883 * @return {boolean} true if typeof oDD = DragDrop
15886 isTypeOfDD: function (oDD) {
15887 return (oDD && oDD.__ygDragDrop);
15891 * Utility function to determine if a given element has been
15892 * registered as a drag drop handle for the given Drag Drop object.
15894 * @param {String} id the element id to check
15895 * @return {boolean} true if this element is a DragDrop handle, false
15899 isHandle: function(sDDId, sHandleId) {
15900 return ( this.handleIds[sDDId] &&
15901 this.handleIds[sDDId][sHandleId] );
15905 * Returns the DragDrop instance for a given id
15906 * @method getDDById
15907 * @param {String} id the id of the DragDrop object
15908 * @return {DragDrop} the drag drop object, null if it is not found
15911 getDDById: function(id) {
15912 for (var i in this.ids) {
15913 if (this.ids[i][id]) {
15914 return this.ids[i][id];
15921 * Fired after a registered DragDrop object gets the mousedown event.
15922 * Sets up the events required to track the object being dragged
15923 * @method handleMouseDown
15924 * @param {Event} e the event
15925 * @param oDD the DragDrop object being dragged
15929 handleMouseDown: function(e, oDD) {
15931 Roo.QuickTips.disable();
15933 this.currentTarget = e.getTarget();
15935 this.dragCurrent = oDD;
15937 var el = oDD.getEl();
15939 // track start position
15940 this.startX = e.getPageX();
15941 this.startY = e.getPageY();
15943 this.deltaX = this.startX - el.offsetLeft;
15944 this.deltaY = this.startY - el.offsetTop;
15946 this.dragThreshMet = false;
15948 this.clickTimeout = setTimeout(
15950 var DDM = Roo.dd.DDM;
15951 DDM.startDrag(DDM.startX, DDM.startY);
15953 this.clickTimeThresh );
15957 * Fired when either the drag pixel threshol or the mousedown hold
15958 * time threshold has been met.
15959 * @method startDrag
15960 * @param x {int} the X position of the original mousedown
15961 * @param y {int} the Y position of the original mousedown
15964 startDrag: function(x, y) {
15965 clearTimeout(this.clickTimeout);
15966 if (this.dragCurrent) {
15967 this.dragCurrent.b4StartDrag(x, y);
15968 this.dragCurrent.startDrag(x, y);
15970 this.dragThreshMet = true;
15974 * Internal function to handle the mouseup event. Will be invoked
15975 * from the context of the document.
15976 * @method handleMouseUp
15977 * @param {Event} e the event
15981 handleMouseUp: function(e) {
15984 Roo.QuickTips.enable();
15986 if (! this.dragCurrent) {
15990 clearTimeout(this.clickTimeout);
15992 if (this.dragThreshMet) {
15993 this.fireEvents(e, true);
16003 * Utility to stop event propagation and event default, if these
16004 * features are turned on.
16005 * @method stopEvent
16006 * @param {Event} e the event as returned by this.getEvent()
16009 stopEvent: function(e){
16010 if(this.stopPropagation) {
16011 e.stopPropagation();
16014 if (this.preventDefault) {
16015 e.preventDefault();
16020 * Internal function to clean up event handlers after the drag
16021 * operation is complete
16023 * @param {Event} e the event
16027 stopDrag: function(e) {
16028 // Fire the drag end event for the item that was dragged
16029 if (this.dragCurrent) {
16030 if (this.dragThreshMet) {
16031 this.dragCurrent.b4EndDrag(e);
16032 this.dragCurrent.endDrag(e);
16035 this.dragCurrent.onMouseUp(e);
16038 this.dragCurrent = null;
16039 this.dragOvers = {};
16043 * Internal function to handle the mousemove event. Will be invoked
16044 * from the context of the html element.
16046 * @TODO figure out what we can do about mouse events lost when the
16047 * user drags objects beyond the window boundary. Currently we can
16048 * detect this in internet explorer by verifying that the mouse is
16049 * down during the mousemove event. Firefox doesn't give us the
16050 * button state on the mousemove event.
16051 * @method handleMouseMove
16052 * @param {Event} e the event
16056 handleMouseMove: function(e) {
16057 if (! this.dragCurrent) {
16061 // var button = e.which || e.button;
16063 // check for IE mouseup outside of page boundary
16064 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16066 return this.handleMouseUp(e);
16069 if (!this.dragThreshMet) {
16070 var diffX = Math.abs(this.startX - e.getPageX());
16071 var diffY = Math.abs(this.startY - e.getPageY());
16072 if (diffX > this.clickPixelThresh ||
16073 diffY > this.clickPixelThresh) {
16074 this.startDrag(this.startX, this.startY);
16078 if (this.dragThreshMet) {
16079 this.dragCurrent.b4Drag(e);
16080 this.dragCurrent.onDrag(e);
16081 if(!this.dragCurrent.moveOnly){
16082 this.fireEvents(e, false);
16092 * Iterates over all of the DragDrop elements to find ones we are
16093 * hovering over or dropping on
16094 * @method fireEvents
16095 * @param {Event} e the event
16096 * @param {boolean} isDrop is this a drop op or a mouseover op?
16100 fireEvents: function(e, isDrop) {
16101 var dc = this.dragCurrent;
16103 // If the user did the mouse up outside of the window, we could
16104 // get here even though we have ended the drag.
16105 if (!dc || dc.isLocked()) {
16109 var pt = e.getPoint();
16111 // cache the previous dragOver array
16117 var enterEvts = [];
16119 // Check to see if the object(s) we were hovering over is no longer
16120 // being hovered over so we can fire the onDragOut event
16121 for (var i in this.dragOvers) {
16123 var ddo = this.dragOvers[i];
16125 if (! this.isTypeOfDD(ddo)) {
16129 if (! this.isOverTarget(pt, ddo, this.mode)) {
16130 outEvts.push( ddo );
16133 oldOvers[i] = true;
16134 delete this.dragOvers[i];
16137 for (var sGroup in dc.groups) {
16139 if ("string" != typeof sGroup) {
16143 for (i in this.ids[sGroup]) {
16144 var oDD = this.ids[sGroup][i];
16145 if (! this.isTypeOfDD(oDD)) {
16149 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16150 if (this.isOverTarget(pt, oDD, this.mode)) {
16151 // look for drop interactions
16153 dropEvts.push( oDD );
16154 // look for drag enter and drag over interactions
16157 // initial drag over: dragEnter fires
16158 if (!oldOvers[oDD.id]) {
16159 enterEvts.push( oDD );
16160 // subsequent drag overs: dragOver fires
16162 overEvts.push( oDD );
16165 this.dragOvers[oDD.id] = oDD;
16173 if (outEvts.length) {
16174 dc.b4DragOut(e, outEvts);
16175 dc.onDragOut(e, outEvts);
16178 if (enterEvts.length) {
16179 dc.onDragEnter(e, enterEvts);
16182 if (overEvts.length) {
16183 dc.b4DragOver(e, overEvts);
16184 dc.onDragOver(e, overEvts);
16187 if (dropEvts.length) {
16188 dc.b4DragDrop(e, dropEvts);
16189 dc.onDragDrop(e, dropEvts);
16193 // fire dragout events
16195 for (i=0, len=outEvts.length; i<len; ++i) {
16196 dc.b4DragOut(e, outEvts[i].id);
16197 dc.onDragOut(e, outEvts[i].id);
16200 // fire enter events
16201 for (i=0,len=enterEvts.length; i<len; ++i) {
16202 // dc.b4DragEnter(e, oDD.id);
16203 dc.onDragEnter(e, enterEvts[i].id);
16206 // fire over events
16207 for (i=0,len=overEvts.length; i<len; ++i) {
16208 dc.b4DragOver(e, overEvts[i].id);
16209 dc.onDragOver(e, overEvts[i].id);
16212 // fire drop events
16213 for (i=0, len=dropEvts.length; i<len; ++i) {
16214 dc.b4DragDrop(e, dropEvts[i].id);
16215 dc.onDragDrop(e, dropEvts[i].id);
16220 // notify about a drop that did not find a target
16221 if (isDrop && !dropEvts.length) {
16222 dc.onInvalidDrop(e);
16228 * Helper function for getting the best match from the list of drag
16229 * and drop objects returned by the drag and drop events when we are
16230 * in INTERSECT mode. It returns either the first object that the
16231 * cursor is over, or the object that has the greatest overlap with
16232 * the dragged element.
16233 * @method getBestMatch
16234 * @param {DragDrop[]} dds The array of drag and drop objects
16236 * @return {DragDrop} The best single match
16239 getBestMatch: function(dds) {
16241 // Return null if the input is not what we expect
16242 //if (!dds || !dds.length || dds.length == 0) {
16244 // If there is only one item, it wins
16245 //} else if (dds.length == 1) {
16247 var len = dds.length;
16252 // Loop through the targeted items
16253 for (var i=0; i<len; ++i) {
16255 // If the cursor is over the object, it wins. If the
16256 // cursor is over multiple matches, the first one we come
16258 if (dd.cursorIsOver) {
16261 // Otherwise the object with the most overlap wins
16264 winner.overlap.getArea() < dd.overlap.getArea()) {
16275 * Refreshes the cache of the top-left and bottom-right points of the
16276 * drag and drop objects in the specified group(s). This is in the
16277 * format that is stored in the drag and drop instance, so typical
16280 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16284 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16286 * @TODO this really should be an indexed array. Alternatively this
16287 * method could accept both.
16288 * @method refreshCache
16289 * @param {Object} groups an associative array of groups to refresh
16292 refreshCache: function(groups) {
16293 for (var sGroup in groups) {
16294 if ("string" != typeof sGroup) {
16297 for (var i in this.ids[sGroup]) {
16298 var oDD = this.ids[sGroup][i];
16300 if (this.isTypeOfDD(oDD)) {
16301 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16302 var loc = this.getLocation(oDD);
16304 this.locationCache[oDD.id] = loc;
16306 delete this.locationCache[oDD.id];
16307 // this will unregister the drag and drop object if
16308 // the element is not in a usable state
16317 * This checks to make sure an element exists and is in the DOM. The
16318 * main purpose is to handle cases where innerHTML is used to remove
16319 * drag and drop objects from the DOM. IE provides an 'unspecified
16320 * error' when trying to access the offsetParent of such an element
16322 * @param {HTMLElement} el the element to check
16323 * @return {boolean} true if the element looks usable
16326 verifyEl: function(el) {
16331 parent = el.offsetParent;
16334 parent = el.offsetParent;
16345 * Returns a Region object containing the drag and drop element's position
16346 * and size, including the padding configured for it
16347 * @method getLocation
16348 * @param {DragDrop} oDD the drag and drop object to get the
16350 * @return {Roo.lib.Region} a Region object representing the total area
16351 * the element occupies, including any padding
16352 * the instance is configured for.
16355 getLocation: function(oDD) {
16356 if (! this.isTypeOfDD(oDD)) {
16360 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16363 pos= Roo.lib.Dom.getXY(el);
16371 x2 = x1 + el.offsetWidth;
16373 y2 = y1 + el.offsetHeight;
16375 t = y1 - oDD.padding[0];
16376 r = x2 + oDD.padding[1];
16377 b = y2 + oDD.padding[2];
16378 l = x1 - oDD.padding[3];
16380 return new Roo.lib.Region( t, r, b, l );
16384 * Checks the cursor location to see if it over the target
16385 * @method isOverTarget
16386 * @param {Roo.lib.Point} pt The point to evaluate
16387 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16388 * @return {boolean} true if the mouse is over the target
16392 isOverTarget: function(pt, oTarget, intersect) {
16393 // use cache if available
16394 var loc = this.locationCache[oTarget.id];
16395 if (!loc || !this.useCache) {
16396 loc = this.getLocation(oTarget);
16397 this.locationCache[oTarget.id] = loc;
16405 oTarget.cursorIsOver = loc.contains( pt );
16407 // DragDrop is using this as a sanity check for the initial mousedown
16408 // in this case we are done. In POINT mode, if the drag obj has no
16409 // contraints, we are also done. Otherwise we need to evaluate the
16410 // location of the target as related to the actual location of the
16411 // dragged element.
16412 var dc = this.dragCurrent;
16413 if (!dc || !dc.getTargetCoord ||
16414 (!intersect && !dc.constrainX && !dc.constrainY)) {
16415 return oTarget.cursorIsOver;
16418 oTarget.overlap = null;
16420 // Get the current location of the drag element, this is the
16421 // location of the mouse event less the delta that represents
16422 // where the original mousedown happened on the element. We
16423 // need to consider constraints and ticks as well.
16424 var pos = dc.getTargetCoord(pt.x, pt.y);
16426 var el = dc.getDragEl();
16427 var curRegion = new Roo.lib.Region( pos.y,
16428 pos.x + el.offsetWidth,
16429 pos.y + el.offsetHeight,
16432 var overlap = curRegion.intersect(loc);
16435 oTarget.overlap = overlap;
16436 return (intersect) ? true : oTarget.cursorIsOver;
16443 * unload event handler
16444 * @method _onUnload
16448 _onUnload: function(e, me) {
16449 Roo.dd.DragDropMgr.unregAll();
16453 * Cleans up the drag and drop events and objects.
16458 unregAll: function() {
16460 if (this.dragCurrent) {
16462 this.dragCurrent = null;
16465 this._execOnAll("unreg", []);
16467 for (i in this.elementCache) {
16468 delete this.elementCache[i];
16471 this.elementCache = {};
16476 * A cache of DOM elements
16477 * @property elementCache
16484 * Get the wrapper for the DOM element specified
16485 * @method getElWrapper
16486 * @param {String} id the id of the element to get
16487 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16489 * @deprecated This wrapper isn't that useful
16492 getElWrapper: function(id) {
16493 var oWrapper = this.elementCache[id];
16494 if (!oWrapper || !oWrapper.el) {
16495 oWrapper = this.elementCache[id] =
16496 new this.ElementWrapper(Roo.getDom(id));
16502 * Returns the actual DOM element
16503 * @method getElement
16504 * @param {String} id the id of the elment to get
16505 * @return {Object} The element
16506 * @deprecated use Roo.getDom instead
16509 getElement: function(id) {
16510 return Roo.getDom(id);
16514 * Returns the style property for the DOM element (i.e.,
16515 * document.getElById(id).style)
16517 * @param {String} id the id of the elment to get
16518 * @return {Object} The style property of the element
16519 * @deprecated use Roo.getDom instead
16522 getCss: function(id) {
16523 var el = Roo.getDom(id);
16524 return (el) ? el.style : null;
16528 * Inner class for cached elements
16529 * @class DragDropMgr.ElementWrapper
16534 ElementWrapper: function(el) {
16539 this.el = el || null;
16544 this.id = this.el && el.id;
16546 * A reference to the style property
16549 this.css = this.el && el.style;
16553 * Returns the X position of an html element
16555 * @param el the element for which to get the position
16556 * @return {int} the X coordinate
16558 * @deprecated use Roo.lib.Dom.getX instead
16561 getPosX: function(el) {
16562 return Roo.lib.Dom.getX(el);
16566 * Returns the Y position of an html element
16568 * @param el the element for which to get the position
16569 * @return {int} the Y coordinate
16570 * @deprecated use Roo.lib.Dom.getY instead
16573 getPosY: function(el) {
16574 return Roo.lib.Dom.getY(el);
16578 * Swap two nodes. In IE, we use the native method, for others we
16579 * emulate the IE behavior
16581 * @param n1 the first node to swap
16582 * @param n2 the other node to swap
16585 swapNode: function(n1, n2) {
16589 var p = n2.parentNode;
16590 var s = n2.nextSibling;
16593 p.insertBefore(n1, n2);
16594 } else if (n2 == n1.nextSibling) {
16595 p.insertBefore(n2, n1);
16597 n1.parentNode.replaceChild(n2, n1);
16598 p.insertBefore(n1, s);
16604 * Returns the current scroll position
16605 * @method getScroll
16609 getScroll: function () {
16610 var t, l, dde=document.documentElement, db=document.body;
16611 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16613 l = dde.scrollLeft;
16620 return { top: t, left: l };
16624 * Returns the specified element style property
16626 * @param {HTMLElement} el the element
16627 * @param {string} styleProp the style property
16628 * @return {string} The value of the style property
16629 * @deprecated use Roo.lib.Dom.getStyle
16632 getStyle: function(el, styleProp) {
16633 return Roo.fly(el).getStyle(styleProp);
16637 * Gets the scrollTop
16638 * @method getScrollTop
16639 * @return {int} the document's scrollTop
16642 getScrollTop: function () { return this.getScroll().top; },
16645 * Gets the scrollLeft
16646 * @method getScrollLeft
16647 * @return {int} the document's scrollTop
16650 getScrollLeft: function () { return this.getScroll().left; },
16653 * Sets the x/y position of an element to the location of the
16656 * @param {HTMLElement} moveEl The element to move
16657 * @param {HTMLElement} targetEl The position reference element
16660 moveToEl: function (moveEl, targetEl) {
16661 var aCoord = Roo.lib.Dom.getXY(targetEl);
16662 Roo.lib.Dom.setXY(moveEl, aCoord);
16666 * Numeric array sort function
16667 * @method numericSort
16670 numericSort: function(a, b) { return (a - b); },
16674 * @property _timeoutCount
16681 * Trying to make the load order less important. Without this we get
16682 * an error if this file is loaded before the Event Utility.
16683 * @method _addListeners
16687 _addListeners: function() {
16688 var DDM = Roo.dd.DDM;
16689 if ( Roo.lib.Event && document ) {
16692 if (DDM._timeoutCount > 2000) {
16694 setTimeout(DDM._addListeners, 10);
16695 if (document && document.body) {
16696 DDM._timeoutCount += 1;
16703 * Recursively searches the immediate parent and all child nodes for
16704 * the handle element in order to determine wheter or not it was
16706 * @method handleWasClicked
16707 * @param node the html element to inspect
16710 handleWasClicked: function(node, id) {
16711 if (this.isHandle(id, node.id)) {
16714 // check to see if this is a text node child of the one we want
16715 var p = node.parentNode;
16718 if (this.isHandle(id, p.id)) {
16733 // shorter alias, save a few bytes
16734 Roo.dd.DDM = Roo.dd.DragDropMgr;
16735 Roo.dd.DDM._addListeners();
16739 * Ext JS Library 1.1.1
16740 * Copyright(c) 2006-2007, Ext JS, LLC.
16742 * Originally Released Under LGPL - original licence link has changed is not relivant.
16745 * <script type="text/javascript">
16750 * A DragDrop implementation where the linked element follows the
16751 * mouse cursor during a drag.
16752 * @extends Roo.dd.DragDrop
16754 * @param {String} id the id of the linked element
16755 * @param {String} sGroup the group of related DragDrop items
16756 * @param {object} config an object containing configurable attributes
16757 * Valid properties for DD:
16760 Roo.dd.DD = function(id, sGroup, config) {
16762 this.init(id, sGroup, config);
16766 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16769 * When set to true, the utility automatically tries to scroll the browser
16770 * window wehn a drag and drop element is dragged near the viewport boundary.
16771 * Defaults to true.
16778 * Sets the pointer offset to the distance between the linked element's top
16779 * left corner and the location the element was clicked
16780 * @method autoOffset
16781 * @param {int} iPageX the X coordinate of the click
16782 * @param {int} iPageY the Y coordinate of the click
16784 autoOffset: function(iPageX, iPageY) {
16785 var x = iPageX - this.startPageX;
16786 var y = iPageY - this.startPageY;
16787 this.setDelta(x, y);
16791 * Sets the pointer offset. You can call this directly to force the
16792 * offset to be in a particular location (e.g., pass in 0,0 to set it
16793 * to the center of the object)
16795 * @param {int} iDeltaX the distance from the left
16796 * @param {int} iDeltaY the distance from the top
16798 setDelta: function(iDeltaX, iDeltaY) {
16799 this.deltaX = iDeltaX;
16800 this.deltaY = iDeltaY;
16804 * Sets the drag element to the location of the mousedown or click event,
16805 * maintaining the cursor location relative to the location on the element
16806 * that was clicked. Override this if you want to place the element in a
16807 * location other than where the cursor is.
16808 * @method setDragElPos
16809 * @param {int} iPageX the X coordinate of the mousedown or drag event
16810 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16812 setDragElPos: function(iPageX, iPageY) {
16813 // the first time we do this, we are going to check to make sure
16814 // the element has css positioning
16816 var el = this.getDragEl();
16817 this.alignElWithMouse(el, iPageX, iPageY);
16821 * Sets the element to the location of the mousedown or click event,
16822 * maintaining the cursor location relative to the location on the element
16823 * that was clicked. Override this if you want to place the element in a
16824 * location other than where the cursor is.
16825 * @method alignElWithMouse
16826 * @param {HTMLElement} el the element to move
16827 * @param {int} iPageX the X coordinate of the mousedown or drag event
16828 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16830 alignElWithMouse: function(el, iPageX, iPageY) {
16831 var oCoord = this.getTargetCoord(iPageX, iPageY);
16832 var fly = el.dom ? el : Roo.fly(el);
16833 if (!this.deltaSetXY) {
16834 var aCoord = [oCoord.x, oCoord.y];
16836 var newLeft = fly.getLeft(true);
16837 var newTop = fly.getTop(true);
16838 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
16840 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
16843 this.cachePosition(oCoord.x, oCoord.y);
16844 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
16849 * Saves the most recent position so that we can reset the constraints and
16850 * tick marks on-demand. We need to know this so that we can calculate the
16851 * number of pixels the element is offset from its original position.
16852 * @method cachePosition
16853 * @param iPageX the current x position (optional, this just makes it so we
16854 * don't have to look it up again)
16855 * @param iPageY the current y position (optional, this just makes it so we
16856 * don't have to look it up again)
16858 cachePosition: function(iPageX, iPageY) {
16860 this.lastPageX = iPageX;
16861 this.lastPageY = iPageY;
16863 var aCoord = Roo.lib.Dom.getXY(this.getEl());
16864 this.lastPageX = aCoord[0];
16865 this.lastPageY = aCoord[1];
16870 * Auto-scroll the window if the dragged object has been moved beyond the
16871 * visible window boundary.
16872 * @method autoScroll
16873 * @param {int} x the drag element's x position
16874 * @param {int} y the drag element's y position
16875 * @param {int} h the height of the drag element
16876 * @param {int} w the width of the drag element
16879 autoScroll: function(x, y, h, w) {
16882 // The client height
16883 var clientH = Roo.lib.Dom.getViewWidth();
16885 // The client width
16886 var clientW = Roo.lib.Dom.getViewHeight();
16888 // The amt scrolled down
16889 var st = this.DDM.getScrollTop();
16891 // The amt scrolled right
16892 var sl = this.DDM.getScrollLeft();
16894 // Location of the bottom of the element
16897 // Location of the right of the element
16900 // The distance from the cursor to the bottom of the visible area,
16901 // adjusted so that we don't scroll if the cursor is beyond the
16902 // element drag constraints
16903 var toBot = (clientH + st - y - this.deltaY);
16905 // The distance from the cursor to the right of the visible area
16906 var toRight = (clientW + sl - x - this.deltaX);
16909 // How close to the edge the cursor must be before we scroll
16910 // var thresh = (document.all) ? 100 : 40;
16913 // How many pixels to scroll per autoscroll op. This helps to reduce
16914 // clunky scrolling. IE is more sensitive about this ... it needs this
16915 // value to be higher.
16916 var scrAmt = (document.all) ? 80 : 30;
16918 // Scroll down if we are near the bottom of the visible page and the
16919 // obj extends below the crease
16920 if ( bot > clientH && toBot < thresh ) {
16921 window.scrollTo(sl, st + scrAmt);
16924 // Scroll up if the window is scrolled down and the top of the object
16925 // goes above the top border
16926 if ( y < st && st > 0 && y - st < thresh ) {
16927 window.scrollTo(sl, st - scrAmt);
16930 // Scroll right if the obj is beyond the right border and the cursor is
16931 // near the border.
16932 if ( right > clientW && toRight < thresh ) {
16933 window.scrollTo(sl + scrAmt, st);
16936 // Scroll left if the window has been scrolled to the right and the obj
16937 // extends past the left border
16938 if ( x < sl && sl > 0 && x - sl < thresh ) {
16939 window.scrollTo(sl - scrAmt, st);
16945 * Finds the location the element should be placed if we want to move
16946 * it to where the mouse location less the click offset would place us.
16947 * @method getTargetCoord
16948 * @param {int} iPageX the X coordinate of the click
16949 * @param {int} iPageY the Y coordinate of the click
16950 * @return an object that contains the coordinates (Object.x and Object.y)
16953 getTargetCoord: function(iPageX, iPageY) {
16956 var x = iPageX - this.deltaX;
16957 var y = iPageY - this.deltaY;
16959 if (this.constrainX) {
16960 if (x < this.minX) { x = this.minX; }
16961 if (x > this.maxX) { x = this.maxX; }
16964 if (this.constrainY) {
16965 if (y < this.minY) { y = this.minY; }
16966 if (y > this.maxY) { y = this.maxY; }
16969 x = this.getTick(x, this.xTicks);
16970 y = this.getTick(y, this.yTicks);
16977 * Sets up config options specific to this class. Overrides
16978 * Roo.dd.DragDrop, but all versions of this method through the
16979 * inheritance chain are called
16981 applyConfig: function() {
16982 Roo.dd.DD.superclass.applyConfig.call(this);
16983 this.scroll = (this.config.scroll !== false);
16987 * Event that fires prior to the onMouseDown event. Overrides
16990 b4MouseDown: function(e) {
16991 // this.resetConstraints();
16992 this.autoOffset(e.getPageX(),
16997 * Event that fires prior to the onDrag event. Overrides
17000 b4Drag: function(e) {
17001 this.setDragElPos(e.getPageX(),
17005 toString: function() {
17006 return ("DD " + this.id);
17009 //////////////////////////////////////////////////////////////////////////
17010 // Debugging ygDragDrop events that can be overridden
17011 //////////////////////////////////////////////////////////////////////////
17013 startDrag: function(x, y) {
17016 onDrag: function(e) {
17019 onDragEnter: function(e, id) {
17022 onDragOver: function(e, id) {
17025 onDragOut: function(e, id) {
17028 onDragDrop: function(e, id) {
17031 endDrag: function(e) {
17038 * Ext JS Library 1.1.1
17039 * Copyright(c) 2006-2007, Ext JS, LLC.
17041 * Originally Released Under LGPL - original licence link has changed is not relivant.
17044 * <script type="text/javascript">
17048 * @class Roo.dd.DDProxy
17049 * A DragDrop implementation that inserts an empty, bordered div into
17050 * the document that follows the cursor during drag operations. At the time of
17051 * the click, the frame div is resized to the dimensions of the linked html
17052 * element, and moved to the exact location of the linked element.
17054 * References to the "frame" element refer to the single proxy element that
17055 * was created to be dragged in place of all DDProxy elements on the
17058 * @extends Roo.dd.DD
17060 * @param {String} id the id of the linked html element
17061 * @param {String} sGroup the group of related DragDrop objects
17062 * @param {object} config an object containing configurable attributes
17063 * Valid properties for DDProxy in addition to those in DragDrop:
17064 * resizeFrame, centerFrame, dragElId
17066 Roo.dd.DDProxy = function(id, sGroup, config) {
17068 this.init(id, sGroup, config);
17074 * The default drag frame div id
17075 * @property Roo.dd.DDProxy.dragElId
17079 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17081 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17084 * By default we resize the drag frame to be the same size as the element
17085 * we want to drag (this is to get the frame effect). We can turn it off
17086 * if we want a different behavior.
17087 * @property resizeFrame
17093 * By default the frame is positioned exactly where the drag element is, so
17094 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17095 * you do not have constraints on the obj is to have the drag frame centered
17096 * around the cursor. Set centerFrame to true for this effect.
17097 * @property centerFrame
17100 centerFrame: false,
17103 * Creates the proxy element if it does not yet exist
17104 * @method createFrame
17106 createFrame: function() {
17108 var body = document.body;
17110 if (!body || !body.firstChild) {
17111 setTimeout( function() { self.createFrame(); }, 50 );
17115 var div = this.getDragEl();
17118 div = document.createElement("div");
17119 div.id = this.dragElId;
17122 s.position = "absolute";
17123 s.visibility = "hidden";
17125 s.border = "2px solid #aaa";
17128 // appendChild can blow up IE if invoked prior to the window load event
17129 // while rendering a table. It is possible there are other scenarios
17130 // that would cause this to happen as well.
17131 body.insertBefore(div, body.firstChild);
17136 * Initialization for the drag frame element. Must be called in the
17137 * constructor of all subclasses
17138 * @method initFrame
17140 initFrame: function() {
17141 this.createFrame();
17144 applyConfig: function() {
17145 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17147 this.resizeFrame = (this.config.resizeFrame !== false);
17148 this.centerFrame = (this.config.centerFrame);
17149 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17153 * Resizes the drag frame to the dimensions of the clicked object, positions
17154 * it over the object, and finally displays it
17155 * @method showFrame
17156 * @param {int} iPageX X click position
17157 * @param {int} iPageY Y click position
17160 showFrame: function(iPageX, iPageY) {
17161 var el = this.getEl();
17162 var dragEl = this.getDragEl();
17163 var s = dragEl.style;
17165 this._resizeProxy();
17167 if (this.centerFrame) {
17168 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17169 Math.round(parseInt(s.height, 10)/2) );
17172 this.setDragElPos(iPageX, iPageY);
17174 Roo.fly(dragEl).show();
17178 * The proxy is automatically resized to the dimensions of the linked
17179 * element when a drag is initiated, unless resizeFrame is set to false
17180 * @method _resizeProxy
17183 _resizeProxy: function() {
17184 if (this.resizeFrame) {
17185 var el = this.getEl();
17186 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17190 // overrides Roo.dd.DragDrop
17191 b4MouseDown: function(e) {
17192 var x = e.getPageX();
17193 var y = e.getPageY();
17194 this.autoOffset(x, y);
17195 this.setDragElPos(x, y);
17198 // overrides Roo.dd.DragDrop
17199 b4StartDrag: function(x, y) {
17200 // show the drag frame
17201 this.showFrame(x, y);
17204 // overrides Roo.dd.DragDrop
17205 b4EndDrag: function(e) {
17206 Roo.fly(this.getDragEl()).hide();
17209 // overrides Roo.dd.DragDrop
17210 // By default we try to move the element to the last location of the frame.
17211 // This is so that the default behavior mirrors that of Roo.dd.DD.
17212 endDrag: function(e) {
17214 var lel = this.getEl();
17215 var del = this.getDragEl();
17217 // Show the drag frame briefly so we can get its position
17218 del.style.visibility = "";
17221 // Hide the linked element before the move to get around a Safari
17223 lel.style.visibility = "hidden";
17224 Roo.dd.DDM.moveToEl(lel, del);
17225 del.style.visibility = "hidden";
17226 lel.style.visibility = "";
17231 beforeMove : function(){
17235 afterDrag : function(){
17239 toString: function() {
17240 return ("DDProxy " + this.id);
17246 * Ext JS Library 1.1.1
17247 * Copyright(c) 2006-2007, Ext JS, LLC.
17249 * Originally Released Under LGPL - original licence link has changed is not relivant.
17252 * <script type="text/javascript">
17256 * @class Roo.dd.DDTarget
17257 * A DragDrop implementation that does not move, but can be a drop
17258 * target. You would get the same result by simply omitting implementation
17259 * for the event callbacks, but this way we reduce the processing cost of the
17260 * event listener and the callbacks.
17261 * @extends Roo.dd.DragDrop
17263 * @param {String} id the id of the element that is a drop target
17264 * @param {String} sGroup the group of related DragDrop objects
17265 * @param {object} config an object containing configurable attributes
17266 * Valid properties for DDTarget in addition to those in
17270 Roo.dd.DDTarget = function(id, sGroup, config) {
17272 this.initTarget(id, sGroup, config);
17276 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17277 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17278 toString: function() {
17279 return ("DDTarget " + this.id);
17284 * Ext JS Library 1.1.1
17285 * Copyright(c) 2006-2007, Ext JS, LLC.
17287 * Originally Released Under LGPL - original licence link has changed is not relivant.
17290 * <script type="text/javascript">
17295 * @class Roo.dd.ScrollManager
17296 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17297 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17300 Roo.dd.ScrollManager = function(){
17301 var ddm = Roo.dd.DragDropMgr;
17306 var onStop = function(e){
17311 var triggerRefresh = function(){
17312 if(ddm.dragCurrent){
17313 ddm.refreshCache(ddm.dragCurrent.groups);
17317 var doScroll = function(){
17318 if(ddm.dragCurrent){
17319 var dds = Roo.dd.ScrollManager;
17321 if(proc.el.scroll(proc.dir, dds.increment)){
17325 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17330 var clearProc = function(){
17332 clearInterval(proc.id);
17339 var startProc = function(el, dir){
17343 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17346 var onFire = function(e, isDrop){
17347 if(isDrop || !ddm.dragCurrent){ return; }
17348 var dds = Roo.dd.ScrollManager;
17349 if(!dragEl || dragEl != ddm.dragCurrent){
17350 dragEl = ddm.dragCurrent;
17351 // refresh regions on drag start
17352 dds.refreshCache();
17355 var xy = Roo.lib.Event.getXY(e);
17356 var pt = new Roo.lib.Point(xy[0], xy[1]);
17357 for(var id in els){
17358 var el = els[id], r = el._region;
17359 if(r && r.contains(pt) && el.isScrollable()){
17360 if(r.bottom - pt.y <= dds.thresh){
17362 startProc(el, "down");
17365 }else if(r.right - pt.x <= dds.thresh){
17367 startProc(el, "left");
17370 }else if(pt.y - r.top <= dds.thresh){
17372 startProc(el, "up");
17375 }else if(pt.x - r.left <= dds.thresh){
17377 startProc(el, "right");
17386 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17387 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17391 * Registers new overflow element(s) to auto scroll
17392 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17394 register : function(el){
17395 if(el instanceof Array){
17396 for(var i = 0, len = el.length; i < len; i++) {
17397 this.register(el[i]);
17406 * Unregisters overflow element(s) so they are no longer scrolled
17407 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17409 unregister : function(el){
17410 if(el instanceof Array){
17411 for(var i = 0, len = el.length; i < len; i++) {
17412 this.unregister(el[i]);
17421 * The number of pixels from the edge of a container the pointer needs to be to
17422 * trigger scrolling (defaults to 25)
17428 * The number of pixels to scroll in each scroll increment (defaults to 50)
17434 * The frequency of scrolls in milliseconds (defaults to 500)
17440 * True to animate the scroll (defaults to true)
17446 * The animation duration in seconds -
17447 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17453 * Manually trigger a cache refresh.
17455 refreshCache : function(){
17456 for(var id in els){
17457 if(typeof els[id] == 'object'){ // for people extending the object prototype
17458 els[id]._region = els[id].getRegion();
17465 * Ext JS Library 1.1.1
17466 * Copyright(c) 2006-2007, Ext JS, LLC.
17468 * Originally Released Under LGPL - original licence link has changed is not relivant.
17471 * <script type="text/javascript">
17476 * @class Roo.dd.Registry
17477 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17478 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17481 Roo.dd.Registry = function(){
17484 var autoIdSeed = 0;
17486 var getId = function(el, autogen){
17487 if(typeof el == "string"){
17491 if(!id && autogen !== false){
17492 id = "roodd-" + (++autoIdSeed);
17500 * Register a drag drop element
17501 * @param {String|HTMLElement} element The id or DOM node to register
17502 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17503 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17504 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17505 * populated in the data object (if applicable):
17507 Value Description<br />
17508 --------- ------------------------------------------<br />
17509 handles Array of DOM nodes that trigger dragging<br />
17510 for the element being registered<br />
17511 isHandle True if the element passed in triggers<br />
17512 dragging itself, else false
17515 register : function(el, data){
17517 if(typeof el == "string"){
17518 el = document.getElementById(el);
17521 elements[getId(el)] = data;
17522 if(data.isHandle !== false){
17523 handles[data.ddel.id] = data;
17526 var hs = data.handles;
17527 for(var i = 0, len = hs.length; i < len; i++){
17528 handles[getId(hs[i])] = data;
17534 * Unregister a drag drop element
17535 * @param {String|HTMLElement} element The id or DOM node to unregister
17537 unregister : function(el){
17538 var id = getId(el, false);
17539 var data = elements[id];
17541 delete elements[id];
17543 var hs = data.handles;
17544 for(var i = 0, len = hs.length; i < len; i++){
17545 delete handles[getId(hs[i], false)];
17552 * Returns the handle registered for a DOM Node by id
17553 * @param {String|HTMLElement} id The DOM node or id to look up
17554 * @return {Object} handle The custom handle data
17556 getHandle : function(id){
17557 if(typeof id != "string"){ // must be element?
17560 return handles[id];
17564 * Returns the handle that is registered for the DOM node that is the target of the event
17565 * @param {Event} e The event
17566 * @return {Object} handle The custom handle data
17568 getHandleFromEvent : function(e){
17569 var t = Roo.lib.Event.getTarget(e);
17570 return t ? handles[t.id] : null;
17574 * Returns a custom data object that is registered for a DOM node by id
17575 * @param {String|HTMLElement} id The DOM node or id to look up
17576 * @return {Object} data The custom data
17578 getTarget : function(id){
17579 if(typeof id != "string"){ // must be element?
17582 return elements[id];
17586 * Returns a custom data object that is registered for the DOM node that is the target of the event
17587 * @param {Event} e The event
17588 * @return {Object} data The custom data
17590 getTargetFromEvent : function(e){
17591 var t = Roo.lib.Event.getTarget(e);
17592 return t ? elements[t.id] || handles[t.id] : null;
17597 * Ext JS Library 1.1.1
17598 * Copyright(c) 2006-2007, Ext JS, LLC.
17600 * Originally Released Under LGPL - original licence link has changed is not relivant.
17603 * <script type="text/javascript">
17608 * @class Roo.dd.StatusProxy
17609 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17610 * default drag proxy used by all Roo.dd components.
17612 * @param {Object} config
17614 Roo.dd.StatusProxy = function(config){
17615 Roo.apply(this, config);
17616 this.id = this.id || Roo.id();
17617 this.el = new Roo.Layer({
17619 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17620 {tag: "div", cls: "x-dd-drop-icon"},
17621 {tag: "div", cls: "x-dd-drag-ghost"}
17624 shadow: !config || config.shadow !== false
17626 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17627 this.dropStatus = this.dropNotAllowed;
17630 Roo.dd.StatusProxy.prototype = {
17632 * @cfg {String} dropAllowed
17633 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17635 dropAllowed : "x-dd-drop-ok",
17637 * @cfg {String} dropNotAllowed
17638 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17640 dropNotAllowed : "x-dd-drop-nodrop",
17643 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17644 * over the current target element.
17645 * @param {String} cssClass The css class for the new drop status indicator image
17647 setStatus : function(cssClass){
17648 cssClass = cssClass || this.dropNotAllowed;
17649 if(this.dropStatus != cssClass){
17650 this.el.replaceClass(this.dropStatus, cssClass);
17651 this.dropStatus = cssClass;
17656 * Resets the status indicator to the default dropNotAllowed value
17657 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17659 reset : function(clearGhost){
17660 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17661 this.dropStatus = this.dropNotAllowed;
17663 this.ghost.update("");
17668 * Updates the contents of the ghost element
17669 * @param {String} html The html that will replace the current innerHTML of the ghost element
17671 update : function(html){
17672 if(typeof html == "string"){
17673 this.ghost.update(html);
17675 this.ghost.update("");
17676 html.style.margin = "0";
17677 this.ghost.dom.appendChild(html);
17679 // ensure float = none set?? cant remember why though.
17680 var el = this.ghost.dom.firstChild;
17682 Roo.fly(el).setStyle('float', 'none');
17687 * Returns the underlying proxy {@link Roo.Layer}
17688 * @return {Roo.Layer} el
17690 getEl : function(){
17695 * Returns the ghost element
17696 * @return {Roo.Element} el
17698 getGhost : function(){
17704 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17706 hide : function(clear){
17714 * Stops the repair animation if it's currently running
17717 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17723 * Displays this proxy
17730 * Force the Layer to sync its shadow and shim positions to the element
17737 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17738 * invalid drop operation by the item being dragged.
17739 * @param {Array} xy The XY position of the element ([x, y])
17740 * @param {Function} callback The function to call after the repair is complete
17741 * @param {Object} scope The scope in which to execute the callback
17743 repair : function(xy, callback, scope){
17744 this.callback = callback;
17745 this.scope = scope;
17746 if(xy && this.animRepair !== false){
17747 this.el.addClass("x-dd-drag-repair");
17748 this.el.hideUnders(true);
17749 this.anim = this.el.shift({
17750 duration: this.repairDuration || .5,
17754 callback: this.afterRepair,
17758 this.afterRepair();
17763 afterRepair : function(){
17765 if(typeof this.callback == "function"){
17766 this.callback.call(this.scope || this);
17768 this.callback = null;
17773 * Ext JS Library 1.1.1
17774 * Copyright(c) 2006-2007, Ext JS, LLC.
17776 * Originally Released Under LGPL - original licence link has changed is not relivant.
17779 * <script type="text/javascript">
17783 * @class Roo.dd.DragSource
17784 * @extends Roo.dd.DDProxy
17785 * A simple class that provides the basic implementation needed to make any element draggable.
17787 * @param {String/HTMLElement/Element} el The container element
17788 * @param {Object} config
17790 Roo.dd.DragSource = function(el, config){
17791 this.el = Roo.get(el);
17792 this.dragData = {};
17794 Roo.apply(this, config);
17797 this.proxy = new Roo.dd.StatusProxy();
17800 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17801 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17803 this.dragging = false;
17806 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17808 * @cfg {String} dropAllowed
17809 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17811 dropAllowed : "x-dd-drop-ok",
17813 * @cfg {String} dropNotAllowed
17814 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17816 dropNotAllowed : "x-dd-drop-nodrop",
17819 * Returns the data object associated with this drag source
17820 * @return {Object} data An object containing arbitrary data
17822 getDragData : function(e){
17823 return this.dragData;
17827 onDragEnter : function(e, id){
17828 var target = Roo.dd.DragDropMgr.getDDById(id);
17829 this.cachedTarget = target;
17830 if(this.beforeDragEnter(target, e, id) !== false){
17831 if(target.isNotifyTarget){
17832 var status = target.notifyEnter(this, e, this.dragData);
17833 this.proxy.setStatus(status);
17835 this.proxy.setStatus(this.dropAllowed);
17838 if(this.afterDragEnter){
17840 * An empty function by default, but provided so that you can perform a custom action
17841 * when the dragged item enters the drop target by providing an implementation.
17842 * @param {Roo.dd.DragDrop} target The drop target
17843 * @param {Event} e The event object
17844 * @param {String} id The id of the dragged element
17845 * @method afterDragEnter
17847 this.afterDragEnter(target, e, id);
17853 * An empty function by default, but provided so that you can perform a custom action
17854 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
17855 * @param {Roo.dd.DragDrop} target The drop target
17856 * @param {Event} e The event object
17857 * @param {String} id The id of the dragged element
17858 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17860 beforeDragEnter : function(target, e, id){
17865 alignElWithMouse: function() {
17866 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
17871 onDragOver : function(e, id){
17872 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17873 if(this.beforeDragOver(target, e, id) !== false){
17874 if(target.isNotifyTarget){
17875 var status = target.notifyOver(this, e, this.dragData);
17876 this.proxy.setStatus(status);
17879 if(this.afterDragOver){
17881 * An empty function by default, but provided so that you can perform a custom action
17882 * while the dragged item is over the drop target by providing an implementation.
17883 * @param {Roo.dd.DragDrop} target The drop target
17884 * @param {Event} e The event object
17885 * @param {String} id The id of the dragged element
17886 * @method afterDragOver
17888 this.afterDragOver(target, e, id);
17894 * An empty function by default, but provided so that you can perform a custom action
17895 * while the dragged item is over the drop target and optionally cancel the onDragOver.
17896 * @param {Roo.dd.DragDrop} target The drop target
17897 * @param {Event} e The event object
17898 * @param {String} id The id of the dragged element
17899 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17901 beforeDragOver : function(target, e, id){
17906 onDragOut : function(e, id){
17907 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17908 if(this.beforeDragOut(target, e, id) !== false){
17909 if(target.isNotifyTarget){
17910 target.notifyOut(this, e, this.dragData);
17912 this.proxy.reset();
17913 if(this.afterDragOut){
17915 * An empty function by default, but provided so that you can perform a custom action
17916 * after the dragged item is dragged out of the target without dropping.
17917 * @param {Roo.dd.DragDrop} target The drop target
17918 * @param {Event} e The event object
17919 * @param {String} id The id of the dragged element
17920 * @method afterDragOut
17922 this.afterDragOut(target, e, id);
17925 this.cachedTarget = null;
17929 * An empty function by default, but provided so that you can perform a custom action before the dragged
17930 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
17931 * @param {Roo.dd.DragDrop} target The drop target
17932 * @param {Event} e The event object
17933 * @param {String} id The id of the dragged element
17934 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17936 beforeDragOut : function(target, e, id){
17941 onDragDrop : function(e, id){
17942 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17943 if(this.beforeDragDrop(target, e, id) !== false){
17944 if(target.isNotifyTarget){
17945 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
17946 this.onValidDrop(target, e, id);
17948 this.onInvalidDrop(target, e, id);
17951 this.onValidDrop(target, e, id);
17954 if(this.afterDragDrop){
17956 * An empty function by default, but provided so that you can perform a custom action
17957 * after a valid drag drop has occurred by providing an implementation.
17958 * @param {Roo.dd.DragDrop} target The drop target
17959 * @param {Event} e The event object
17960 * @param {String} id The id of the dropped element
17961 * @method afterDragDrop
17963 this.afterDragDrop(target, e, id);
17966 delete this.cachedTarget;
17970 * An empty function by default, but provided so that you can perform a custom action before the dragged
17971 * item is dropped onto the target and optionally cancel the onDragDrop.
17972 * @param {Roo.dd.DragDrop} target The drop target
17973 * @param {Event} e The event object
17974 * @param {String} id The id of the dragged element
17975 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
17977 beforeDragDrop : function(target, e, id){
17982 onValidDrop : function(target, e, id){
17984 if(this.afterValidDrop){
17986 * An empty function by default, but provided so that you can perform a custom action
17987 * after a valid drop has occurred by providing an implementation.
17988 * @param {Object} target The target DD
17989 * @param {Event} e The event object
17990 * @param {String} id The id of the dropped element
17991 * @method afterInvalidDrop
17993 this.afterValidDrop(target, e, id);
17998 getRepairXY : function(e, data){
17999 return this.el.getXY();
18003 onInvalidDrop : function(target, e, id){
18004 this.beforeInvalidDrop(target, e, id);
18005 if(this.cachedTarget){
18006 if(this.cachedTarget.isNotifyTarget){
18007 this.cachedTarget.notifyOut(this, e, this.dragData);
18009 this.cacheTarget = null;
18011 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18013 if(this.afterInvalidDrop){
18015 * An empty function by default, but provided so that you can perform a custom action
18016 * after an invalid drop has occurred by providing an implementation.
18017 * @param {Event} e The event object
18018 * @param {String} id The id of the dropped element
18019 * @method afterInvalidDrop
18021 this.afterInvalidDrop(e, id);
18026 afterRepair : function(){
18028 this.el.highlight(this.hlColor || "c3daf9");
18030 this.dragging = false;
18034 * An empty function by default, but provided so that you can perform a custom action after an invalid
18035 * drop has occurred.
18036 * @param {Roo.dd.DragDrop} target The drop target
18037 * @param {Event} e The event object
18038 * @param {String} id The id of the dragged element
18039 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18041 beforeInvalidDrop : function(target, e, id){
18046 handleMouseDown : function(e){
18047 if(this.dragging) {
18050 var data = this.getDragData(e);
18051 if(data && this.onBeforeDrag(data, e) !== false){
18052 this.dragData = data;
18054 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18059 * An empty function by default, but provided so that you can perform a custom action before the initial
18060 * drag event begins and optionally cancel it.
18061 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18062 * @param {Event} e The event object
18063 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18065 onBeforeDrag : function(data, e){
18070 * An empty function by default, but provided so that you can perform a custom action once the initial
18071 * drag event has begun. The drag cannot be canceled from this function.
18072 * @param {Number} x The x position of the click on the dragged object
18073 * @param {Number} y The y position of the click on the dragged object
18075 onStartDrag : Roo.emptyFn,
18077 // private - YUI override
18078 startDrag : function(x, y){
18079 this.proxy.reset();
18080 this.dragging = true;
18081 this.proxy.update("");
18082 this.onInitDrag(x, y);
18087 onInitDrag : function(x, y){
18088 var clone = this.el.dom.cloneNode(true);
18089 clone.id = Roo.id(); // prevent duplicate ids
18090 this.proxy.update(clone);
18091 this.onStartDrag(x, y);
18096 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18097 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18099 getProxy : function(){
18104 * Hides the drag source's {@link Roo.dd.StatusProxy}
18106 hideProxy : function(){
18108 this.proxy.reset(true);
18109 this.dragging = false;
18113 triggerCacheRefresh : function(){
18114 Roo.dd.DDM.refreshCache(this.groups);
18117 // private - override to prevent hiding
18118 b4EndDrag: function(e) {
18121 // private - override to prevent moving
18122 endDrag : function(e){
18123 this.onEndDrag(this.dragData, e);
18127 onEndDrag : function(data, e){
18130 // private - pin to cursor
18131 autoOffset : function(x, y) {
18132 this.setDelta(-12, -20);
18136 * Ext JS Library 1.1.1
18137 * Copyright(c) 2006-2007, Ext JS, LLC.
18139 * Originally Released Under LGPL - original licence link has changed is not relivant.
18142 * <script type="text/javascript">
18147 * @class Roo.dd.DropTarget
18148 * @extends Roo.dd.DDTarget
18149 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18150 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18152 * @param {String/HTMLElement/Element} el The container element
18153 * @param {Object} config
18155 Roo.dd.DropTarget = function(el, config){
18156 this.el = Roo.get(el);
18158 Roo.apply(this, config);
18160 if(this.containerScroll){
18161 Roo.dd.ScrollManager.register(this.el);
18164 Roo.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18169 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18171 * @cfg {String} overClass
18172 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18175 * @cfg {String} dropAllowed
18176 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18178 dropAllowed : "x-dd-drop-ok",
18180 * @cfg {String} dropNotAllowed
18181 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18183 dropNotAllowed : "x-dd-drop-nodrop",
18189 isNotifyTarget : true,
18192 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18193 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18194 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18195 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18196 * @param {Event} e The event
18197 * @param {Object} data An object containing arbitrary data supplied by the drag source
18198 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18199 * underlying {@link Roo.dd.StatusProxy} can be updated
18201 notifyEnter : function(dd, e, data){
18202 if(this.overClass){
18203 this.el.addClass(this.overClass);
18205 return this.dropAllowed;
18209 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18210 * This method will be called on every mouse movement while the drag source is over the drop target.
18211 * This default implementation simply returns the dropAllowed config value.
18212 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18213 * @param {Event} e The event
18214 * @param {Object} data An object containing arbitrary data supplied by the drag source
18215 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18216 * underlying {@link Roo.dd.StatusProxy} can be updated
18218 notifyOver : function(dd, e, data){
18219 return this.dropAllowed;
18223 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18224 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18225 * overClass (if any) from the drop element.
18226 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18227 * @param {Event} e The event
18228 * @param {Object} data An object containing arbitrary data supplied by the drag source
18230 notifyOut : function(dd, e, data){
18231 if(this.overClass){
18232 this.el.removeClass(this.overClass);
18237 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18238 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18239 * implementation that does something to process the drop event and returns true so that the drag source's
18240 * repair action does not run.
18241 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18242 * @param {Event} e The event
18243 * @param {Object} data An object containing arbitrary data supplied by the drag source
18244 * @return {Boolean} True if the drop was valid, else false
18246 notifyDrop : function(dd, e, data){
18251 * Ext JS Library 1.1.1
18252 * Copyright(c) 2006-2007, Ext JS, LLC.
18254 * Originally Released Under LGPL - original licence link has changed is not relivant.
18257 * <script type="text/javascript">
18262 * @class Roo.dd.DragZone
18263 * @extends Roo.dd.DragSource
18264 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18265 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18267 * @param {String/HTMLElement/Element} el The container element
18268 * @param {Object} config
18270 Roo.dd.DragZone = function(el, config){
18271 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18272 if(this.containerScroll){
18273 Roo.dd.ScrollManager.register(this.el);
18277 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18279 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18280 * for auto scrolling during drag operations.
18283 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18284 * method after a failed drop (defaults to "c3daf9" - light blue)
18288 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18289 * for a valid target to drag based on the mouse down. Override this method
18290 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18291 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18292 * @param {EventObject} e The mouse down event
18293 * @return {Object} The dragData
18295 getDragData : function(e){
18296 return Roo.dd.Registry.getHandleFromEvent(e);
18300 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18301 * this.dragData.ddel
18302 * @param {Number} x The x position of the click on the dragged object
18303 * @param {Number} y The y position of the click on the dragged object
18304 * @return {Boolean} true to continue the drag, false to cancel
18306 onInitDrag : function(x, y){
18307 this.proxy.update(this.dragData.ddel.cloneNode(true));
18308 this.onStartDrag(x, y);
18313 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18315 afterRepair : function(){
18317 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18319 this.dragging = false;
18323 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18324 * the XY of this.dragData.ddel
18325 * @param {EventObject} e The mouse up event
18326 * @return {Array} The xy location (e.g. [100, 200])
18328 getRepairXY : function(e){
18329 return Roo.Element.fly(this.dragData.ddel).getXY();
18333 * Ext JS Library 1.1.1
18334 * Copyright(c) 2006-2007, Ext JS, LLC.
18336 * Originally Released Under LGPL - original licence link has changed is not relivant.
18339 * <script type="text/javascript">
18342 * @class Roo.dd.DropZone
18343 * @extends Roo.dd.DropTarget
18344 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18345 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18347 * @param {String/HTMLElement/Element} el The container element
18348 * @param {Object} config
18350 Roo.dd.DropZone = function(el, config){
18351 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18354 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18356 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18357 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18358 * provide your own custom lookup.
18359 * @param {Event} e The event
18360 * @return {Object} data The custom data
18362 getTargetFromEvent : function(e){
18363 return Roo.dd.Registry.getTargetFromEvent(e);
18367 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18368 * that it has registered. This method has no default implementation and should be overridden to provide
18369 * node-specific processing if necessary.
18370 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18371 * {@link #getTargetFromEvent} for this node)
18372 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18373 * @param {Event} e The event
18374 * @param {Object} data An object containing arbitrary data supplied by the drag source
18376 onNodeEnter : function(n, dd, e, data){
18381 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18382 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18383 * overridden to provide the proper feedback.
18384 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18385 * {@link #getTargetFromEvent} for this node)
18386 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18387 * @param {Event} e The event
18388 * @param {Object} data An object containing arbitrary data supplied by the drag source
18389 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18390 * underlying {@link Roo.dd.StatusProxy} can be updated
18392 onNodeOver : function(n, dd, e, data){
18393 return this.dropAllowed;
18397 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18398 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18399 * node-specific processing if necessary.
18400 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18401 * {@link #getTargetFromEvent} for this node)
18402 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18403 * @param {Event} e The event
18404 * @param {Object} data An object containing arbitrary data supplied by the drag source
18406 onNodeOut : function(n, dd, e, data){
18411 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18412 * the drop node. The default implementation returns false, so it should be overridden to provide the
18413 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18414 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18415 * {@link #getTargetFromEvent} for this node)
18416 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18417 * @param {Event} e The event
18418 * @param {Object} data An object containing arbitrary data supplied by the drag source
18419 * @return {Boolean} True if the drop was valid, else false
18421 onNodeDrop : function(n, dd, e, data){
18426 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18427 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18428 * it should be overridden to provide the proper feedback if necessary.
18429 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18430 * @param {Event} e The event
18431 * @param {Object} data An object containing arbitrary data supplied by the drag source
18432 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18433 * underlying {@link Roo.dd.StatusProxy} can be updated
18435 onContainerOver : function(dd, e, data){
18436 return this.dropNotAllowed;
18440 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18441 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18442 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18443 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18444 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18445 * @param {Event} e The event
18446 * @param {Object} data An object containing arbitrary data supplied by the drag source
18447 * @return {Boolean} True if the drop was valid, else false
18449 onContainerDrop : function(dd, e, data){
18454 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18455 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18456 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18457 * you should override this method and provide a custom implementation.
18458 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18459 * @param {Event} e The event
18460 * @param {Object} data An object containing arbitrary data supplied by the drag source
18461 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18462 * underlying {@link Roo.dd.StatusProxy} can be updated
18464 notifyEnter : function(dd, e, data){
18465 return this.dropNotAllowed;
18469 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18470 * This method will be called on every mouse movement while the drag source is over the drop zone.
18471 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18472 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18473 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18474 * registered node, it will call {@link #onContainerOver}.
18475 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18476 * @param {Event} e The event
18477 * @param {Object} data An object containing arbitrary data supplied by the drag source
18478 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18479 * underlying {@link Roo.dd.StatusProxy} can be updated
18481 notifyOver : function(dd, e, data){
18482 var n = this.getTargetFromEvent(e);
18483 if(!n){ // not over valid drop target
18484 if(this.lastOverNode){
18485 this.onNodeOut(this.lastOverNode, dd, e, data);
18486 this.lastOverNode = null;
18488 return this.onContainerOver(dd, e, data);
18490 if(this.lastOverNode != n){
18491 if(this.lastOverNode){
18492 this.onNodeOut(this.lastOverNode, dd, e, data);
18494 this.onNodeEnter(n, dd, e, data);
18495 this.lastOverNode = n;
18497 return this.onNodeOver(n, dd, e, data);
18501 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18502 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18503 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18504 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18505 * @param {Event} e The event
18506 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18508 notifyOut : function(dd, e, data){
18509 if(this.lastOverNode){
18510 this.onNodeOut(this.lastOverNode, dd, e, data);
18511 this.lastOverNode = null;
18516 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18517 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18518 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18519 * otherwise it will call {@link #onContainerDrop}.
18520 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18521 * @param {Event} e The event
18522 * @param {Object} data An object containing arbitrary data supplied by the drag source
18523 * @return {Boolean} True if the drop was valid, else false
18525 notifyDrop : function(dd, e, data){
18526 if(this.lastOverNode){
18527 this.onNodeOut(this.lastOverNode, dd, e, data);
18528 this.lastOverNode = null;
18530 var n = this.getTargetFromEvent(e);
18532 this.onNodeDrop(n, dd, e, data) :
18533 this.onContainerDrop(dd, e, data);
18537 triggerCacheRefresh : function(){
18538 Roo.dd.DDM.refreshCache(this.groups);
18542 * Ext JS Library 1.1.1
18543 * Copyright(c) 2006-2007, Ext JS, LLC.
18545 * Originally Released Under LGPL - original licence link has changed is not relivant.
18548 * <script type="text/javascript">
18553 * @class Roo.data.SortTypes
18555 * Defines the default sorting (casting?) comparison functions used when sorting data.
18557 Roo.data.SortTypes = {
18559 * Default sort that does nothing
18560 * @param {Mixed} s The value being converted
18561 * @return {Mixed} The comparison value
18563 none : function(s){
18568 * The regular expression used to strip tags
18572 stripTagsRE : /<\/?[^>]+>/gi,
18575 * Strips all HTML tags to sort on text only
18576 * @param {Mixed} s The value being converted
18577 * @return {String} The comparison value
18579 asText : function(s){
18580 return String(s).replace(this.stripTagsRE, "");
18584 * Strips all HTML tags to sort on text only - Case insensitive
18585 * @param {Mixed} s The value being converted
18586 * @return {String} The comparison value
18588 asUCText : function(s){
18589 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18593 * Case insensitive string
18594 * @param {Mixed} s The value being converted
18595 * @return {String} The comparison value
18597 asUCString : function(s) {
18598 return String(s).toUpperCase();
18603 * @param {Mixed} s The value being converted
18604 * @return {Number} The comparison value
18606 asDate : function(s) {
18610 if(s instanceof Date){
18611 return s.getTime();
18613 return Date.parse(String(s));
18618 * @param {Mixed} s The value being converted
18619 * @return {Float} The comparison value
18621 asFloat : function(s) {
18622 var val = parseFloat(String(s).replace(/,/g, ""));
18623 if(isNaN(val)) val = 0;
18629 * @param {Mixed} s The value being converted
18630 * @return {Number} The comparison value
18632 asInt : function(s) {
18633 var val = parseInt(String(s).replace(/,/g, ""));
18634 if(isNaN(val)) val = 0;
18639 * Ext JS Library 1.1.1
18640 * Copyright(c) 2006-2007, Ext JS, LLC.
18642 * Originally Released Under LGPL - original licence link has changed is not relivant.
18645 * <script type="text/javascript">
18649 * @class Roo.data.Record
18650 * Instances of this class encapsulate both record <em>definition</em> information, and record
18651 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18652 * to access Records cached in an {@link Roo.data.Store} object.<br>
18654 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18655 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18658 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18660 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18661 * {@link #create}. The parameters are the same.
18662 * @param {Array} data An associative Array of data values keyed by the field name.
18663 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18664 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18665 * not specified an integer id is generated.
18667 Roo.data.Record = function(data, id){
18668 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18673 * Generate a constructor for a specific record layout.
18674 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18675 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18676 * Each field definition object may contain the following properties: <ul>
18677 * <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,
18678 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18679 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18680 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18681 * is being used, then this is a string containing the javascript expression to reference the data relative to
18682 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18683 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18684 * this may be omitted.</p></li>
18685 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18686 * <ul><li>auto (Default, implies no conversion)</li>
18691 * <li>date</li></ul></p></li>
18692 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18693 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18694 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18695 * by the Reader into an object that will be stored in the Record. It is passed the
18696 * following parameters:<ul>
18697 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18699 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18701 * <br>usage:<br><pre><code>
18702 var TopicRecord = Roo.data.Record.create(
18703 {name: 'title', mapping: 'topic_title'},
18704 {name: 'author', mapping: 'username'},
18705 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18706 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18707 {name: 'lastPoster', mapping: 'user2'},
18708 {name: 'excerpt', mapping: 'post_text'}
18711 var myNewRecord = new TopicRecord({
18712 title: 'Do my job please',
18715 lastPost: new Date(),
18716 lastPoster: 'Animal',
18717 excerpt: 'No way dude!'
18719 myStore.add(myNewRecord);
18724 Roo.data.Record.create = function(o){
18725 var f = function(){
18726 f.superclass.constructor.apply(this, arguments);
18728 Roo.extend(f, Roo.data.Record);
18729 var p = f.prototype;
18730 p.fields = new Roo.util.MixedCollection(false, function(field){
18733 for(var i = 0, len = o.length; i < len; i++){
18734 p.fields.add(new Roo.data.Field(o[i]));
18736 f.getField = function(name){
18737 return p.fields.get(name);
18742 Roo.data.Record.AUTO_ID = 1000;
18743 Roo.data.Record.EDIT = 'edit';
18744 Roo.data.Record.REJECT = 'reject';
18745 Roo.data.Record.COMMIT = 'commit';
18747 Roo.data.Record.prototype = {
18749 * Readonly flag - true if this record has been modified.
18758 join : function(store){
18759 this.store = store;
18763 * Set the named field to the specified value.
18764 * @param {String} name The name of the field to set.
18765 * @param {Object} value The value to set the field to.
18767 set : function(name, value){
18768 if(this.data[name] == value){
18772 if(!this.modified){
18773 this.modified = {};
18775 if(typeof this.modified[name] == 'undefined'){
18776 this.modified[name] = this.data[name];
18778 this.data[name] = value;
18780 this.store.afterEdit(this);
18785 * Get the value of the named field.
18786 * @param {String} name The name of the field to get the value of.
18787 * @return {Object} The value of the field.
18789 get : function(name){
18790 return this.data[name];
18794 beginEdit : function(){
18795 this.editing = true;
18796 this.modified = {};
18800 cancelEdit : function(){
18801 this.editing = false;
18802 delete this.modified;
18806 endEdit : function(){
18807 this.editing = false;
18808 if(this.dirty && this.store){
18809 this.store.afterEdit(this);
18814 * Usually called by the {@link Roo.data.Store} which owns the Record.
18815 * Rejects all changes made to the Record since either creation, or the last commit operation.
18816 * Modified fields are reverted to their original values.
18818 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18819 * of reject operations.
18821 reject : function(){
18822 var m = this.modified;
18824 if(typeof m[n] != "function"){
18825 this.data[n] = m[n];
18828 this.dirty = false;
18829 delete this.modified;
18830 this.editing = false;
18832 this.store.afterReject(this);
18837 * Usually called by the {@link Roo.data.Store} which owns the Record.
18838 * Commits all changes made to the Record since either creation, or the last commit operation.
18840 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18841 * of commit operations.
18843 commit : function(){
18844 this.dirty = false;
18845 delete this.modified;
18846 this.editing = false;
18848 this.store.afterCommit(this);
18853 hasError : function(){
18854 return this.error != null;
18858 clearError : function(){
18863 * Creates a copy of this record.
18864 * @param {String} id (optional) A new record id if you don't want to use this record's id
18867 copy : function(newId) {
18868 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
18872 * Ext JS Library 1.1.1
18873 * Copyright(c) 2006-2007, Ext JS, LLC.
18875 * Originally Released Under LGPL - original licence link has changed is not relivant.
18878 * <script type="text/javascript">
18884 * @class Roo.data.Store
18885 * @extends Roo.util.Observable
18886 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
18887 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
18889 * 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
18890 * has no knowledge of the format of the data returned by the Proxy.<br>
18892 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
18893 * instances from the data object. These records are cached and made available through accessor functions.
18895 * Creates a new Store.
18896 * @param {Object} config A config object containing the objects needed for the Store to access data,
18897 * and read the data into Records.
18899 Roo.data.Store = function(config){
18900 this.data = new Roo.util.MixedCollection(false);
18901 this.data.getKey = function(o){
18904 this.baseParams = {};
18906 this.paramNames = {
18913 if(config && config.data){
18914 this.inlineData = config.data;
18915 delete config.data;
18918 Roo.apply(this, config);
18920 if(this.reader){ // reader passed
18921 this.reader = Roo.factory(this.reader, Roo.data);
18922 this.reader.xmodule = this.xmodule || false;
18923 if(!this.recordType){
18924 this.recordType = this.reader.recordType;
18926 if(this.reader.onMetaChange){
18927 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
18931 if(this.recordType){
18932 this.fields = this.recordType.prototype.fields;
18934 this.modified = [];
18938 * @event datachanged
18939 * Fires when the data cache has changed, and a widget which is using this Store
18940 * as a Record cache should refresh its view.
18941 * @param {Store} this
18943 datachanged : true,
18945 * @event metachange
18946 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
18947 * @param {Store} this
18948 * @param {Object} meta The JSON metadata
18953 * Fires when Records have been added to the Store
18954 * @param {Store} this
18955 * @param {Roo.data.Record[]} records The array of Records added
18956 * @param {Number} index The index at which the record(s) were added
18961 * Fires when a Record has been removed from the Store
18962 * @param {Store} this
18963 * @param {Roo.data.Record} record The Record that was removed
18964 * @param {Number} index The index at which the record was removed
18969 * Fires when a Record has been updated
18970 * @param {Store} this
18971 * @param {Roo.data.Record} record The Record that was updated
18972 * @param {String} operation The update operation being performed. Value may be one of:
18974 Roo.data.Record.EDIT
18975 Roo.data.Record.REJECT
18976 Roo.data.Record.COMMIT
18982 * Fires when the data cache has been cleared.
18983 * @param {Store} this
18987 * @event beforeload
18988 * Fires before a request is made for a new data object. If the beforeload handler returns false
18989 * the load action will be canceled.
18990 * @param {Store} this
18991 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18996 * Fires after a new set of Records has been loaded.
18997 * @param {Store} this
18998 * @param {Roo.data.Record[]} records The Records that were loaded
18999 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19003 * @event loadexception
19004 * Fires if an exception occurs in the Proxy during loading.
19005 * Called with the signature of the Proxy's "loadexception" event.
19006 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19009 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19010 * @param {Object} load options
19011 * @param {Object} jsonData from your request (normally this contains the Exception)
19013 loadexception : true
19017 this.proxy = Roo.factory(this.proxy, Roo.data);
19018 this.proxy.xmodule = this.xmodule || false;
19019 this.relayEvents(this.proxy, ["loadexception"]);
19021 this.sortToggle = {};
19023 Roo.data.Store.superclass.constructor.call(this);
19025 if(this.inlineData){
19026 this.loadData(this.inlineData);
19027 delete this.inlineData;
19030 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19032 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19033 * without a remote query - used by combo/forms at present.
19037 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19040 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19043 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19044 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19047 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19048 * on any HTTP request
19051 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19054 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19055 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19057 remoteSort : false,
19060 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19061 * loaded or when a record is removed. (defaults to false).
19063 pruneModifiedRecords : false,
19066 lastOptions : null,
19069 * Add Records to the Store and fires the add event.
19070 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19072 add : function(records){
19073 records = [].concat(records);
19074 for(var i = 0, len = records.length; i < len; i++){
19075 records[i].join(this);
19077 var index = this.data.length;
19078 this.data.addAll(records);
19079 this.fireEvent("add", this, records, index);
19083 * Remove a Record from the Store and fires the remove event.
19084 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19086 remove : function(record){
19087 var index = this.data.indexOf(record);
19088 this.data.removeAt(index);
19089 if(this.pruneModifiedRecords){
19090 this.modified.remove(record);
19092 this.fireEvent("remove", this, record, index);
19096 * Remove all Records from the Store and fires the clear event.
19098 removeAll : function(){
19100 if(this.pruneModifiedRecords){
19101 this.modified = [];
19103 this.fireEvent("clear", this);
19107 * Inserts Records to the Store at the given index and fires the add event.
19108 * @param {Number} index The start index at which to insert the passed Records.
19109 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19111 insert : function(index, records){
19112 records = [].concat(records);
19113 for(var i = 0, len = records.length; i < len; i++){
19114 this.data.insert(index, records[i]);
19115 records[i].join(this);
19117 this.fireEvent("add", this, records, index);
19121 * Get the index within the cache of the passed Record.
19122 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19123 * @return {Number} The index of the passed Record. Returns -1 if not found.
19125 indexOf : function(record){
19126 return this.data.indexOf(record);
19130 * Get the index within the cache of the Record with the passed id.
19131 * @param {String} id The id of the Record to find.
19132 * @return {Number} The index of the Record. Returns -1 if not found.
19134 indexOfId : function(id){
19135 return this.data.indexOfKey(id);
19139 * Get the Record with the specified id.
19140 * @param {String} id The id of the Record to find.
19141 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19143 getById : function(id){
19144 return this.data.key(id);
19148 * Get the Record at the specified index.
19149 * @param {Number} index The index of the Record to find.
19150 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19152 getAt : function(index){
19153 return this.data.itemAt(index);
19157 * Returns a range of Records between specified indices.
19158 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19159 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19160 * @return {Roo.data.Record[]} An array of Records
19162 getRange : function(start, end){
19163 return this.data.getRange(start, end);
19167 storeOptions : function(o){
19168 o = Roo.apply({}, o);
19171 this.lastOptions = o;
19175 * Loads the Record cache from the configured Proxy using the configured Reader.
19177 * If using remote paging, then the first load call must specify the <em>start</em>
19178 * and <em>limit</em> properties in the options.params property to establish the initial
19179 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19181 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19182 * and this call will return before the new data has been loaded. Perform any post-processing
19183 * in a callback function, or in a "load" event handler.</strong>
19185 * @param {Object} options An object containing properties which control loading options:<ul>
19186 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19187 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19188 * passed the following arguments:<ul>
19189 * <li>r : Roo.data.Record[]</li>
19190 * <li>options: Options object from the load call</li>
19191 * <li>success: Boolean success indicator</li></ul></li>
19192 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19193 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19196 load : function(options){
19197 options = options || {};
19198 if(this.fireEvent("beforeload", this, options) !== false){
19199 this.storeOptions(options);
19200 var p = Roo.apply(options.params || {}, this.baseParams);
19201 if(this.sortInfo && this.remoteSort){
19202 var pn = this.paramNames;
19203 p[pn["sort"]] = this.sortInfo.field;
19204 p[pn["dir"]] = this.sortInfo.direction;
19206 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19211 * Reloads the Record cache from the configured Proxy using the configured Reader and
19212 * the options from the last load operation performed.
19213 * @param {Object} options (optional) An object containing properties which may override the options
19214 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19215 * the most recently used options are reused).
19217 reload : function(options){
19218 this.load(Roo.applyIf(options||{}, this.lastOptions));
19222 // Called as a callback by the Reader during a load operation.
19223 loadRecords : function(o, options, success){
19224 if(!o || success === false){
19225 if(success !== false){
19226 this.fireEvent("load", this, [], options);
19228 if(options.callback){
19229 options.callback.call(options.scope || this, [], options, false);
19233 // if data returned failure - throw an exception.
19234 if (o.success === false) {
19235 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19238 var r = o.records, t = o.totalRecords || r.length;
19239 if(!options || options.add !== true){
19240 if(this.pruneModifiedRecords){
19241 this.modified = [];
19243 for(var i = 0, len = r.length; i < len; i++){
19247 this.data = this.snapshot;
19248 delete this.snapshot;
19251 this.data.addAll(r);
19252 this.totalLength = t;
19254 this.fireEvent("datachanged", this);
19256 this.totalLength = Math.max(t, this.data.length+r.length);
19259 this.fireEvent("load", this, r, options);
19260 if(options.callback){
19261 options.callback.call(options.scope || this, r, options, true);
19266 * Loads data from a passed data block. A Reader which understands the format of the data
19267 * must have been configured in the constructor.
19268 * @param {Object} data The data block from which to read the Records. The format of the data expected
19269 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19270 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19272 loadData : function(o, append){
19273 var r = this.reader.readRecords(o);
19274 this.loadRecords(r, {add: append}, true);
19278 * Gets the number of cached records.
19280 * <em>If using paging, this may not be the total size of the dataset. If the data object
19281 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19282 * the data set size</em>
19284 getCount : function(){
19285 return this.data.length || 0;
19289 * Gets the total number of records in the dataset as returned by the server.
19291 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19292 * the dataset size</em>
19294 getTotalCount : function(){
19295 return this.totalLength || 0;
19299 * Returns the sort state of the Store as an object with two properties:
19301 field {String} The name of the field by which the Records are sorted
19302 direction {String} The sort order, "ASC" or "DESC"
19305 getSortState : function(){
19306 return this.sortInfo;
19310 applySort : function(){
19311 if(this.sortInfo && !this.remoteSort){
19312 var s = this.sortInfo, f = s.field;
19313 var st = this.fields.get(f).sortType;
19314 var fn = function(r1, r2){
19315 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19316 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19318 this.data.sort(s.direction, fn);
19319 if(this.snapshot && this.snapshot != this.data){
19320 this.snapshot.sort(s.direction, fn);
19326 * Sets the default sort column and order to be used by the next load operation.
19327 * @param {String} fieldName The name of the field to sort by.
19328 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19330 setDefaultSort : function(field, dir){
19331 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19335 * Sort the Records.
19336 * If remote sorting is used, the sort is performed on the server, and the cache is
19337 * reloaded. If local sorting is used, the cache is sorted internally.
19338 * @param {String} fieldName The name of the field to sort by.
19339 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19341 sort : function(fieldName, dir){
19342 var f = this.fields.get(fieldName);
19344 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19345 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19350 this.sortToggle[f.name] = dir;
19351 this.sortInfo = {field: f.name, direction: dir};
19352 if(!this.remoteSort){
19354 this.fireEvent("datachanged", this);
19356 this.load(this.lastOptions);
19361 * Calls the specified function for each of the Records in the cache.
19362 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19363 * Returning <em>false</em> aborts and exits the iteration.
19364 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19366 each : function(fn, scope){
19367 this.data.each(fn, scope);
19371 * Gets all records modified since the last commit. Modified records are persisted across load operations
19372 * (e.g., during paging).
19373 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19375 getModifiedRecords : function(){
19376 return this.modified;
19380 createFilterFn : function(property, value, anyMatch){
19381 if(!value.exec){ // not a regex
19382 value = String(value);
19383 if(value.length == 0){
19386 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19388 return function(r){
19389 return value.test(r.data[property]);
19394 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19395 * @param {String} property A field on your records
19396 * @param {Number} start The record index to start at (defaults to 0)
19397 * @param {Number} end The last record index to include (defaults to length - 1)
19398 * @return {Number} The sum
19400 sum : function(property, start, end){
19401 var rs = this.data.items, v = 0;
19402 start = start || 0;
19403 end = (end || end === 0) ? end : rs.length-1;
19405 for(var i = start; i <= end; i++){
19406 v += (rs[i].data[property] || 0);
19412 * Filter the records by a specified property.
19413 * @param {String} field A field on your records
19414 * @param {String/RegExp} value Either a string that the field
19415 * should start with or a RegExp to test against the field
19416 * @param {Boolean} anyMatch True to match any part not just the beginning
19418 filter : function(property, value, anyMatch){
19419 var fn = this.createFilterFn(property, value, anyMatch);
19420 return fn ? this.filterBy(fn) : this.clearFilter();
19424 * Filter by a function. The specified function will be called with each
19425 * record in this data source. If the function returns true the record is included,
19426 * otherwise it is filtered.
19427 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19428 * @param {Object} scope (optional) The scope of the function (defaults to this)
19430 filterBy : function(fn, scope){
19431 this.snapshot = this.snapshot || this.data;
19432 this.data = this.queryBy(fn, scope||this);
19433 this.fireEvent("datachanged", this);
19437 * Query the records by a specified property.
19438 * @param {String} field A field on your records
19439 * @param {String/RegExp} value Either a string that the field
19440 * should start with or a RegExp to test against the field
19441 * @param {Boolean} anyMatch True to match any part not just the beginning
19442 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19444 query : function(property, value, anyMatch){
19445 var fn = this.createFilterFn(property, value, anyMatch);
19446 return fn ? this.queryBy(fn) : this.data.clone();
19450 * Query by a function. The specified function will be called with each
19451 * record in this data source. If the function returns true the record is included
19453 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19454 * @param {Object} scope (optional) The scope of the function (defaults to this)
19455 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19457 queryBy : function(fn, scope){
19458 var data = this.snapshot || this.data;
19459 return data.filterBy(fn, scope||this);
19463 * Collects unique values for a particular dataIndex from this store.
19464 * @param {String} dataIndex The property to collect
19465 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19466 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19467 * @return {Array} An array of the unique values
19469 collect : function(dataIndex, allowNull, bypassFilter){
19470 var d = (bypassFilter === true && this.snapshot) ?
19471 this.snapshot.items : this.data.items;
19472 var v, sv, r = [], l = {};
19473 for(var i = 0, len = d.length; i < len; i++){
19474 v = d[i].data[dataIndex];
19476 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19485 * Revert to a view of the Record cache with no filtering applied.
19486 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19488 clearFilter : function(suppressEvent){
19489 if(this.snapshot && this.snapshot != this.data){
19490 this.data = this.snapshot;
19491 delete this.snapshot;
19492 if(suppressEvent !== true){
19493 this.fireEvent("datachanged", this);
19499 afterEdit : function(record){
19500 if(this.modified.indexOf(record) == -1){
19501 this.modified.push(record);
19503 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19507 afterReject : function(record){
19508 this.modified.remove(record);
19509 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19513 afterCommit : function(record){
19514 this.modified.remove(record);
19515 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19519 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19520 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19522 commitChanges : function(){
19523 var m = this.modified.slice(0);
19524 this.modified = [];
19525 for(var i = 0, len = m.length; i < len; i++){
19531 * Cancel outstanding changes on all changed records.
19533 rejectChanges : function(){
19534 var m = this.modified.slice(0);
19535 this.modified = [];
19536 for(var i = 0, len = m.length; i < len; i++){
19541 onMetaChange : function(meta, rtype, o){
19542 this.recordType = rtype;
19543 this.fields = rtype.prototype.fields;
19544 delete this.snapshot;
19545 this.sortInfo = meta.sortInfo;
19546 this.modified = [];
19547 this.fireEvent('metachange', this, this.reader.meta);
19551 * Ext JS Library 1.1.1
19552 * Copyright(c) 2006-2007, Ext JS, LLC.
19554 * Originally Released Under LGPL - original licence link has changed is not relivant.
19557 * <script type="text/javascript">
19561 * @class Roo.data.SimpleStore
19562 * @extends Roo.data.Store
19563 * Small helper class to make creating Stores from Array data easier.
19564 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19565 * @cfg {Array} fields An array of field definition objects, or field name strings.
19566 * @cfg {Array} data The multi-dimensional array of data
19568 * @param {Object} config
19570 Roo.data.SimpleStore = function(config){
19571 Roo.data.SimpleStore.superclass.constructor.call(this, {
19573 reader: new Roo.data.ArrayReader({
19576 Roo.data.Record.create(config.fields)
19578 proxy : new Roo.data.MemoryProxy(config.data)
19582 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19584 * Ext JS Library 1.1.1
19585 * Copyright(c) 2006-2007, Ext JS, LLC.
19587 * Originally Released Under LGPL - original licence link has changed is not relivant.
19590 * <script type="text/javascript">
19595 * @extends Roo.data.Store
19596 * @class Roo.data.JsonStore
19597 * Small helper class to make creating Stores for JSON data easier. <br/>
19599 var store = new Roo.data.JsonStore({
19600 url: 'get-images.php',
19602 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19605 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19606 * JsonReader and HttpProxy (unless inline data is provided).</b>
19607 * @cfg {Array} fields An array of field definition objects, or field name strings.
19609 * @param {Object} config
19611 Roo.data.JsonStore = function(c){
19612 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19613 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19614 reader: new Roo.data.JsonReader(c, c.fields)
19617 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19619 * Ext JS Library 1.1.1
19620 * Copyright(c) 2006-2007, Ext JS, LLC.
19622 * Originally Released Under LGPL - original licence link has changed is not relivant.
19625 * <script type="text/javascript">
19629 Roo.data.Field = function(config){
19630 if(typeof config == "string"){
19631 config = {name: config};
19633 Roo.apply(this, config);
19636 this.type = "auto";
19639 var st = Roo.data.SortTypes;
19640 // named sortTypes are supported, here we look them up
19641 if(typeof this.sortType == "string"){
19642 this.sortType = st[this.sortType];
19645 // set default sortType for strings and dates
19646 if(!this.sortType){
19649 this.sortType = st.asUCString;
19652 this.sortType = st.asDate;
19655 this.sortType = st.none;
19660 var stripRe = /[\$,%]/g;
19662 // prebuilt conversion function for this field, instead of
19663 // switching every time we're reading a value
19665 var cv, dateFormat = this.dateFormat;
19670 cv = function(v){ return v; };
19673 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19677 return v !== undefined && v !== null && v !== '' ?
19678 parseInt(String(v).replace(stripRe, ""), 10) : '';
19683 return v !== undefined && v !== null && v !== '' ?
19684 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19689 cv = function(v){ return v === true || v === "true" || v == 1; };
19696 if(v instanceof Date){
19700 if(dateFormat == "timestamp"){
19701 return new Date(v*1000);
19703 return Date.parseDate(v, dateFormat);
19705 var parsed = Date.parse(v);
19706 return parsed ? new Date(parsed) : null;
19715 Roo.data.Field.prototype = {
19723 * Ext JS Library 1.1.1
19724 * Copyright(c) 2006-2007, Ext JS, LLC.
19726 * Originally Released Under LGPL - original licence link has changed is not relivant.
19729 * <script type="text/javascript">
19732 // Base class for reading structured data from a data source. This class is intended to be
19733 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19736 * @class Roo.data.DataReader
19737 * Base class for reading structured data from a data source. This class is intended to be
19738 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19741 Roo.data.DataReader = function(meta, recordType){
19745 this.recordType = recordType instanceof Array ?
19746 Roo.data.Record.create(recordType) : recordType;
19749 Roo.data.DataReader.prototype = {
19751 * Create an empty record
19752 * @param {Object} data (optional) - overlay some values
19753 * @return {Roo.data.Record} record created.
19755 newRow : function(d) {
19757 this.recordType.prototype.fields.each(function(c) {
19759 case 'int' : da[c.name] = 0; break;
19760 case 'date' : da[c.name] = new Date(); break;
19761 case 'float' : da[c.name] = 0.0; break;
19762 case 'boolean' : da[c.name] = false; break;
19763 default : da[c.name] = ""; break;
19767 return new this.recordType(Roo.apply(da, d));
19772 * Ext JS Library 1.1.1
19773 * Copyright(c) 2006-2007, Ext JS, LLC.
19775 * Originally Released Under LGPL - original licence link has changed is not relivant.
19778 * <script type="text/javascript">
19782 * @class Roo.data.DataProxy
19783 * @extends Roo.data.Observable
19784 * This class is an abstract base class for implementations which provide retrieval of
19785 * unformatted data objects.<br>
19787 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19788 * (of the appropriate type which knows how to parse the data object) to provide a block of
19789 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19791 * Custom implementations must implement the load method as described in
19792 * {@link Roo.data.HttpProxy#load}.
19794 Roo.data.DataProxy = function(){
19797 * @event beforeload
19798 * Fires before a network request is made to retrieve a data object.
19799 * @param {Object} This DataProxy object.
19800 * @param {Object} params The params parameter to the load function.
19805 * Fires before the load method's callback is called.
19806 * @param {Object} This DataProxy object.
19807 * @param {Object} o The data object.
19808 * @param {Object} arg The callback argument object passed to the load function.
19812 * @event loadexception
19813 * Fires if an Exception occurs during data retrieval.
19814 * @param {Object} This DataProxy object.
19815 * @param {Object} o The data object.
19816 * @param {Object} arg The callback argument object passed to the load function.
19817 * @param {Object} e The Exception.
19819 loadexception : true
19821 Roo.data.DataProxy.superclass.constructor.call(this);
19824 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
19827 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
19831 * Ext JS Library 1.1.1
19832 * Copyright(c) 2006-2007, Ext JS, LLC.
19834 * Originally Released Under LGPL - original licence link has changed is not relivant.
19837 * <script type="text/javascript">
19840 * @class Roo.data.MemoryProxy
19841 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
19842 * to the Reader when its load method is called.
19844 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
19846 Roo.data.MemoryProxy = function(data){
19850 Roo.data.MemoryProxy.superclass.constructor.call(this);
19854 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
19856 * Load data from the requested source (in this case an in-memory
19857 * data object passed to the constructor), read the data object into
19858 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
19859 * process that block using the passed callback.
19860 * @param {Object} params This parameter is not used by the MemoryProxy class.
19861 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19862 * object into a block of Roo.data.Records.
19863 * @param {Function} callback The function into which to pass the block of Roo.data.records.
19864 * The function must be passed <ul>
19865 * <li>The Record block object</li>
19866 * <li>The "arg" argument from the load function</li>
19867 * <li>A boolean success indicator</li>
19869 * @param {Object} scope The scope in which to call the callback
19870 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19872 load : function(params, reader, callback, scope, arg){
19873 params = params || {};
19876 result = reader.readRecords(this.data);
19878 this.fireEvent("loadexception", this, arg, null, e);
19879 callback.call(scope, null, arg, false);
19882 callback.call(scope, result, arg, true);
19886 update : function(params, records){
19891 * Ext JS Library 1.1.1
19892 * Copyright(c) 2006-2007, Ext JS, LLC.
19894 * Originally Released Under LGPL - original licence link has changed is not relivant.
19897 * <script type="text/javascript">
19900 * @class Roo.data.HttpProxy
19901 * @extends Roo.data.DataProxy
19902 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
19903 * configured to reference a certain URL.<br><br>
19905 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
19906 * from which the running page was served.<br><br>
19908 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
19910 * Be aware that to enable the browser to parse an XML document, the server must set
19911 * the Content-Type header in the HTTP response to "text/xml".
19913 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
19914 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
19915 * will be used to make the request.
19917 Roo.data.HttpProxy = function(conn){
19918 Roo.data.HttpProxy.superclass.constructor.call(this);
19919 // is conn a conn config or a real conn?
19921 this.useAjax = !conn || !conn.events;
19925 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
19926 // thse are take from connection...
19929 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
19932 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
19933 * extra parameters to each request made by this object. (defaults to undefined)
19936 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
19937 * to each request made by this object. (defaults to undefined)
19940 * @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)
19943 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
19946 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
19952 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
19956 * Return the {@link Roo.data.Connection} object being used by this Proxy.
19957 * @return {Connection} The Connection object. This object may be used to subscribe to events on
19958 * a finer-grained basis than the DataProxy events.
19960 getConnection : function(){
19961 return this.useAjax ? Roo.Ajax : this.conn;
19965 * Load data from the configured {@link Roo.data.Connection}, read the data object into
19966 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
19967 * process that block using the passed callback.
19968 * @param {Object} params An object containing properties which are to be used as HTTP parameters
19969 * for the request to the remote server.
19970 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19971 * object into a block of Roo.data.Records.
19972 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
19973 * The function must be passed <ul>
19974 * <li>The Record block object</li>
19975 * <li>The "arg" argument from the load function</li>
19976 * <li>A boolean success indicator</li>
19978 * @param {Object} scope The scope in which to call the callback
19979 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19981 load : function(params, reader, callback, scope, arg){
19982 if(this.fireEvent("beforeload", this, params) !== false){
19984 params : params || {},
19986 callback : callback,
19991 callback : this.loadResponse,
19995 Roo.applyIf(o, this.conn);
19996 if(this.activeRequest){
19997 Roo.Ajax.abort(this.activeRequest);
19999 this.activeRequest = Roo.Ajax.request(o);
20001 this.conn.request(o);
20004 callback.call(scope||this, null, arg, false);
20009 loadResponse : function(o, success, response){
20010 delete this.activeRequest;
20012 this.fireEvent("loadexception", this, o, response);
20013 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20018 result = o.reader.read(response);
20020 this.fireEvent("loadexception", this, o, response, e);
20021 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20025 this.fireEvent("load", this, o, o.request.arg);
20026 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20030 update : function(dataSet){
20035 updateResponse : function(dataSet){
20040 * Ext JS Library 1.1.1
20041 * Copyright(c) 2006-2007, Ext JS, LLC.
20043 * Originally Released Under LGPL - original licence link has changed is not relivant.
20046 * <script type="text/javascript">
20050 * @class Roo.data.ScriptTagProxy
20051 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20052 * other than the originating domain of the running page.<br><br>
20054 * <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
20055 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20057 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20058 * source code that is used as the source inside a <script> tag.<br><br>
20060 * In order for the browser to process the returned data, the server must wrap the data object
20061 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20062 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20063 * depending on whether the callback name was passed:
20066 boolean scriptTag = false;
20067 String cb = request.getParameter("callback");
20070 response.setContentType("text/javascript");
20072 response.setContentType("application/x-json");
20074 Writer out = response.getWriter();
20076 out.write(cb + "(");
20078 out.print(dataBlock.toJsonString());
20085 * @param {Object} config A configuration object.
20087 Roo.data.ScriptTagProxy = function(config){
20088 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20089 Roo.apply(this, config);
20090 this.head = document.getElementsByTagName("head")[0];
20093 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20095 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20097 * @cfg {String} url The URL from which to request the data object.
20100 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20104 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20105 * the server the name of the callback function set up by the load call to process the returned data object.
20106 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20107 * javascript output which calls this named function passing the data object as its only parameter.
20109 callbackParam : "callback",
20111 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20112 * name to the request.
20117 * Load data from the configured URL, read the data object into
20118 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20119 * process that block using the passed callback.
20120 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20121 * for the request to the remote server.
20122 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20123 * object into a block of Roo.data.Records.
20124 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20125 * The function must be passed <ul>
20126 * <li>The Record block object</li>
20127 * <li>The "arg" argument from the load function</li>
20128 * <li>A boolean success indicator</li>
20130 * @param {Object} scope The scope in which to call the callback
20131 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20133 load : function(params, reader, callback, scope, arg){
20134 if(this.fireEvent("beforeload", this, params) !== false){
20136 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20138 var url = this.url;
20139 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20141 url += "&_dc=" + (new Date().getTime());
20143 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20146 cb : "stcCallback"+transId,
20147 scriptId : "stcScript"+transId,
20151 callback : callback,
20157 window[trans.cb] = function(o){
20158 conn.handleResponse(o, trans);
20161 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20163 if(this.autoAbort !== false){
20167 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20169 var script = document.createElement("script");
20170 script.setAttribute("src", url);
20171 script.setAttribute("type", "text/javascript");
20172 script.setAttribute("id", trans.scriptId);
20173 this.head.appendChild(script);
20175 this.trans = trans;
20177 callback.call(scope||this, null, arg, false);
20182 isLoading : function(){
20183 return this.trans ? true : false;
20187 * Abort the current server request.
20189 abort : function(){
20190 if(this.isLoading()){
20191 this.destroyTrans(this.trans);
20196 destroyTrans : function(trans, isLoaded){
20197 this.head.removeChild(document.getElementById(trans.scriptId));
20198 clearTimeout(trans.timeoutId);
20200 window[trans.cb] = undefined;
20202 delete window[trans.cb];
20205 // if hasn't been loaded, wait for load to remove it to prevent script error
20206 window[trans.cb] = function(){
20207 window[trans.cb] = undefined;
20209 delete window[trans.cb];
20216 handleResponse : function(o, trans){
20217 this.trans = false;
20218 this.destroyTrans(trans, true);
20221 result = trans.reader.readRecords(o);
20223 this.fireEvent("loadexception", this, o, trans.arg, e);
20224 trans.callback.call(trans.scope||window, null, trans.arg, false);
20227 this.fireEvent("load", this, o, trans.arg);
20228 trans.callback.call(trans.scope||window, result, trans.arg, true);
20232 handleFailure : function(trans){
20233 this.trans = false;
20234 this.destroyTrans(trans, false);
20235 this.fireEvent("loadexception", this, null, trans.arg);
20236 trans.callback.call(trans.scope||window, null, trans.arg, false);
20240 * Ext JS Library 1.1.1
20241 * Copyright(c) 2006-2007, Ext JS, LLC.
20243 * Originally Released Under LGPL - original licence link has changed is not relivant.
20246 * <script type="text/javascript">
20250 * @class Roo.data.JsonReader
20251 * @extends Roo.data.DataReader
20252 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20253 * based on mappings in a provided Roo.data.Record constructor.
20257 var RecordDef = Roo.data.Record.create([
20258 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20259 {name: 'occupation'} // This field will use "occupation" as the mapping.
20261 var myReader = new Roo.data.JsonReader({
20262 totalProperty: "results", // The property which contains the total dataset size (optional)
20263 root: "rows", // The property which contains an Array of row objects
20264 id: "id" // The property within each row object that provides an ID for the record (optional)
20268 * This would consume a JSON file like this:
20270 { 'results': 2, 'rows': [
20271 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20272 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20275 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20276 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20277 * paged from the remote server.
20278 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20279 * @cfg {String} root name of the property which contains the Array of row objects.
20280 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20282 * Create a new JsonReader
20283 * @param {Object} meta Metadata configuration options
20284 * @param {Object} recordType Either an Array of field definition objects,
20285 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20287 Roo.data.JsonReader = function(meta, recordType){
20290 // set some defaults:
20291 Roo.applyIf(meta, {
20292 totalProperty: 'total',
20293 successProperty : 'success',
20298 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20300 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20302 * This method is only used by a DataProxy which has retrieved data from a remote server.
20303 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20304 * @return {Object} data A data block which is used by an Roo.data.Store object as
20305 * a cache of Roo.data.Records.
20307 read : function(response){
20308 var json = response.responseText;
20310 var o = eval("("+json+")");
20312 throw {message: "JsonReader.read: Json object not found"};
20317 this.meta = o.metaData;
20318 this.recordType = Roo.data.Record.create(o.metaData.fields);
20319 this.onMetaChange(this.meta, this.recordType, o);
20321 return this.readRecords(o);
20324 // private function a store will implement
20325 onMetaChange : function(meta, recordType, o){
20332 simpleAccess: function(obj, subsc) {
20339 getJsonAccessor: function(){
20341 return function(expr) {
20343 return(re.test(expr))
20344 ? new Function("obj", "return obj." + expr)
20349 return Roo.emptyFn;
20354 * Create a data block containing Roo.data.Records from an XML document.
20355 * @param {Object} o An object which contains an Array of row objects in the property specified
20356 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20357 * which contains the total size of the dataset.
20358 * @return {Object} data A data block which is used by an Roo.data.Store object as
20359 * a cache of Roo.data.Records.
20361 readRecords : function(o){
20363 * After any data loads, the raw JSON data is available for further custom processing.
20367 var s = this.meta, Record = this.recordType,
20368 f = Record.prototype.fields, fi = f.items, fl = f.length;
20370 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20372 if(s.totalProperty) {
20373 this.getTotal = this.getJsonAccessor(s.totalProperty);
20375 if(s.successProperty) {
20376 this.getSuccess = this.getJsonAccessor(s.successProperty);
20378 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20380 var g = this.getJsonAccessor(s.id);
20381 this.getId = function(rec) {
20383 return (r === undefined || r === "") ? null : r;
20386 this.getId = function(){return null;};
20389 for(var i = 0; i < fl; i++){
20391 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20392 this.ef[i] = this.getJsonAccessor(map);
20396 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20397 if(s.totalProperty){
20398 var v = parseInt(this.getTotal(o), 10);
20403 if(s.successProperty){
20404 var v = this.getSuccess(o);
20405 if(v === false || v === 'false'){
20410 for(var i = 0; i < c; i++){
20413 var id = this.getId(n);
20414 for(var j = 0; j < fl; j++){
20416 var v = this.ef[j](n);
20417 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20419 var record = new Record(values, id);
20421 records[i] = record;
20426 totalRecords : totalRecords
20431 * Ext JS Library 1.1.1
20432 * Copyright(c) 2006-2007, Ext JS, LLC.
20434 * Originally Released Under LGPL - original licence link has changed is not relivant.
20437 * <script type="text/javascript">
20441 * @class Roo.data.XmlReader
20442 * @extends Roo.data.DataReader
20443 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20444 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20446 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20447 * header in the HTTP response must be set to "text/xml".</em>
20451 var RecordDef = Roo.data.Record.create([
20452 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20453 {name: 'occupation'} // This field will use "occupation" as the mapping.
20455 var myReader = new Roo.data.XmlReader({
20456 totalRecords: "results", // The element which contains the total dataset size (optional)
20457 record: "row", // The repeated element which contains row information
20458 id: "id" // The element within the row that provides an ID for the record (optional)
20462 * This would consume an XML file like this:
20466 <results>2</results>
20469 <name>Bill</name>
20470 <occupation>Gardener</occupation>
20474 <name>Ben</name>
20475 <occupation>Horticulturalist</occupation>
20479 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20480 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20481 * paged from the remote server.
20482 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20483 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20484 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20485 * a record identifier value.
20487 * Create a new XmlReader
20488 * @param {Object} meta Metadata configuration options
20489 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20490 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20491 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20493 Roo.data.XmlReader = function(meta, recordType){
20495 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20497 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20499 * This method is only used by a DataProxy which has retrieved data from a remote server.
20500 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20501 * to contain a method called 'responseXML' that returns an XML document object.
20502 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20503 * a cache of Roo.data.Records.
20505 read : function(response){
20506 var doc = response.responseXML;
20508 throw {message: "XmlReader.read: XML Document not available"};
20510 return this.readRecords(doc);
20514 * Create a data block containing Roo.data.Records from an XML document.
20515 * @param {Object} doc A parsed XML document.
20516 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20517 * a cache of Roo.data.Records.
20519 readRecords : function(doc){
20521 * After any data loads/reads, the raw XML Document is available for further custom processing.
20522 * @type XMLDocument
20524 this.xmlData = doc;
20525 var root = doc.documentElement || doc;
20526 var q = Roo.DomQuery;
20527 var recordType = this.recordType, fields = recordType.prototype.fields;
20528 var sid = this.meta.id;
20529 var totalRecords = 0, success = true;
20530 if(this.meta.totalRecords){
20531 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20534 if(this.meta.success){
20535 var sv = q.selectValue(this.meta.success, root, true);
20536 success = sv !== false && sv !== 'false';
20539 var ns = q.select(this.meta.record, root);
20540 for(var i = 0, len = ns.length; i < len; i++) {
20543 var id = sid ? q.selectValue(sid, n) : undefined;
20544 for(var j = 0, jlen = fields.length; j < jlen; j++){
20545 var f = fields.items[j];
20546 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20548 values[f.name] = v;
20550 var record = new recordType(values, id);
20552 records[records.length] = record;
20558 totalRecords : totalRecords || records.length
20563 * Ext JS Library 1.1.1
20564 * Copyright(c) 2006-2007, Ext JS, LLC.
20566 * Originally Released Under LGPL - original licence link has changed is not relivant.
20569 * <script type="text/javascript">
20573 * @class Roo.data.ArrayReader
20574 * @extends Roo.data.DataReader
20575 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20576 * Each element of that Array represents a row of data fields. The
20577 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20578 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20582 var RecordDef = Roo.data.Record.create([
20583 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20584 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20586 var myReader = new Roo.data.ArrayReader({
20587 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20591 * This would consume an Array like this:
20593 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20595 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20597 * Create a new JsonReader
20598 * @param {Object} meta Metadata configuration options.
20599 * @param {Object} recordType Either an Array of field definition objects
20600 * as specified to {@link Roo.data.Record#create},
20601 * or an {@link Roo.data.Record} object
20602 * created using {@link Roo.data.Record#create}.
20604 Roo.data.ArrayReader = function(meta, recordType){
20605 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20608 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20610 * Create a data block containing Roo.data.Records from an XML document.
20611 * @param {Object} o An Array of row objects which represents the dataset.
20612 * @return {Object} data A data block which is used by an Roo.data.Store object as
20613 * a cache of Roo.data.Records.
20615 readRecords : function(o){
20616 var sid = this.meta ? this.meta.id : null;
20617 var recordType = this.recordType, fields = recordType.prototype.fields;
20620 for(var i = 0; i < root.length; i++){
20623 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20624 for(var j = 0, jlen = fields.length; j < jlen; j++){
20625 var f = fields.items[j];
20626 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20627 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20629 values[f.name] = v;
20631 var record = new recordType(values, id);
20633 records[records.length] = record;
20637 totalRecords : records.length
20642 * Ext JS Library 1.1.1
20643 * Copyright(c) 2006-2007, Ext JS, LLC.
20645 * Originally Released Under LGPL - original licence link has changed is not relivant.
20648 * <script type="text/javascript">
20653 * @class Roo.data.Tree
20654 * @extends Roo.util.Observable
20655 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20656 * in the tree have most standard DOM functionality.
20658 * @param {Node} root (optional) The root node
20660 Roo.data.Tree = function(root){
20661 this.nodeHash = {};
20663 * The root node for this tree
20668 this.setRootNode(root);
20673 * Fires when a new child node is appended to a node in this tree.
20674 * @param {Tree} tree The owner tree
20675 * @param {Node} parent The parent node
20676 * @param {Node} node The newly appended node
20677 * @param {Number} index The index of the newly appended node
20682 * Fires when a child node is removed from a node in this tree.
20683 * @param {Tree} tree The owner tree
20684 * @param {Node} parent The parent node
20685 * @param {Node} node The child node removed
20690 * Fires when a node is moved to a new location in the tree
20691 * @param {Tree} tree The owner tree
20692 * @param {Node} node The node moved
20693 * @param {Node} oldParent The old parent of this node
20694 * @param {Node} newParent The new parent of this node
20695 * @param {Number} index The index it was moved to
20700 * Fires when a new child node is inserted in a node in this tree.
20701 * @param {Tree} tree The owner tree
20702 * @param {Node} parent The parent node
20703 * @param {Node} node The child node inserted
20704 * @param {Node} refNode The child node the node was inserted before
20708 * @event beforeappend
20709 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20710 * @param {Tree} tree The owner tree
20711 * @param {Node} parent The parent node
20712 * @param {Node} node The child node to be appended
20714 "beforeappend" : true,
20716 * @event beforeremove
20717 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20718 * @param {Tree} tree The owner tree
20719 * @param {Node} parent The parent node
20720 * @param {Node} node The child node to be removed
20722 "beforeremove" : true,
20724 * @event beforemove
20725 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20726 * @param {Tree} tree The owner tree
20727 * @param {Node} node The node being moved
20728 * @param {Node} oldParent The parent of the node
20729 * @param {Node} newParent The new parent the node is moving to
20730 * @param {Number} index The index it is being moved to
20732 "beforemove" : true,
20734 * @event beforeinsert
20735 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20736 * @param {Tree} tree The owner tree
20737 * @param {Node} parent The parent node
20738 * @param {Node} node The child node to be inserted
20739 * @param {Node} refNode The child node the node is being inserted before
20741 "beforeinsert" : true
20744 Roo.data.Tree.superclass.constructor.call(this);
20747 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20748 pathSeparator: "/",
20750 proxyNodeEvent : function(){
20751 return this.fireEvent.apply(this, arguments);
20755 * Returns the root node for this tree.
20758 getRootNode : function(){
20763 * Sets the root node for this tree.
20764 * @param {Node} node
20767 setRootNode : function(node){
20769 node.ownerTree = this;
20770 node.isRoot = true;
20771 this.registerNode(node);
20776 * Gets a node in this tree by its id.
20777 * @param {String} id
20780 getNodeById : function(id){
20781 return this.nodeHash[id];
20784 registerNode : function(node){
20785 this.nodeHash[node.id] = node;
20788 unregisterNode : function(node){
20789 delete this.nodeHash[node.id];
20792 toString : function(){
20793 return "[Tree"+(this.id?" "+this.id:"")+"]";
20798 * @class Roo.data.Node
20799 * @extends Roo.util.Observable
20800 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
20801 * @cfg {String} id The id for this node. If one is not specified, one is generated.
20803 * @param {Object} attributes The attributes/config for the node
20805 Roo.data.Node = function(attributes){
20807 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
20810 this.attributes = attributes || {};
20811 this.leaf = this.attributes.leaf;
20813 * The node id. @type String
20815 this.id = this.attributes.id;
20817 this.id = Roo.id(null, "ynode-");
20818 this.attributes.id = this.id;
20821 * All child nodes of this node. @type Array
20823 this.childNodes = [];
20824 if(!this.childNodes.indexOf){ // indexOf is a must
20825 this.childNodes.indexOf = function(o){
20826 for(var i = 0, len = this.length; i < len; i++){
20827 if(this[i] == o) return i;
20833 * The parent node for this node. @type Node
20835 this.parentNode = null;
20837 * The first direct child node of this node, or null if this node has no child nodes. @type Node
20839 this.firstChild = null;
20841 * The last direct child node of this node, or null if this node has no child nodes. @type Node
20843 this.lastChild = null;
20845 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
20847 this.previousSibling = null;
20849 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
20851 this.nextSibling = null;
20856 * Fires when a new child node is appended
20857 * @param {Tree} tree The owner tree
20858 * @param {Node} this This node
20859 * @param {Node} node The newly appended node
20860 * @param {Number} index The index of the newly appended node
20865 * Fires when a child node is removed
20866 * @param {Tree} tree The owner tree
20867 * @param {Node} this This node
20868 * @param {Node} node The removed node
20873 * Fires when this node is moved to a new location in the tree
20874 * @param {Tree} tree The owner tree
20875 * @param {Node} this This node
20876 * @param {Node} oldParent The old parent of this node
20877 * @param {Node} newParent The new parent of this node
20878 * @param {Number} index The index it was moved to
20883 * Fires when a new child node is inserted.
20884 * @param {Tree} tree The owner tree
20885 * @param {Node} this This node
20886 * @param {Node} node The child node inserted
20887 * @param {Node} refNode The child node the node was inserted before
20891 * @event beforeappend
20892 * Fires before a new child is appended, return false to cancel the append.
20893 * @param {Tree} tree The owner tree
20894 * @param {Node} this This node
20895 * @param {Node} node The child node to be appended
20897 "beforeappend" : true,
20899 * @event beforeremove
20900 * Fires before a child is removed, return false to cancel the remove.
20901 * @param {Tree} tree The owner tree
20902 * @param {Node} this This node
20903 * @param {Node} node The child node to be removed
20905 "beforeremove" : true,
20907 * @event beforemove
20908 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
20909 * @param {Tree} tree The owner tree
20910 * @param {Node} this This node
20911 * @param {Node} oldParent The parent of this node
20912 * @param {Node} newParent The new parent this node is moving to
20913 * @param {Number} index The index it is being moved to
20915 "beforemove" : true,
20917 * @event beforeinsert
20918 * Fires before a new child is inserted, return false to cancel the insert.
20919 * @param {Tree} tree The owner tree
20920 * @param {Node} this This node
20921 * @param {Node} node The child node to be inserted
20922 * @param {Node} refNode The child node the node is being inserted before
20924 "beforeinsert" : true
20926 this.listeners = this.attributes.listeners;
20927 Roo.data.Node.superclass.constructor.call(this);
20930 Roo.extend(Roo.data.Node, Roo.util.Observable, {
20931 fireEvent : function(evtName){
20932 // first do standard event for this node
20933 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
20936 // then bubble it up to the tree if the event wasn't cancelled
20937 var ot = this.getOwnerTree();
20939 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
20947 * Returns true if this node is a leaf
20948 * @return {Boolean}
20950 isLeaf : function(){
20951 return this.leaf === true;
20955 setFirstChild : function(node){
20956 this.firstChild = node;
20960 setLastChild : function(node){
20961 this.lastChild = node;
20966 * Returns true if this node is the last child of its parent
20967 * @return {Boolean}
20969 isLast : function(){
20970 return (!this.parentNode ? true : this.parentNode.lastChild == this);
20974 * Returns true if this node is the first child of its parent
20975 * @return {Boolean}
20977 isFirst : function(){
20978 return (!this.parentNode ? true : this.parentNode.firstChild == this);
20981 hasChildNodes : function(){
20982 return !this.isLeaf() && this.childNodes.length > 0;
20986 * Insert node(s) as the last child node of this node.
20987 * @param {Node/Array} node The node or Array of nodes to append
20988 * @return {Node} The appended node if single append, or null if an array was passed
20990 appendChild : function(node){
20992 if(node instanceof Array){
20994 }else if(arguments.length > 1){
20997 // if passed an array or multiple args do them one by one
20999 for(var i = 0, len = multi.length; i < len; i++) {
21000 this.appendChild(multi[i]);
21003 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21006 var index = this.childNodes.length;
21007 var oldParent = node.parentNode;
21008 // it's a move, make sure we move it cleanly
21010 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21013 oldParent.removeChild(node);
21015 index = this.childNodes.length;
21017 this.setFirstChild(node);
21019 this.childNodes.push(node);
21020 node.parentNode = this;
21021 var ps = this.childNodes[index-1];
21023 node.previousSibling = ps;
21024 ps.nextSibling = node;
21026 node.previousSibling = null;
21028 node.nextSibling = null;
21029 this.setLastChild(node);
21030 node.setOwnerTree(this.getOwnerTree());
21031 this.fireEvent("append", this.ownerTree, this, node, index);
21033 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21040 * Removes a child node from this node.
21041 * @param {Node} node The node to remove
21042 * @return {Node} The removed node
21044 removeChild : function(node){
21045 var index = this.childNodes.indexOf(node);
21049 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21053 // remove it from childNodes collection
21054 this.childNodes.splice(index, 1);
21057 if(node.previousSibling){
21058 node.previousSibling.nextSibling = node.nextSibling;
21060 if(node.nextSibling){
21061 node.nextSibling.previousSibling = node.previousSibling;
21064 // update child refs
21065 if(this.firstChild == node){
21066 this.setFirstChild(node.nextSibling);
21068 if(this.lastChild == node){
21069 this.setLastChild(node.previousSibling);
21072 node.setOwnerTree(null);
21073 // clear any references from the node
21074 node.parentNode = null;
21075 node.previousSibling = null;
21076 node.nextSibling = null;
21077 this.fireEvent("remove", this.ownerTree, this, node);
21082 * Inserts the first node before the second node in this nodes childNodes collection.
21083 * @param {Node} node The node to insert
21084 * @param {Node} refNode The node to insert before (if null the node is appended)
21085 * @return {Node} The inserted node
21087 insertBefore : function(node, refNode){
21088 if(!refNode){ // like standard Dom, refNode can be null for append
21089 return this.appendChild(node);
21092 if(node == refNode){
21096 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21099 var index = this.childNodes.indexOf(refNode);
21100 var oldParent = node.parentNode;
21101 var refIndex = index;
21103 // when moving internally, indexes will change after remove
21104 if(oldParent == this && this.childNodes.indexOf(node) < index){
21108 // it's a move, make sure we move it cleanly
21110 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21113 oldParent.removeChild(node);
21116 this.setFirstChild(node);
21118 this.childNodes.splice(refIndex, 0, node);
21119 node.parentNode = this;
21120 var ps = this.childNodes[refIndex-1];
21122 node.previousSibling = ps;
21123 ps.nextSibling = node;
21125 node.previousSibling = null;
21127 node.nextSibling = refNode;
21128 refNode.previousSibling = node;
21129 node.setOwnerTree(this.getOwnerTree());
21130 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21132 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21138 * Returns the child node at the specified index.
21139 * @param {Number} index
21142 item : function(index){
21143 return this.childNodes[index];
21147 * Replaces one child node in this node with another.
21148 * @param {Node} newChild The replacement node
21149 * @param {Node} oldChild The node to replace
21150 * @return {Node} The replaced node
21152 replaceChild : function(newChild, oldChild){
21153 this.insertBefore(newChild, oldChild);
21154 this.removeChild(oldChild);
21159 * Returns the index of a child node
21160 * @param {Node} node
21161 * @return {Number} The index of the node or -1 if it was not found
21163 indexOf : function(child){
21164 return this.childNodes.indexOf(child);
21168 * Returns the tree this node is in.
21171 getOwnerTree : function(){
21172 // if it doesn't have one, look for one
21173 if(!this.ownerTree){
21177 this.ownerTree = p.ownerTree;
21183 return this.ownerTree;
21187 * Returns depth of this node (the root node has a depth of 0)
21190 getDepth : function(){
21193 while(p.parentNode){
21201 setOwnerTree : function(tree){
21202 // if it's move, we need to update everyone
21203 if(tree != this.ownerTree){
21204 if(this.ownerTree){
21205 this.ownerTree.unregisterNode(this);
21207 this.ownerTree = tree;
21208 var cs = this.childNodes;
21209 for(var i = 0, len = cs.length; i < len; i++) {
21210 cs[i].setOwnerTree(tree);
21213 tree.registerNode(this);
21219 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21220 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21221 * @return {String} The path
21223 getPath : function(attr){
21224 attr = attr || "id";
21225 var p = this.parentNode;
21226 var b = [this.attributes[attr]];
21228 b.unshift(p.attributes[attr]);
21231 var sep = this.getOwnerTree().pathSeparator;
21232 return sep + b.join(sep);
21236 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21237 * function call will be the scope provided or the current node. The arguments to the function
21238 * will be the args provided or the current node. If the function returns false at any point,
21239 * the bubble is stopped.
21240 * @param {Function} fn The function to call
21241 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21242 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21244 bubble : function(fn, scope, args){
21247 if(fn.call(scope || p, args || p) === false){
21255 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21256 * function call will be the scope provided or the current node. The arguments to the function
21257 * will be the args provided or the current node. If the function returns false at any point,
21258 * the cascade is stopped on that branch.
21259 * @param {Function} fn The function to call
21260 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21261 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21263 cascade : function(fn, scope, args){
21264 if(fn.call(scope || this, args || this) !== false){
21265 var cs = this.childNodes;
21266 for(var i = 0, len = cs.length; i < len; i++) {
21267 cs[i].cascade(fn, scope, args);
21273 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21274 * function call will be the scope provided or the current node. The arguments to the function
21275 * will be the args provided or the current node. If the function returns false at any point,
21276 * the iteration stops.
21277 * @param {Function} fn The function to call
21278 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21279 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21281 eachChild : function(fn, scope, args){
21282 var cs = this.childNodes;
21283 for(var i = 0, len = cs.length; i < len; i++) {
21284 if(fn.call(scope || this, args || cs[i]) === false){
21291 * Finds the first child that has the attribute with the specified value.
21292 * @param {String} attribute The attribute name
21293 * @param {Mixed} value The value to search for
21294 * @return {Node} The found child or null if none was found
21296 findChild : function(attribute, value){
21297 var cs = this.childNodes;
21298 for(var i = 0, len = cs.length; i < len; i++) {
21299 if(cs[i].attributes[attribute] == value){
21307 * Finds the first child by a custom function. The child matches if the function passed
21309 * @param {Function} fn
21310 * @param {Object} scope (optional)
21311 * @return {Node} The found child or null if none was found
21313 findChildBy : function(fn, scope){
21314 var cs = this.childNodes;
21315 for(var i = 0, len = cs.length; i < len; i++) {
21316 if(fn.call(scope||cs[i], cs[i]) === true){
21324 * Sorts this nodes children using the supplied sort function
21325 * @param {Function} fn
21326 * @param {Object} scope (optional)
21328 sort : function(fn, scope){
21329 var cs = this.childNodes;
21330 var len = cs.length;
21332 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21334 for(var i = 0; i < len; i++){
21336 n.previousSibling = cs[i-1];
21337 n.nextSibling = cs[i+1];
21339 this.setFirstChild(n);
21342 this.setLastChild(n);
21349 * Returns true if this node is an ancestor (at any point) of the passed node.
21350 * @param {Node} node
21351 * @return {Boolean}
21353 contains : function(node){
21354 return node.isAncestor(this);
21358 * Returns true if the passed node is an ancestor (at any point) of this node.
21359 * @param {Node} node
21360 * @return {Boolean}
21362 isAncestor : function(node){
21363 var p = this.parentNode;
21373 toString : function(){
21374 return "[Node"+(this.id?" "+this.id:"")+"]";
21378 * Ext JS Library 1.1.1
21379 * Copyright(c) 2006-2007, Ext JS, LLC.
21381 * Originally Released Under LGPL - original licence link has changed is not relivant.
21384 * <script type="text/javascript">
21389 * @class Roo.ComponentMgr
21390 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21393 Roo.ComponentMgr = function(){
21394 var all = new Roo.util.MixedCollection();
21398 * Registers a component.
21399 * @param {Roo.Component} c The component
21401 register : function(c){
21406 * Unregisters a component.
21407 * @param {Roo.Component} c The component
21409 unregister : function(c){
21414 * Returns a component by id
21415 * @param {String} id The component id
21417 get : function(id){
21418 return all.get(id);
21422 * Registers a function that will be called when a specified component is added to ComponentMgr
21423 * @param {String} id The component id
21424 * @param {Funtction} fn The callback function
21425 * @param {Object} scope The scope of the callback
21427 onAvailable : function(id, fn, scope){
21428 all.on("add", function(index, o){
21430 fn.call(scope || o, o);
21431 all.un("add", fn, scope);
21438 * Ext JS Library 1.1.1
21439 * Copyright(c) 2006-2007, Ext JS, LLC.
21441 * Originally Released Under LGPL - original licence link has changed is not relivant.
21444 * <script type="text/javascript">
21448 * @class Roo.Component
21449 * @extends Roo.util.Observable
21450 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21451 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21452 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21453 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21454 * All visual components (widgets) that require rendering into a layout should subclass Component.
21456 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21457 * 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
21458 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21460 Roo.Component = function(config){
21461 config = config || {};
21462 if(config.tagName || config.dom || typeof config == "string"){ // element object
21463 config = {el: config, id: config.id || config};
21465 this.initialConfig = config;
21467 Roo.apply(this, config);
21471 * Fires after the component is disabled.
21472 * @param {Roo.Component} this
21477 * Fires after the component is enabled.
21478 * @param {Roo.Component} this
21482 * @event beforeshow
21483 * Fires before the component is shown. Return false to stop the show.
21484 * @param {Roo.Component} this
21489 * Fires after the component is shown.
21490 * @param {Roo.Component} this
21494 * @event beforehide
21495 * Fires before the component is hidden. Return false to stop the hide.
21496 * @param {Roo.Component} this
21501 * Fires after the component is hidden.
21502 * @param {Roo.Component} this
21506 * @event beforerender
21507 * Fires before the component is rendered. Return false to stop the render.
21508 * @param {Roo.Component} this
21510 beforerender : true,
21513 * Fires after the component is rendered.
21514 * @param {Roo.Component} this
21518 * @event beforedestroy
21519 * Fires before the component is destroyed. Return false to stop the destroy.
21520 * @param {Roo.Component} this
21522 beforedestroy : true,
21525 * Fires after the component is destroyed.
21526 * @param {Roo.Component} this
21531 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21533 Roo.ComponentMgr.register(this);
21534 Roo.Component.superclass.constructor.call(this);
21535 this.initComponent();
21536 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21537 this.render(this.renderTo);
21538 delete this.renderTo;
21543 Roo.Component.AUTO_ID = 1000;
21545 Roo.extend(Roo.Component, Roo.util.Observable, {
21547 * @property {Boolean} hidden
21548 * true if this component is hidden. Read-only.
21552 * true if this component is disabled. Read-only.
21556 * true if this component has been rendered. Read-only.
21560 /** @cfg {String} disableClass
21561 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21563 disabledClass : "x-item-disabled",
21564 /** @cfg {Boolean} allowDomMove
21565 * Whether the component can move the Dom node when rendering (defaults to true).
21567 allowDomMove : true,
21568 /** @cfg {String} hideMode
21569 * How this component should hidden. Supported values are
21570 * "visibility" (css visibility), "offsets" (negative offset position) and
21571 * "display" (css display) - defaults to "display".
21573 hideMode: 'display',
21576 ctype : "Roo.Component",
21578 /** @cfg {String} actionMode
21579 * which property holds the element that used for hide() / show() / disable() / enable()
21585 getActionEl : function(){
21586 return this[this.actionMode];
21589 initComponent : Roo.emptyFn,
21591 * If this is a lazy rendering component, render it to its container element.
21592 * @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.
21594 render : function(container, position){
21595 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21596 if(!container && this.el){
21597 this.el = Roo.get(this.el);
21598 container = this.el.dom.parentNode;
21599 this.allowDomMove = false;
21601 this.container = Roo.get(container);
21602 this.rendered = true;
21603 if(position !== undefined){
21604 if(typeof position == 'number'){
21605 position = this.container.dom.childNodes[position];
21607 position = Roo.getDom(position);
21610 this.onRender(this.container, position || null);
21612 this.el.addClass(this.cls);
21616 this.el.applyStyles(this.style);
21619 this.fireEvent("render", this);
21620 this.afterRender(this.container);
21632 // default function is not really useful
21633 onRender : function(ct, position){
21635 this.el = Roo.get(this.el);
21636 if(this.allowDomMove !== false){
21637 ct.dom.insertBefore(this.el.dom, position);
21643 getAutoCreate : function(){
21644 var cfg = typeof this.autoCreate == "object" ?
21645 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21646 if(this.id && !cfg.id){
21653 afterRender : Roo.emptyFn,
21656 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21657 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21659 destroy : function(){
21660 if(this.fireEvent("beforedestroy", this) !== false){
21661 this.purgeListeners();
21662 this.beforeDestroy();
21664 this.el.removeAllListeners();
21666 if(this.actionMode == "container"){
21667 this.container.remove();
21671 Roo.ComponentMgr.unregister(this);
21672 this.fireEvent("destroy", this);
21677 beforeDestroy : function(){
21682 onDestroy : function(){
21687 * Returns the underlying {@link Roo.Element}.
21688 * @return {Roo.Element} The element
21690 getEl : function(){
21695 * Returns the id of this component.
21698 getId : function(){
21703 * Try to focus this component.
21704 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21705 * @return {Roo.Component} this
21707 focus : function(selectText){
21710 if(selectText === true){
21711 this.el.dom.select();
21726 * Disable this component.
21727 * @return {Roo.Component} this
21729 disable : function(){
21733 this.disabled = true;
21734 this.fireEvent("disable", this);
21739 onDisable : function(){
21740 this.getActionEl().addClass(this.disabledClass);
21741 this.el.dom.disabled = true;
21745 * Enable this component.
21746 * @return {Roo.Component} this
21748 enable : function(){
21752 this.disabled = false;
21753 this.fireEvent("enable", this);
21758 onEnable : function(){
21759 this.getActionEl().removeClass(this.disabledClass);
21760 this.el.dom.disabled = false;
21764 * Convenience function for setting disabled/enabled by boolean.
21765 * @param {Boolean} disabled
21767 setDisabled : function(disabled){
21768 this[disabled ? "disable" : "enable"]();
21772 * Show this component.
21773 * @return {Roo.Component} this
21776 if(this.fireEvent("beforeshow", this) !== false){
21777 this.hidden = false;
21781 this.fireEvent("show", this);
21787 onShow : function(){
21788 var ae = this.getActionEl();
21789 if(this.hideMode == 'visibility'){
21790 ae.dom.style.visibility = "visible";
21791 }else if(this.hideMode == 'offsets'){
21792 ae.removeClass('x-hidden');
21794 ae.dom.style.display = "";
21799 * Hide this component.
21800 * @return {Roo.Component} this
21803 if(this.fireEvent("beforehide", this) !== false){
21804 this.hidden = true;
21808 this.fireEvent("hide", this);
21814 onHide : function(){
21815 var ae = this.getActionEl();
21816 if(this.hideMode == 'visibility'){
21817 ae.dom.style.visibility = "hidden";
21818 }else if(this.hideMode == 'offsets'){
21819 ae.addClass('x-hidden');
21821 ae.dom.style.display = "none";
21826 * Convenience function to hide or show this component by boolean.
21827 * @param {Boolean} visible True to show, false to hide
21828 * @return {Roo.Component} this
21830 setVisible: function(visible){
21840 * Returns true if this component is visible.
21842 isVisible : function(){
21843 return this.getActionEl().isVisible();
21846 cloneConfig : function(overrides){
21847 overrides = overrides || {};
21848 var id = overrides.id || Roo.id();
21849 var cfg = Roo.applyIf(overrides, this.initialConfig);
21850 cfg.id = id; // prevent dup id
21851 return new this.constructor(cfg);
21855 * Ext JS Library 1.1.1
21856 * Copyright(c) 2006-2007, Ext JS, LLC.
21858 * Originally Released Under LGPL - original licence link has changed is not relivant.
21861 * <script type="text/javascript">
21866 * @extends Roo.Element
21867 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
21868 * automatic maintaining of shadow/shim positions.
21869 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
21870 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
21871 * you can pass a string with a CSS class name. False turns off the shadow.
21872 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
21873 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
21874 * @cfg {String} cls CSS class to add to the element
21875 * @cfg {Number} zindex Starting z-index (defaults to 11000)
21876 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
21878 * @param {Object} config An object with config options.
21879 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
21882 Roo.Layer = function(config, existingEl){
21883 config = config || {};
21884 var dh = Roo.DomHelper;
21885 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
21887 this.dom = Roo.getDom(existingEl);
21890 var o = config.dh || {tag: "div", cls: "x-layer"};
21891 this.dom = dh.append(pel, o);
21894 this.addClass(config.cls);
21896 this.constrain = config.constrain !== false;
21897 this.visibilityMode = Roo.Element.VISIBILITY;
21899 this.id = this.dom.id = config.id;
21901 this.id = Roo.id(this.dom);
21903 this.zindex = config.zindex || this.getZIndex();
21904 this.position("absolute", this.zindex);
21906 this.shadowOffset = config.shadowOffset || 4;
21907 this.shadow = new Roo.Shadow({
21908 offset : this.shadowOffset,
21909 mode : config.shadow
21912 this.shadowOffset = 0;
21914 this.useShim = config.shim !== false && Roo.useShims;
21915 this.useDisplay = config.useDisplay;
21919 var supr = Roo.Element.prototype;
21921 // shims are shared among layer to keep from having 100 iframes
21924 Roo.extend(Roo.Layer, Roo.Element, {
21926 getZIndex : function(){
21927 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
21930 getShim : function(){
21937 var shim = shims.shift();
21939 shim = this.createShim();
21940 shim.enableDisplayMode('block');
21941 shim.dom.style.display = 'none';
21942 shim.dom.style.visibility = 'visible';
21944 var pn = this.dom.parentNode;
21945 if(shim.dom.parentNode != pn){
21946 pn.insertBefore(shim.dom, this.dom);
21948 shim.setStyle('z-index', this.getZIndex()-2);
21953 hideShim : function(){
21955 this.shim.setDisplayed(false);
21956 shims.push(this.shim);
21961 disableShadow : function(){
21963 this.shadowDisabled = true;
21964 this.shadow.hide();
21965 this.lastShadowOffset = this.shadowOffset;
21966 this.shadowOffset = 0;
21970 enableShadow : function(show){
21972 this.shadowDisabled = false;
21973 this.shadowOffset = this.lastShadowOffset;
21974 delete this.lastShadowOffset;
21982 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
21983 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
21984 sync : function(doShow){
21985 var sw = this.shadow;
21986 if(!this.updating && this.isVisible() && (sw || this.useShim)){
21987 var sh = this.getShim();
21989 var w = this.getWidth(),
21990 h = this.getHeight();
21992 var l = this.getLeft(true),
21993 t = this.getTop(true);
21995 if(sw && !this.shadowDisabled){
21996 if(doShow && !sw.isVisible()){
21999 sw.realign(l, t, w, h);
22005 // fit the shim behind the shadow, so it is shimmed too
22006 var a = sw.adjusts, s = sh.dom.style;
22007 s.left = (Math.min(l, l+a.l))+"px";
22008 s.top = (Math.min(t, t+a.t))+"px";
22009 s.width = (w+a.w)+"px";
22010 s.height = (h+a.h)+"px";
22017 sh.setLeftTop(l, t);
22024 destroy : function(){
22027 this.shadow.hide();
22029 this.removeAllListeners();
22030 var pn = this.dom.parentNode;
22032 pn.removeChild(this.dom);
22034 Roo.Element.uncache(this.id);
22037 remove : function(){
22042 beginUpdate : function(){
22043 this.updating = true;
22047 endUpdate : function(){
22048 this.updating = false;
22053 hideUnders : function(negOffset){
22055 this.shadow.hide();
22061 constrainXY : function(){
22062 if(this.constrain){
22063 var vw = Roo.lib.Dom.getViewWidth(),
22064 vh = Roo.lib.Dom.getViewHeight();
22065 var s = Roo.get(document).getScroll();
22067 var xy = this.getXY();
22068 var x = xy[0], y = xy[1];
22069 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22070 // only move it if it needs it
22072 // first validate right/bottom
22073 if((x + w) > vw+s.left){
22074 x = vw - w - this.shadowOffset;
22077 if((y + h) > vh+s.top){
22078 y = vh - h - this.shadowOffset;
22081 // then make sure top/left isn't negative
22092 var ay = this.avoidY;
22093 if(y <= ay && (y+h) >= ay){
22099 supr.setXY.call(this, xy);
22105 isVisible : function(){
22106 return this.visible;
22110 showAction : function(){
22111 this.visible = true; // track visibility to prevent getStyle calls
22112 if(this.useDisplay === true){
22113 this.setDisplayed("");
22114 }else if(this.lastXY){
22115 supr.setXY.call(this, this.lastXY);
22116 }else if(this.lastLT){
22117 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22122 hideAction : function(){
22123 this.visible = false;
22124 if(this.useDisplay === true){
22125 this.setDisplayed(false);
22127 this.setLeftTop(-10000,-10000);
22131 // overridden Element method
22132 setVisible : function(v, a, d, c, e){
22137 var cb = function(){
22142 }.createDelegate(this);
22143 supr.setVisible.call(this, true, true, d, cb, e);
22146 this.hideUnders(true);
22155 }.createDelegate(this);
22157 supr.setVisible.call(this, v, a, d, cb, e);
22166 storeXY : function(xy){
22167 delete this.lastLT;
22171 storeLeftTop : function(left, top){
22172 delete this.lastXY;
22173 this.lastLT = [left, top];
22177 beforeFx : function(){
22178 this.beforeAction();
22179 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22183 afterFx : function(){
22184 Roo.Layer.superclass.afterFx.apply(this, arguments);
22185 this.sync(this.isVisible());
22189 beforeAction : function(){
22190 if(!this.updating && this.shadow){
22191 this.shadow.hide();
22195 // overridden Element method
22196 setLeft : function(left){
22197 this.storeLeftTop(left, this.getTop(true));
22198 supr.setLeft.apply(this, arguments);
22202 setTop : function(top){
22203 this.storeLeftTop(this.getLeft(true), top);
22204 supr.setTop.apply(this, arguments);
22208 setLeftTop : function(left, top){
22209 this.storeLeftTop(left, top);
22210 supr.setLeftTop.apply(this, arguments);
22214 setXY : function(xy, a, d, c, e){
22216 this.beforeAction();
22218 var cb = this.createCB(c);
22219 supr.setXY.call(this, xy, a, d, cb, e);
22226 createCB : function(c){
22237 // overridden Element method
22238 setX : function(x, a, d, c, e){
22239 this.setXY([x, this.getY()], a, d, c, e);
22242 // overridden Element method
22243 setY : function(y, a, d, c, e){
22244 this.setXY([this.getX(), y], a, d, c, e);
22247 // overridden Element method
22248 setSize : function(w, h, a, d, c, e){
22249 this.beforeAction();
22250 var cb = this.createCB(c);
22251 supr.setSize.call(this, w, h, a, d, cb, e);
22257 // overridden Element method
22258 setWidth : function(w, a, d, c, e){
22259 this.beforeAction();
22260 var cb = this.createCB(c);
22261 supr.setWidth.call(this, w, a, d, cb, e);
22267 // overridden Element method
22268 setHeight : function(h, a, d, c, e){
22269 this.beforeAction();
22270 var cb = this.createCB(c);
22271 supr.setHeight.call(this, h, a, d, cb, e);
22277 // overridden Element method
22278 setBounds : function(x, y, w, h, a, d, c, e){
22279 this.beforeAction();
22280 var cb = this.createCB(c);
22282 this.storeXY([x, y]);
22283 supr.setXY.call(this, [x, y]);
22284 supr.setSize.call(this, w, h, a, d, cb, e);
22287 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22293 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22294 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22295 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22296 * @param {Number} zindex The new z-index to set
22297 * @return {this} The Layer
22299 setZIndex : function(zindex){
22300 this.zindex = zindex;
22301 this.setStyle("z-index", zindex + 2);
22303 this.shadow.setZIndex(zindex + 1);
22306 this.shim.setStyle("z-index", zindex);
22312 * Ext JS Library 1.1.1
22313 * Copyright(c) 2006-2007, Ext JS, LLC.
22315 * Originally Released Under LGPL - original licence link has changed is not relivant.
22318 * <script type="text/javascript">
22323 * @class Roo.Shadow
22324 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22325 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22326 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22328 * Create a new Shadow
22329 * @param {Object} config The config object
22331 Roo.Shadow = function(config){
22332 Roo.apply(this, config);
22333 if(typeof this.mode != "string"){
22334 this.mode = this.defaultMode;
22336 var o = this.offset, a = {h: 0};
22337 var rad = Math.floor(this.offset/2);
22338 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22344 a.l -= this.offset + rad;
22345 a.t -= this.offset + rad;
22356 a.l -= (this.offset - rad);
22357 a.t -= this.offset + rad;
22359 a.w -= (this.offset - rad)*2;
22370 a.l -= (this.offset - rad);
22371 a.t -= (this.offset - rad);
22373 a.w -= (this.offset + rad + 1);
22374 a.h -= (this.offset + rad);
22383 Roo.Shadow.prototype = {
22385 * @cfg {String} mode
22386 * The shadow display mode. Supports the following options:<br />
22387 * sides: Shadow displays on both sides and bottom only<br />
22388 * frame: Shadow displays equally on all four sides<br />
22389 * drop: Traditional bottom-right drop shadow (default)
22392 * @cfg {String} offset
22393 * The number of pixels to offset the shadow from the element (defaults to 4)
22398 defaultMode: "drop",
22401 * Displays the shadow under the target element
22402 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22404 show : function(target){
22405 target = Roo.get(target);
22407 this.el = Roo.Shadow.Pool.pull();
22408 if(this.el.dom.nextSibling != target.dom){
22409 this.el.insertBefore(target);
22412 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22414 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22417 target.getLeft(true),
22418 target.getTop(true),
22422 this.el.dom.style.display = "block";
22426 * Returns true if the shadow is visible, else false
22428 isVisible : function(){
22429 return this.el ? true : false;
22433 * Direct alignment when values are already available. Show must be called at least once before
22434 * calling this method to ensure it is initialized.
22435 * @param {Number} left The target element left position
22436 * @param {Number} top The target element top position
22437 * @param {Number} width The target element width
22438 * @param {Number} height The target element height
22440 realign : function(l, t, w, h){
22444 var a = this.adjusts, d = this.el.dom, s = d.style;
22446 s.left = (l+a.l)+"px";
22447 s.top = (t+a.t)+"px";
22448 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22449 if(s.width != sws || s.height != shs){
22453 var cn = d.childNodes;
22454 var sww = Math.max(0, (sw-12))+"px";
22455 cn[0].childNodes[1].style.width = sww;
22456 cn[1].childNodes[1].style.width = sww;
22457 cn[2].childNodes[1].style.width = sww;
22458 cn[1].style.height = Math.max(0, (sh-12))+"px";
22464 * Hides this shadow
22468 this.el.dom.style.display = "none";
22469 Roo.Shadow.Pool.push(this.el);
22475 * Adjust the z-index of this shadow
22476 * @param {Number} zindex The new z-index
22478 setZIndex : function(z){
22481 this.el.setStyle("z-index", z);
22486 // Private utility class that manages the internal Shadow cache
22487 Roo.Shadow.Pool = function(){
22489 var markup = Roo.isIE ?
22490 '<div class="x-ie-shadow"></div>' :
22491 '<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>';
22494 var sh = p.shift();
22496 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22497 sh.autoBoxAdjust = false;
22502 push : function(sh){
22508 * Ext JS Library 1.1.1
22509 * Copyright(c) 2006-2007, Ext JS, LLC.
22511 * Originally Released Under LGPL - original licence link has changed is not relivant.
22514 * <script type="text/javascript">
22518 * @class Roo.BoxComponent
22519 * @extends Roo.Component
22520 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22521 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22522 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22523 * layout containers.
22525 * @param {Roo.Element/String/Object} config The configuration options.
22527 Roo.BoxComponent = function(config){
22528 Roo.Component.call(this, config);
22532 * Fires after the component is resized.
22533 * @param {Roo.Component} this
22534 * @param {Number} adjWidth The box-adjusted width that was set
22535 * @param {Number} adjHeight The box-adjusted height that was set
22536 * @param {Number} rawWidth The width that was originally specified
22537 * @param {Number} rawHeight The height that was originally specified
22542 * Fires after the component is moved.
22543 * @param {Roo.Component} this
22544 * @param {Number} x The new x position
22545 * @param {Number} y The new y position
22551 Roo.extend(Roo.BoxComponent, Roo.Component, {
22552 // private, set in afterRender to signify that the component has been rendered
22554 // private, used to defer height settings to subclasses
22555 deferHeight: false,
22556 /** @cfg {Number} width
22557 * width (optional) size of component
22559 /** @cfg {Number} height
22560 * height (optional) size of component
22564 * Sets the width and height of the component. This method fires the resize event. This method can accept
22565 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22566 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22567 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22568 * @return {Roo.BoxComponent} this
22570 setSize : function(w, h){
22571 // support for standard size objects
22572 if(typeof w == 'object'){
22577 if(!this.boxReady){
22583 // prevent recalcs when not needed
22584 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22587 this.lastSize = {width: w, height: h};
22589 var adj = this.adjustSize(w, h);
22590 var aw = adj.width, ah = adj.height;
22591 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22592 var rz = this.getResizeEl();
22593 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22594 rz.setSize(aw, ah);
22595 }else if(!this.deferHeight && ah !== undefined){
22597 }else if(aw !== undefined){
22600 this.onResize(aw, ah, w, h);
22601 this.fireEvent('resize', this, aw, ah, w, h);
22607 * Gets the current size of the component's underlying element.
22608 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22610 getSize : function(){
22611 return this.el.getSize();
22615 * Gets the current XY position of the component's underlying element.
22616 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22617 * @return {Array} The XY position of the element (e.g., [100, 200])
22619 getPosition : function(local){
22620 if(local === true){
22621 return [this.el.getLeft(true), this.el.getTop(true)];
22623 return this.xy || this.el.getXY();
22627 * Gets the current box measurements of the component's underlying element.
22628 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22629 * @returns {Object} box An object in the format {x, y, width, height}
22631 getBox : function(local){
22632 var s = this.el.getSize();
22634 s.x = this.el.getLeft(true);
22635 s.y = this.el.getTop(true);
22637 var xy = this.xy || this.el.getXY();
22645 * Sets the current box measurements of the component's underlying element.
22646 * @param {Object} box An object in the format {x, y, width, height}
22647 * @returns {Roo.BoxComponent} this
22649 updateBox : function(box){
22650 this.setSize(box.width, box.height);
22651 this.setPagePosition(box.x, box.y);
22656 getResizeEl : function(){
22657 return this.resizeEl || this.el;
22661 getPositionEl : function(){
22662 return this.positionEl || this.el;
22666 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22667 * This method fires the move event.
22668 * @param {Number} left The new left
22669 * @param {Number} top The new top
22670 * @returns {Roo.BoxComponent} this
22672 setPosition : function(x, y){
22675 if(!this.boxReady){
22678 var adj = this.adjustPosition(x, y);
22679 var ax = adj.x, ay = adj.y;
22681 var el = this.getPositionEl();
22682 if(ax !== undefined || ay !== undefined){
22683 if(ax !== undefined && ay !== undefined){
22684 el.setLeftTop(ax, ay);
22685 }else if(ax !== undefined){
22687 }else if(ay !== undefined){
22690 this.onPosition(ax, ay);
22691 this.fireEvent('move', this, ax, ay);
22697 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22698 * This method fires the move event.
22699 * @param {Number} x The new x position
22700 * @param {Number} y The new y position
22701 * @returns {Roo.BoxComponent} this
22703 setPagePosition : function(x, y){
22706 if(!this.boxReady){
22709 if(x === undefined || y === undefined){ // cannot translate undefined points
22712 var p = this.el.translatePoints(x, y);
22713 this.setPosition(p.left, p.top);
22718 onRender : function(ct, position){
22719 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22721 this.resizeEl = Roo.get(this.resizeEl);
22723 if(this.positionEl){
22724 this.positionEl = Roo.get(this.positionEl);
22729 afterRender : function(){
22730 Roo.BoxComponent.superclass.afterRender.call(this);
22731 this.boxReady = true;
22732 this.setSize(this.width, this.height);
22733 if(this.x || this.y){
22734 this.setPosition(this.x, this.y);
22736 if(this.pageX || this.pageY){
22737 this.setPagePosition(this.pageX, this.pageY);
22742 * Force the component's size to recalculate based on the underlying element's current height and width.
22743 * @returns {Roo.BoxComponent} this
22745 syncSize : function(){
22746 delete this.lastSize;
22747 this.setSize(this.el.getWidth(), this.el.getHeight());
22752 * Called after the component is resized, this method is empty by default but can be implemented by any
22753 * subclass that needs to perform custom logic after a resize occurs.
22754 * @param {Number} adjWidth The box-adjusted width that was set
22755 * @param {Number} adjHeight The box-adjusted height that was set
22756 * @param {Number} rawWidth The width that was originally specified
22757 * @param {Number} rawHeight The height that was originally specified
22759 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22764 * Called after the component is moved, this method is empty by default but can be implemented by any
22765 * subclass that needs to perform custom logic after a move occurs.
22766 * @param {Number} x The new x position
22767 * @param {Number} y The new y position
22769 onPosition : function(x, y){
22774 adjustSize : function(w, h){
22775 if(this.autoWidth){
22778 if(this.autoHeight){
22781 return {width : w, height: h};
22785 adjustPosition : function(x, y){
22786 return {x : x, y: y};
22790 * Ext JS Library 1.1.1
22791 * Copyright(c) 2006-2007, Ext JS, LLC.
22793 * Originally Released Under LGPL - original licence link has changed is not relivant.
22796 * <script type="text/javascript">
22801 * @class Roo.SplitBar
22802 * @extends Roo.util.Observable
22803 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
22807 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
22808 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
22809 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
22810 split.minSize = 100;
22811 split.maxSize = 600;
22812 split.animate = true;
22813 split.on('moved', splitterMoved);
22816 * Create a new SplitBar
22817 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
22818 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
22819 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22820 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
22821 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
22822 position of the SplitBar).
22824 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
22827 this.el = Roo.get(dragElement, true);
22828 this.el.dom.unselectable = "on";
22830 this.resizingEl = Roo.get(resizingElement, true);
22834 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22835 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
22838 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
22841 * The minimum size of the resizing element. (Defaults to 0)
22847 * The maximum size of the resizing element. (Defaults to 2000)
22850 this.maxSize = 2000;
22853 * Whether to animate the transition to the new size
22856 this.animate = false;
22859 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
22862 this.useShim = false;
22867 if(!existingProxy){
22869 this.proxy = Roo.SplitBar.createProxy(this.orientation);
22871 this.proxy = Roo.get(existingProxy).dom;
22874 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
22877 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
22880 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
22883 this.dragSpecs = {};
22886 * @private The adapter to use to positon and resize elements
22888 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
22889 this.adapter.init(this);
22891 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22893 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
22894 this.el.addClass("x-splitbar-h");
22897 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
22898 this.el.addClass("x-splitbar-v");
22904 * Fires when the splitter is moved (alias for {@link #event-moved})
22905 * @param {Roo.SplitBar} this
22906 * @param {Number} newSize the new width or height
22911 * Fires when the splitter is moved
22912 * @param {Roo.SplitBar} this
22913 * @param {Number} newSize the new width or height
22917 * @event beforeresize
22918 * Fires before the splitter is dragged
22919 * @param {Roo.SplitBar} this
22921 "beforeresize" : true,
22923 "beforeapply" : true
22926 Roo.util.Observable.call(this);
22929 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
22930 onStartProxyDrag : function(x, y){
22931 this.fireEvent("beforeresize", this);
22933 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
22935 o.enableDisplayMode("block");
22936 // all splitbars share the same overlay
22937 Roo.SplitBar.prototype.overlay = o;
22939 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
22940 this.overlay.show();
22941 Roo.get(this.proxy).setDisplayed("block");
22942 var size = this.adapter.getElementSize(this);
22943 this.activeMinSize = this.getMinimumSize();;
22944 this.activeMaxSize = this.getMaximumSize();;
22945 var c1 = size - this.activeMinSize;
22946 var c2 = Math.max(this.activeMaxSize - size, 0);
22947 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22948 this.dd.resetConstraints();
22949 this.dd.setXConstraint(
22950 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
22951 this.placement == Roo.SplitBar.LEFT ? c2 : c1
22953 this.dd.setYConstraint(0, 0);
22955 this.dd.resetConstraints();
22956 this.dd.setXConstraint(0, 0);
22957 this.dd.setYConstraint(
22958 this.placement == Roo.SplitBar.TOP ? c1 : c2,
22959 this.placement == Roo.SplitBar.TOP ? c2 : c1
22962 this.dragSpecs.startSize = size;
22963 this.dragSpecs.startPoint = [x, y];
22964 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
22968 * @private Called after the drag operation by the DDProxy
22970 onEndProxyDrag : function(e){
22971 Roo.get(this.proxy).setDisplayed(false);
22972 var endPoint = Roo.lib.Event.getXY(e);
22974 this.overlay.hide();
22977 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22978 newSize = this.dragSpecs.startSize +
22979 (this.placement == Roo.SplitBar.LEFT ?
22980 endPoint[0] - this.dragSpecs.startPoint[0] :
22981 this.dragSpecs.startPoint[0] - endPoint[0]
22984 newSize = this.dragSpecs.startSize +
22985 (this.placement == Roo.SplitBar.TOP ?
22986 endPoint[1] - this.dragSpecs.startPoint[1] :
22987 this.dragSpecs.startPoint[1] - endPoint[1]
22990 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
22991 if(newSize != this.dragSpecs.startSize){
22992 if(this.fireEvent('beforeapply', this, newSize) !== false){
22993 this.adapter.setElementSize(this, newSize);
22994 this.fireEvent("moved", this, newSize);
22995 this.fireEvent("resize", this, newSize);
23001 * Get the adapter this SplitBar uses
23002 * @return The adapter object
23004 getAdapter : function(){
23005 return this.adapter;
23009 * Set the adapter this SplitBar uses
23010 * @param {Object} adapter A SplitBar adapter object
23012 setAdapter : function(adapter){
23013 this.adapter = adapter;
23014 this.adapter.init(this);
23018 * Gets the minimum size for the resizing element
23019 * @return {Number} The minimum size
23021 getMinimumSize : function(){
23022 return this.minSize;
23026 * Sets the minimum size for the resizing element
23027 * @param {Number} minSize The minimum size
23029 setMinimumSize : function(minSize){
23030 this.minSize = minSize;
23034 * Gets the maximum size for the resizing element
23035 * @return {Number} The maximum size
23037 getMaximumSize : function(){
23038 return this.maxSize;
23042 * Sets the maximum size for the resizing element
23043 * @param {Number} maxSize The maximum size
23045 setMaximumSize : function(maxSize){
23046 this.maxSize = maxSize;
23050 * Sets the initialize size for the resizing element
23051 * @param {Number} size The initial size
23053 setCurrentSize : function(size){
23054 var oldAnimate = this.animate;
23055 this.animate = false;
23056 this.adapter.setElementSize(this, size);
23057 this.animate = oldAnimate;
23061 * Destroy this splitbar.
23062 * @param {Boolean} removeEl True to remove the element
23064 destroy : function(removeEl){
23066 this.shim.remove();
23069 this.proxy.parentNode.removeChild(this.proxy);
23077 * @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.
23079 Roo.SplitBar.createProxy = function(dir){
23080 var proxy = new Roo.Element(document.createElement("div"));
23081 proxy.unselectable();
23082 var cls = 'x-splitbar-proxy';
23083 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23084 document.body.appendChild(proxy.dom);
23089 * @class Roo.SplitBar.BasicLayoutAdapter
23090 * Default Adapter. It assumes the splitter and resizing element are not positioned
23091 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23093 Roo.SplitBar.BasicLayoutAdapter = function(){
23096 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23097 // do nothing for now
23098 init : function(s){
23102 * Called before drag operations to get the current size of the resizing element.
23103 * @param {Roo.SplitBar} s The SplitBar using this adapter
23105 getElementSize : function(s){
23106 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23107 return s.resizingEl.getWidth();
23109 return s.resizingEl.getHeight();
23114 * Called after drag operations to set the size of the resizing element.
23115 * @param {Roo.SplitBar} s The SplitBar using this adapter
23116 * @param {Number} newSize The new size to set
23117 * @param {Function} onComplete A function to be invoked when resizing is complete
23119 setElementSize : function(s, newSize, onComplete){
23120 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23122 s.resizingEl.setWidth(newSize);
23124 onComplete(s, newSize);
23127 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23132 s.resizingEl.setHeight(newSize);
23134 onComplete(s, newSize);
23137 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23144 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23145 * @extends Roo.SplitBar.BasicLayoutAdapter
23146 * Adapter that moves the splitter element to align with the resized sizing element.
23147 * Used with an absolute positioned SplitBar.
23148 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23149 * document.body, make sure you assign an id to the body element.
23151 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23152 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23153 this.container = Roo.get(container);
23156 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23157 init : function(s){
23158 this.basic.init(s);
23161 getElementSize : function(s){
23162 return this.basic.getElementSize(s);
23165 setElementSize : function(s, newSize, onComplete){
23166 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23169 moveSplitter : function(s){
23170 var yes = Roo.SplitBar;
23171 switch(s.placement){
23173 s.el.setX(s.resizingEl.getRight());
23176 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23179 s.el.setY(s.resizingEl.getBottom());
23182 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23189 * Orientation constant - Create a vertical SplitBar
23193 Roo.SplitBar.VERTICAL = 1;
23196 * Orientation constant - Create a horizontal SplitBar
23200 Roo.SplitBar.HORIZONTAL = 2;
23203 * Placement constant - The resizing element is to the left of the splitter element
23207 Roo.SplitBar.LEFT = 1;
23210 * Placement constant - The resizing element is to the right of the splitter element
23214 Roo.SplitBar.RIGHT = 2;
23217 * Placement constant - The resizing element is positioned above the splitter element
23221 Roo.SplitBar.TOP = 3;
23224 * Placement constant - The resizing element is positioned under splitter element
23228 Roo.SplitBar.BOTTOM = 4;
23231 * Ext JS Library 1.1.1
23232 * Copyright(c) 2006-2007, Ext JS, LLC.
23234 * Originally Released Under LGPL - original licence link has changed is not relivant.
23237 * <script type="text/javascript">
23242 * @extends Roo.util.Observable
23243 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23244 * This class also supports single and multi selection modes. <br>
23245 * Create a data model bound view:
23247 var store = new Roo.data.Store(...);
23249 var view = new Roo.View({
23251 template : '<div id="{0}">{2} - {1}</div>', // auto create template
23253 singleSelect: true,
23254 selectedClass: "ydataview-selected",
23258 // listen for node click?
23259 view.on("click", function(vw, index, node, e){
23260 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23264 dataModel.load("foobar.xml");
23266 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23268 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23269 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23271 * Note: old style constructor is still suported (container, template, config)
23274 * Create a new View
23275 * @param {Object} config The config object
23278 Roo.View = function(config, depreciated_tpl, depreciated_config){
23280 if (typeof(depreciated_tpl) == 'undefined') {
23281 // new way.. - universal constructor.
23282 Roo.apply(this, config);
23283 this.el = Roo.get(this.el);
23286 this.el = Roo.get(config);
23287 this.tpl = depreciated_tpl;
23288 Roo.apply(this, depreciated_config);
23292 if(typeof(this.tpl) == "string"){
23293 this.tpl = new Roo.Template(this.tpl);
23297 this.tpl.compile();
23304 * @event beforeclick
23305 * Fires before a click is processed. Returns false to cancel the default action.
23306 * @param {Roo.View} this
23307 * @param {Number} index The index of the target node
23308 * @param {HTMLElement} node The target node
23309 * @param {Roo.EventObject} e The raw event object
23311 "beforeclick" : true,
23314 * Fires when a template node is clicked.
23315 * @param {Roo.View} this
23316 * @param {Number} index The index of the target node
23317 * @param {HTMLElement} node The target node
23318 * @param {Roo.EventObject} e The raw event object
23323 * Fires when a template node is double clicked.
23324 * @param {Roo.View} this
23325 * @param {Number} index The index of the target node
23326 * @param {HTMLElement} node The target node
23327 * @param {Roo.EventObject} e The raw event object
23331 * @event contextmenu
23332 * Fires when a template node is right clicked.
23333 * @param {Roo.View} this
23334 * @param {Number} index The index of the target node
23335 * @param {HTMLElement} node The target node
23336 * @param {Roo.EventObject} e The raw event object
23338 "contextmenu" : true,
23340 * @event selectionchange
23341 * Fires when the selected nodes change.
23342 * @param {Roo.View} this
23343 * @param {Array} selections Array of the selected nodes
23345 "selectionchange" : true,
23348 * @event beforeselect
23349 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23350 * @param {Roo.View} this
23351 * @param {HTMLElement} node The node to be selected
23352 * @param {Array} selections Array of currently selected nodes
23354 "beforeselect" : true
23358 "click": this.onClick,
23359 "dblclick": this.onDblClick,
23360 "contextmenu": this.onContextMenu,
23364 this.selections = [];
23366 this.cmp = new Roo.CompositeElementLite([]);
23368 this.store = Roo.factory(this.store, Roo.data);
23369 this.setStore(this.store, true);
23371 Roo.View.superclass.constructor.call(this);
23374 Roo.extend(Roo.View, Roo.util.Observable, {
23377 * @cfg {Roo.data.Store} store Data store to load data from.
23382 * @cfg {String|Roo.Element} el The container element.
23387 * @cfg {String|Roo.Template} tpl The template used by this View
23392 * @cfg {String} selectedClass The css class to add to selected nodes
23394 selectedClass : "x-view-selected",
23396 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23400 * Returns the element this view is bound to.
23401 * @return {Roo.Element}
23403 getEl : function(){
23408 * Refreshes the view.
23410 refresh : function(){
23412 this.clearSelections();
23413 this.el.update("");
23415 var records = this.store.getRange();
23416 if(records.length < 1){
23417 this.el.update(this.emptyText);
23420 for(var i = 0, len = records.length; i < len; i++){
23421 var data = this.prepareData(records[i].data, i, records[i]);
23422 html[html.length] = t.apply(data);
23424 this.el.update(html.join(""));
23425 this.nodes = this.el.dom.childNodes;
23426 this.updateIndexes(0);
23430 * Function to override to reformat the data that is sent to
23431 * the template for each node.
23432 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23433 * a JSON object for an UpdateManager bound view).
23435 prepareData : function(data){
23439 onUpdate : function(ds, record){
23440 this.clearSelections();
23441 var index = this.store.indexOf(record);
23442 var n = this.nodes[index];
23443 this.tpl.insertBefore(n, this.prepareData(record.data));
23444 n.parentNode.removeChild(n);
23445 this.updateIndexes(index, index);
23448 onAdd : function(ds, records, index){
23449 this.clearSelections();
23450 if(this.nodes.length == 0){
23454 var n = this.nodes[index];
23455 for(var i = 0, len = records.length; i < len; i++){
23456 var d = this.prepareData(records[i].data);
23458 this.tpl.insertBefore(n, d);
23460 this.tpl.append(this.el, d);
23463 this.updateIndexes(index);
23466 onRemove : function(ds, record, index){
23467 this.clearSelections();
23468 this.el.dom.removeChild(this.nodes[index]);
23469 this.updateIndexes(index);
23473 * Refresh an individual node.
23474 * @param {Number} index
23476 refreshNode : function(index){
23477 this.onUpdate(this.store, this.store.getAt(index));
23480 updateIndexes : function(startIndex, endIndex){
23481 var ns = this.nodes;
23482 startIndex = startIndex || 0;
23483 endIndex = endIndex || ns.length - 1;
23484 for(var i = startIndex; i <= endIndex; i++){
23485 ns[i].nodeIndex = i;
23490 * Changes the data store this view uses and refresh the view.
23491 * @param {Store} store
23493 setStore : function(store, initial){
23494 if(!initial && this.store){
23495 this.store.un("datachanged", this.refresh);
23496 this.store.un("add", this.onAdd);
23497 this.store.un("remove", this.onRemove);
23498 this.store.un("update", this.onUpdate);
23499 this.store.un("clear", this.refresh);
23503 store.on("datachanged", this.refresh, this);
23504 store.on("add", this.onAdd, this);
23505 store.on("remove", this.onRemove, this);
23506 store.on("update", this.onUpdate, this);
23507 store.on("clear", this.refresh, this);
23516 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23517 * @param {HTMLElement} node
23518 * @return {HTMLElement} The template node
23520 findItemFromChild : function(node){
23521 var el = this.el.dom;
23522 if(!node || node.parentNode == el){
23525 var p = node.parentNode;
23526 while(p && p != el){
23527 if(p.parentNode == el){
23536 onClick : function(e){
23537 var item = this.findItemFromChild(e.getTarget());
23539 var index = this.indexOf(item);
23540 if(this.onItemClick(item, index, e) !== false){
23541 this.fireEvent("click", this, index, item, e);
23544 this.clearSelections();
23549 onContextMenu : function(e){
23550 var item = this.findItemFromChild(e.getTarget());
23552 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23557 onDblClick : function(e){
23558 var item = this.findItemFromChild(e.getTarget());
23560 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23564 onItemClick : function(item, index, e){
23565 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23568 if(this.multiSelect || this.singleSelect){
23569 if(this.multiSelect && e.shiftKey && this.lastSelection){
23570 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23572 this.select(item, this.multiSelect && e.ctrlKey);
23573 this.lastSelection = item;
23575 e.preventDefault();
23581 * Get the number of selected nodes.
23584 getSelectionCount : function(){
23585 return this.selections.length;
23589 * Get the currently selected nodes.
23590 * @return {Array} An array of HTMLElements
23592 getSelectedNodes : function(){
23593 return this.selections;
23597 * Get the indexes of the selected nodes.
23600 getSelectedIndexes : function(){
23601 var indexes = [], s = this.selections;
23602 for(var i = 0, len = s.length; i < len; i++){
23603 indexes.push(s[i].nodeIndex);
23609 * Clear all selections
23610 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23612 clearSelections : function(suppressEvent){
23613 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23614 this.cmp.elements = this.selections;
23615 this.cmp.removeClass(this.selectedClass);
23616 this.selections = [];
23617 if(!suppressEvent){
23618 this.fireEvent("selectionchange", this, this.selections);
23624 * Returns true if the passed node is selected
23625 * @param {HTMLElement/Number} node The node or node index
23626 * @return {Boolean}
23628 isSelected : function(node){
23629 var s = this.selections;
23633 node = this.getNode(node);
23634 return s.indexOf(node) !== -1;
23639 * @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
23640 * @param {Boolean} keepExisting (optional) true to keep existing selections
23641 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23643 select : function(nodeInfo, keepExisting, suppressEvent){
23644 if(nodeInfo instanceof Array){
23646 this.clearSelections(true);
23648 for(var i = 0, len = nodeInfo.length; i < len; i++){
23649 this.select(nodeInfo[i], true, true);
23652 var node = this.getNode(nodeInfo);
23653 if(node && !this.isSelected(node)){
23655 this.clearSelections(true);
23657 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23658 Roo.fly(node).addClass(this.selectedClass);
23659 this.selections.push(node);
23660 if(!suppressEvent){
23661 this.fireEvent("selectionchange", this, this.selections);
23669 * Gets a template node.
23670 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23671 * @return {HTMLElement} The node or null if it wasn't found
23673 getNode : function(nodeInfo){
23674 if(typeof nodeInfo == "string"){
23675 return document.getElementById(nodeInfo);
23676 }else if(typeof nodeInfo == "number"){
23677 return this.nodes[nodeInfo];
23683 * Gets a range template nodes.
23684 * @param {Number} startIndex
23685 * @param {Number} endIndex
23686 * @return {Array} An array of nodes
23688 getNodes : function(start, end){
23689 var ns = this.nodes;
23690 start = start || 0;
23691 end = typeof end == "undefined" ? ns.length - 1 : end;
23694 for(var i = start; i <= end; i++){
23698 for(var i = start; i >= end; i--){
23706 * Finds the index of the passed node
23707 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23708 * @return {Number} The index of the node or -1
23710 indexOf : function(node){
23711 node = this.getNode(node);
23712 if(typeof node.nodeIndex == "number"){
23713 return node.nodeIndex;
23715 var ns = this.nodes;
23716 for(var i = 0, len = ns.length; i < len; i++){
23726 * Ext JS Library 1.1.1
23727 * Copyright(c) 2006-2007, Ext JS, LLC.
23729 * Originally Released Under LGPL - original licence link has changed is not relivant.
23732 * <script type="text/javascript">
23736 * @class Roo.JsonView
23737 * @extends Roo.View
23738 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23740 var view = new Roo.JsonView({
23741 container: "my-element",
23742 template: '<div id="{id}">{foo} - {bar}</div>', // auto create template
23747 // listen for node click?
23748 view.on("click", function(vw, index, node, e){
23749 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23752 // direct load of JSON data
23753 view.load("foobar.php");
23755 // Example from my blog list
23756 var tpl = new Roo.Template(
23757 '<div class="entry">' +
23758 '<a class="entry-title" href="{link}">{title}</a>' +
23759 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23760 "</div><hr />"
23763 var moreView = new Roo.JsonView({
23764 container : "entry-list",
23768 moreView.on("beforerender", this.sortEntries, this);
23770 url: "/blog/get-posts.php",
23771 params: "allposts=true",
23772 text: "Loading Blog Entries..."
23776 * Note: old code is supported with arguments : (container, template, config)
23780 * Create a new JsonView
23782 * @param {Object} config The config object
23785 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
23788 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
23790 var um = this.el.getUpdateManager();
23791 um.setRenderer(this);
23792 um.on("update", this.onLoad, this);
23793 um.on("failure", this.onLoadException, this);
23796 * @event beforerender
23797 * Fires before rendering of the downloaded JSON data.
23798 * @param {Roo.JsonView} this
23799 * @param {Object} data The JSON data loaded
23803 * Fires when data is loaded.
23804 * @param {Roo.JsonView} this
23805 * @param {Object} data The JSON data loaded
23806 * @param {Object} response The raw Connect response object
23809 * @event loadexception
23810 * Fires when loading fails.
23811 * @param {Roo.JsonView} this
23812 * @param {Object} response The raw Connect response object
23815 'beforerender' : true,
23817 'loadexception' : true
23820 Roo.extend(Roo.JsonView, Roo.View, {
23822 * @type {String} The root property in the loaded JSON object that contains the data
23827 * Refreshes the view.
23829 refresh : function(){
23830 this.clearSelections();
23831 this.el.update("");
23833 var o = this.jsonData;
23834 if(o && o.length > 0){
23835 for(var i = 0, len = o.length; i < len; i++){
23836 var data = this.prepareData(o[i], i, o);
23837 html[html.length] = this.tpl.apply(data);
23840 html.push(this.emptyText);
23842 this.el.update(html.join(""));
23843 this.nodes = this.el.dom.childNodes;
23844 this.updateIndexes(0);
23848 * 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.
23849 * @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:
23852 url: "your-url.php",
23853 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
23854 callback: yourFunction,
23855 scope: yourObject, //(optional scope)
23858 text: "Loading...",
23863 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
23864 * 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.
23865 * @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}
23866 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
23867 * @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.
23870 var um = this.el.getUpdateManager();
23871 um.update.apply(um, arguments);
23874 render : function(el, response){
23875 this.clearSelections();
23876 this.el.update("");
23879 o = Roo.util.JSON.decode(response.responseText);
23882 o = /** eval:var:o */ eval("o." + this.jsonRoot);
23887 * The current JSON data or null
23890 this.beforeRender();
23895 * Get the number of records in the current JSON dataset
23898 getCount : function(){
23899 return this.jsonData ? this.jsonData.length : 0;
23903 * Returns the JSON object for the specified node(s)
23904 * @param {HTMLElement/Array} node The node or an array of nodes
23905 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
23906 * you get the JSON object for the node
23908 getNodeData : function(node){
23909 if(node instanceof Array){
23911 for(var i = 0, len = node.length; i < len; i++){
23912 data.push(this.getNodeData(node[i]));
23916 return this.jsonData[this.indexOf(node)] || null;
23919 beforeRender : function(){
23920 this.snapshot = this.jsonData;
23922 this.sort.apply(this, this.sortInfo);
23924 this.fireEvent("beforerender", this, this.jsonData);
23927 onLoad : function(el, o){
23928 this.fireEvent("load", this, this.jsonData, o);
23931 onLoadException : function(el, o){
23932 this.fireEvent("loadexception", this, o);
23936 * Filter the data by a specific property.
23937 * @param {String} property A property on your JSON objects
23938 * @param {String/RegExp} value Either string that the property values
23939 * should start with, or a RegExp to test against the property
23941 filter : function(property, value){
23944 var ss = this.snapshot;
23945 if(typeof value == "string"){
23946 var vlen = value.length;
23948 this.clearFilter();
23951 value = value.toLowerCase();
23952 for(var i = 0, len = ss.length; i < len; i++){
23954 if(o[property].substr(0, vlen).toLowerCase() == value){
23958 } else if(value.exec){ // regex?
23959 for(var i = 0, len = ss.length; i < len; i++){
23961 if(value.test(o[property])){
23968 this.jsonData = data;
23974 * Filter by a function. The passed function will be called with each
23975 * object in the current dataset. If the function returns true the value is kept,
23976 * otherwise it is filtered.
23977 * @param {Function} fn
23978 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
23980 filterBy : function(fn, scope){
23983 var ss = this.snapshot;
23984 for(var i = 0, len = ss.length; i < len; i++){
23986 if(fn.call(scope || this, o)){
23990 this.jsonData = data;
23996 * Clears the current filter.
23998 clearFilter : function(){
23999 if(this.snapshot && this.jsonData != this.snapshot){
24000 this.jsonData = this.snapshot;
24007 * Sorts the data for this view and refreshes it.
24008 * @param {String} property A property on your JSON objects to sort on
24009 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24010 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24012 sort : function(property, dir, sortType){
24013 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24016 var dsc = dir && dir.toLowerCase() == "desc";
24017 var f = function(o1, o2){
24018 var v1 = sortType ? sortType(o1[p]) : o1[p];
24019 var v2 = sortType ? sortType(o2[p]) : o2[p];
24022 return dsc ? +1 : -1;
24023 } else if(v1 > v2){
24024 return dsc ? -1 : +1;
24029 this.jsonData.sort(f);
24031 if(this.jsonData != this.snapshot){
24032 this.snapshot.sort(f);
24038 * Ext JS Library 1.1.1
24039 * Copyright(c) 2006-2007, Ext JS, LLC.
24041 * Originally Released Under LGPL - original licence link has changed is not relivant.
24044 * <script type="text/javascript">
24049 * @class Roo.ColorPalette
24050 * @extends Roo.Component
24051 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24052 * Here's an example of typical usage:
24054 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24055 cp.render('my-div');
24057 cp.on('select', function(palette, selColor){
24058 // do something with selColor
24062 * Create a new ColorPalette
24063 * @param {Object} config The config object
24065 Roo.ColorPalette = function(config){
24066 Roo.ColorPalette.superclass.constructor.call(this, config);
24070 * Fires when a color is selected
24071 * @param {ColorPalette} this
24072 * @param {String} color The 6-digit color hex code (without the # symbol)
24078 this.on("select", this.handler, this.scope, true);
24081 Roo.extend(Roo.ColorPalette, Roo.Component, {
24083 * @cfg {String} itemCls
24084 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24086 itemCls : "x-color-palette",
24088 * @cfg {String} value
24089 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24090 * the hex codes are case-sensitive.
24093 clickEvent:'click',
24095 ctype: "Roo.ColorPalette",
24098 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24100 allowReselect : false,
24103 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24104 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24105 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24106 * of colors with the width setting until the box is symmetrical.</p>
24107 * <p>You can override individual colors if needed:</p>
24109 var cp = new Roo.ColorPalette();
24110 cp.colors[0] = "FF0000"; // change the first box to red
24113 Or you can provide a custom array of your own for complete control:
24115 var cp = new Roo.ColorPalette();
24116 cp.colors = ["000000", "993300", "333300"];
24121 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24122 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24123 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24124 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24125 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24129 onRender : function(container, position){
24130 var t = new Roo.MasterTemplate(
24131 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24133 var c = this.colors;
24134 for(var i = 0, len = c.length; i < len; i++){
24137 var el = document.createElement("div");
24138 el.className = this.itemCls;
24140 container.dom.insertBefore(el, position);
24141 this.el = Roo.get(el);
24142 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24143 if(this.clickEvent != 'click'){
24144 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24149 afterRender : function(){
24150 Roo.ColorPalette.superclass.afterRender.call(this);
24152 var s = this.value;
24159 handleClick : function(e, t){
24160 e.preventDefault();
24161 if(!this.disabled){
24162 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24163 this.select(c.toUpperCase());
24168 * Selects the specified color in the palette (fires the select event)
24169 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24171 select : function(color){
24172 color = color.replace("#", "");
24173 if(color != this.value || this.allowReselect){
24176 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24178 el.child("a.color-"+color).addClass("x-color-palette-sel");
24179 this.value = color;
24180 this.fireEvent("select", this, color);
24185 * Ext JS Library 1.1.1
24186 * Copyright(c) 2006-2007, Ext JS, LLC.
24188 * Originally Released Under LGPL - original licence link has changed is not relivant.
24191 * <script type="text/javascript">
24195 * @class Roo.DatePicker
24196 * @extends Roo.Component
24197 * Simple date picker class.
24199 * Create a new DatePicker
24200 * @param {Object} config The config object
24202 Roo.DatePicker = function(config){
24203 Roo.DatePicker.superclass.constructor.call(this, config);
24205 this.value = config && config.value ?
24206 config.value.clearTime() : new Date().clearTime();
24211 * Fires when a date is selected
24212 * @param {DatePicker} this
24213 * @param {Date} date The selected date
24219 this.on("select", this.handler, this.scope || this);
24221 // build the disabledDatesRE
24222 if(!this.disabledDatesRE && this.disabledDates){
24223 var dd = this.disabledDates;
24225 for(var i = 0; i < dd.length; i++){
24227 if(i != dd.length-1) re += "|";
24229 this.disabledDatesRE = new RegExp(re + ")");
24233 Roo.extend(Roo.DatePicker, Roo.Component, {
24235 * @cfg {String} todayText
24236 * The text to display on the button that selects the current date (defaults to "Today")
24238 todayText : "Today",
24240 * @cfg {String} okText
24241 * The text to display on the ok button
24243 okText : " OK ", //   to give the user extra clicking room
24245 * @cfg {String} cancelText
24246 * The text to display on the cancel button
24248 cancelText : "Cancel",
24250 * @cfg {String} todayTip
24251 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24253 todayTip : "{0} (Spacebar)",
24255 * @cfg {Date} minDate
24256 * Minimum allowable date (JavaScript date object, defaults to null)
24260 * @cfg {Date} maxDate
24261 * Maximum allowable date (JavaScript date object, defaults to null)
24265 * @cfg {String} minText
24266 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24268 minText : "This date is before the minimum date",
24270 * @cfg {String} maxText
24271 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24273 maxText : "This date is after the maximum date",
24275 * @cfg {String} format
24276 * The default date format string which can be overriden for localization support. The format must be
24277 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24281 * @cfg {Array} disabledDays
24282 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24284 disabledDays : null,
24286 * @cfg {String} disabledDaysText
24287 * The tooltip to display when the date falls on a disabled day (defaults to "")
24289 disabledDaysText : "",
24291 * @cfg {RegExp} disabledDatesRE
24292 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24294 disabledDatesRE : null,
24296 * @cfg {String} disabledDatesText
24297 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24299 disabledDatesText : "",
24301 * @cfg {Boolean} constrainToViewport
24302 * True to constrain the date picker to the viewport (defaults to true)
24304 constrainToViewport : true,
24306 * @cfg {Array} monthNames
24307 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24309 monthNames : Date.monthNames,
24311 * @cfg {Array} dayNames
24312 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24314 dayNames : Date.dayNames,
24316 * @cfg {String} nextText
24317 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24319 nextText: 'Next Month (Control+Right)',
24321 * @cfg {String} prevText
24322 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24324 prevText: 'Previous Month (Control+Left)',
24326 * @cfg {String} monthYearText
24327 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24329 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24331 * @cfg {Number} startDay
24332 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24336 * @cfg {Bool} showClear
24337 * Show a clear button (usefull for date form elements that can be blank.)
24343 * Sets the value of the date field
24344 * @param {Date} value The date to set
24346 setValue : function(value){
24347 var old = this.value;
24348 this.value = value.clearTime(true);
24350 this.update(this.value);
24355 * Gets the current selected value of the date field
24356 * @return {Date} The selected date
24358 getValue : function(){
24363 focus : function(){
24365 this.update(this.activeDate);
24370 onRender : function(container, position){
24372 '<table cellspacing="0">',
24373 '<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>',
24374 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24375 var dn = this.dayNames;
24376 for(var i = 0; i < 7; i++){
24377 var d = this.startDay+i;
24381 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24383 m[m.length] = "</tr></thead><tbody><tr>";
24384 for(var i = 0; i < 42; i++) {
24385 if(i % 7 == 0 && i != 0){
24386 m[m.length] = "</tr><tr>";
24388 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24390 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24391 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24393 var el = document.createElement("div");
24394 el.className = "x-date-picker";
24395 el.innerHTML = m.join("");
24397 container.dom.insertBefore(el, position);
24399 this.el = Roo.get(el);
24400 this.eventEl = Roo.get(el.firstChild);
24402 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24403 handler: this.showPrevMonth,
24405 preventDefault:true,
24409 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24410 handler: this.showNextMonth,
24412 preventDefault:true,
24416 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24418 this.monthPicker = this.el.down('div.x-date-mp');
24419 this.monthPicker.enableDisplayMode('block');
24421 var kn = new Roo.KeyNav(this.eventEl, {
24422 "left" : function(e){
24424 this.showPrevMonth() :
24425 this.update(this.activeDate.add("d", -1));
24428 "right" : function(e){
24430 this.showNextMonth() :
24431 this.update(this.activeDate.add("d", 1));
24434 "up" : function(e){
24436 this.showNextYear() :
24437 this.update(this.activeDate.add("d", -7));
24440 "down" : function(e){
24442 this.showPrevYear() :
24443 this.update(this.activeDate.add("d", 7));
24446 "pageUp" : function(e){
24447 this.showNextMonth();
24450 "pageDown" : function(e){
24451 this.showPrevMonth();
24454 "enter" : function(e){
24455 e.stopPropagation();
24462 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24464 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24466 this.el.unselectable();
24468 this.cells = this.el.select("table.x-date-inner tbody td");
24469 this.textNodes = this.el.query("table.x-date-inner tbody span");
24471 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24473 tooltip: this.monthYearText
24476 this.mbtn.on('click', this.showMonthPicker, this);
24477 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24480 var today = (new Date()).dateFormat(this.format);
24482 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24484 text: String.format(this.todayText, today),
24485 tooltip: String.format(this.todayTip, today),
24486 handler: this.selectToday,
24490 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24493 if (this.showClear) {
24495 baseTb.add( new Roo.Toolbar.Fill());
24498 cls: 'x-btn-icon x-btn-clear',
24499 handler: function() {
24501 this.fireEvent("select", this, '');
24511 this.update(this.value);
24514 createMonthPicker : function(){
24515 if(!this.monthPicker.dom.firstChild){
24516 var buf = ['<table border="0" cellspacing="0">'];
24517 for(var i = 0; i < 6; i++){
24519 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24520 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24522 '<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>' :
24523 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24527 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24529 '</button><button type="button" class="x-date-mp-cancel">',
24531 '</button></td></tr>',
24534 this.monthPicker.update(buf.join(''));
24535 this.monthPicker.on('click', this.onMonthClick, this);
24536 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24538 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24539 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24541 this.mpMonths.each(function(m, a, i){
24544 m.dom.xmonth = 5 + Math.round(i * .5);
24546 m.dom.xmonth = Math.round((i-1) * .5);
24552 showMonthPicker : function(){
24553 this.createMonthPicker();
24554 var size = this.el.getSize();
24555 this.monthPicker.setSize(size);
24556 this.monthPicker.child('table').setSize(size);
24558 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24559 this.updateMPMonth(this.mpSelMonth);
24560 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24561 this.updateMPYear(this.mpSelYear);
24563 this.monthPicker.slideIn('t', {duration:.2});
24566 updateMPYear : function(y){
24568 var ys = this.mpYears.elements;
24569 for(var i = 1; i <= 10; i++){
24570 var td = ys[i-1], y2;
24572 y2 = y + Math.round(i * .5);
24573 td.firstChild.innerHTML = y2;
24576 y2 = y - (5-Math.round(i * .5));
24577 td.firstChild.innerHTML = y2;
24580 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24584 updateMPMonth : function(sm){
24585 this.mpMonths.each(function(m, a, i){
24586 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24590 selectMPMonth: function(m){
24594 onMonthClick : function(e, t){
24596 var el = new Roo.Element(t), pn;
24597 if(el.is('button.x-date-mp-cancel')){
24598 this.hideMonthPicker();
24600 else if(el.is('button.x-date-mp-ok')){
24601 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24602 this.hideMonthPicker();
24604 else if(pn = el.up('td.x-date-mp-month', 2)){
24605 this.mpMonths.removeClass('x-date-mp-sel');
24606 pn.addClass('x-date-mp-sel');
24607 this.mpSelMonth = pn.dom.xmonth;
24609 else if(pn = el.up('td.x-date-mp-year', 2)){
24610 this.mpYears.removeClass('x-date-mp-sel');
24611 pn.addClass('x-date-mp-sel');
24612 this.mpSelYear = pn.dom.xyear;
24614 else if(el.is('a.x-date-mp-prev')){
24615 this.updateMPYear(this.mpyear-10);
24617 else if(el.is('a.x-date-mp-next')){
24618 this.updateMPYear(this.mpyear+10);
24622 onMonthDblClick : function(e, t){
24624 var el = new Roo.Element(t), pn;
24625 if(pn = el.up('td.x-date-mp-month', 2)){
24626 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24627 this.hideMonthPicker();
24629 else if(pn = el.up('td.x-date-mp-year', 2)){
24630 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24631 this.hideMonthPicker();
24635 hideMonthPicker : function(disableAnim){
24636 if(this.monthPicker){
24637 if(disableAnim === true){
24638 this.monthPicker.hide();
24640 this.monthPicker.slideOut('t', {duration:.2});
24646 showPrevMonth : function(e){
24647 this.update(this.activeDate.add("mo", -1));
24651 showNextMonth : function(e){
24652 this.update(this.activeDate.add("mo", 1));
24656 showPrevYear : function(){
24657 this.update(this.activeDate.add("y", -1));
24661 showNextYear : function(){
24662 this.update(this.activeDate.add("y", 1));
24666 handleMouseWheel : function(e){
24667 var delta = e.getWheelDelta();
24669 this.showPrevMonth();
24671 } else if(delta < 0){
24672 this.showNextMonth();
24678 handleDateClick : function(e, t){
24680 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24681 this.setValue(new Date(t.dateValue));
24682 this.fireEvent("select", this, this.value);
24687 selectToday : function(){
24688 this.setValue(new Date().clearTime());
24689 this.fireEvent("select", this, this.value);
24693 update : function(date){
24694 var vd = this.activeDate;
24695 this.activeDate = date;
24697 var t = date.getTime();
24698 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24699 this.cells.removeClass("x-date-selected");
24700 this.cells.each(function(c){
24701 if(c.dom.firstChild.dateValue == t){
24702 c.addClass("x-date-selected");
24703 setTimeout(function(){
24704 try{c.dom.firstChild.focus();}catch(e){}
24712 var days = date.getDaysInMonth();
24713 var firstOfMonth = date.getFirstDateOfMonth();
24714 var startingPos = firstOfMonth.getDay()-this.startDay;
24716 if(startingPos <= this.startDay){
24720 var pm = date.add("mo", -1);
24721 var prevStart = pm.getDaysInMonth()-startingPos;
24723 var cells = this.cells.elements;
24724 var textEls = this.textNodes;
24725 days += startingPos;
24727 // convert everything to numbers so it's fast
24728 var day = 86400000;
24729 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24730 var today = new Date().clearTime().getTime();
24731 var sel = date.clearTime().getTime();
24732 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24733 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24734 var ddMatch = this.disabledDatesRE;
24735 var ddText = this.disabledDatesText;
24736 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24737 var ddaysText = this.disabledDaysText;
24738 var format = this.format;
24740 var setCellClass = function(cal, cell){
24742 var t = d.getTime();
24743 cell.firstChild.dateValue = t;
24745 cell.className += " x-date-today";
24746 cell.title = cal.todayText;
24749 cell.className += " x-date-selected";
24750 setTimeout(function(){
24751 try{cell.firstChild.focus();}catch(e){}
24756 cell.className = " x-date-disabled";
24757 cell.title = cal.minText;
24761 cell.className = " x-date-disabled";
24762 cell.title = cal.maxText;
24766 if(ddays.indexOf(d.getDay()) != -1){
24767 cell.title = ddaysText;
24768 cell.className = " x-date-disabled";
24771 if(ddMatch && format){
24772 var fvalue = d.dateFormat(format);
24773 if(ddMatch.test(fvalue)){
24774 cell.title = ddText.replace("%0", fvalue);
24775 cell.className = " x-date-disabled";
24781 for(; i < startingPos; i++) {
24782 textEls[i].innerHTML = (++prevStart);
24783 d.setDate(d.getDate()+1);
24784 cells[i].className = "x-date-prevday";
24785 setCellClass(this, cells[i]);
24787 for(; i < days; i++){
24788 intDay = i - startingPos + 1;
24789 textEls[i].innerHTML = (intDay);
24790 d.setDate(d.getDate()+1);
24791 cells[i].className = "x-date-active";
24792 setCellClass(this, cells[i]);
24795 for(; i < 42; i++) {
24796 textEls[i].innerHTML = (++extraDays);
24797 d.setDate(d.getDate()+1);
24798 cells[i].className = "x-date-nextday";
24799 setCellClass(this, cells[i]);
24802 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
24804 if(!this.internalRender){
24805 var main = this.el.dom.firstChild;
24806 var w = main.offsetWidth;
24807 this.el.setWidth(w + this.el.getBorderWidth("lr"));
24808 Roo.fly(main).setWidth(w);
24809 this.internalRender = true;
24810 // opera does not respect the auto grow header center column
24811 // then, after it gets a width opera refuses to recalculate
24812 // without a second pass
24813 if(Roo.isOpera && !this.secondPass){
24814 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
24815 this.secondPass = true;
24816 this.update.defer(10, this, [date]);
24822 * Ext JS Library 1.1.1
24823 * Copyright(c) 2006-2007, Ext JS, LLC.
24825 * Originally Released Under LGPL - original licence link has changed is not relivant.
24828 * <script type="text/javascript">
24831 * @class Roo.TabPanel
24832 * @extends Roo.util.Observable
24833 * A lightweight tab container.
24837 // basic tabs 1, built from existing content
24838 var tabs = new Roo.TabPanel("tabs1");
24839 tabs.addTab("script", "View Script");
24840 tabs.addTab("markup", "View Markup");
24841 tabs.activate("script");
24843 // more advanced tabs, built from javascript
24844 var jtabs = new Roo.TabPanel("jtabs");
24845 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
24847 // set up the UpdateManager
24848 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
24849 var updater = tab2.getUpdateManager();
24850 updater.setDefaultUrl("ajax1.htm");
24851 tab2.on('activate', updater.refresh, updater, true);
24853 // Use setUrl for Ajax loading
24854 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
24855 tab3.setUrl("ajax2.htm", null, true);
24858 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
24861 jtabs.activate("jtabs-1");
24864 * Create a new TabPanel.
24865 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
24866 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
24868 Roo.TabPanel = function(container, config){
24870 * The container element for this TabPanel.
24871 * @type Roo.Element
24873 this.el = Roo.get(container, true);
24875 if(typeof config == "boolean"){
24876 this.tabPosition = config ? "bottom" : "top";
24878 Roo.apply(this, config);
24881 if(this.tabPosition == "bottom"){
24882 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24883 this.el.addClass("x-tabs-bottom");
24885 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
24886 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
24887 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
24889 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
24891 if(this.tabPosition != "bottom"){
24892 /** The body element that contains {@link Roo.TabPanelItem} bodies.
24893 * @type Roo.Element
24895 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24896 this.el.addClass("x-tabs-top");
24900 this.bodyEl.setStyle("position", "relative");
24902 this.active = null;
24903 this.activateDelegate = this.activate.createDelegate(this);
24908 * Fires when the active tab changes
24909 * @param {Roo.TabPanel} this
24910 * @param {Roo.TabPanelItem} activePanel The new active tab
24914 * @event beforetabchange
24915 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
24916 * @param {Roo.TabPanel} this
24917 * @param {Object} e Set cancel to true on this object to cancel the tab change
24918 * @param {Roo.TabPanelItem} tab The tab being changed to
24920 "beforetabchange" : true
24923 Roo.EventManager.onWindowResize(this.onResize, this);
24924 this.cpad = this.el.getPadding("lr");
24925 this.hiddenCount = 0;
24927 Roo.TabPanel.superclass.constructor.call(this);
24930 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
24932 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
24934 tabPosition : "top",
24936 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
24938 currentTabWidth : 0,
24940 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
24944 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
24948 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
24950 preferredTabWidth : 175,
24952 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
24954 resizeTabs : false,
24956 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
24958 monitorResize : true,
24961 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
24962 * @param {String} id The id of the div to use <b>or create</b>
24963 * @param {String} text The text for the tab
24964 * @param {String} content (optional) Content to put in the TabPanelItem body
24965 * @param {Boolean} closable (optional) True to create a close icon on the tab
24966 * @return {Roo.TabPanelItem} The created TabPanelItem
24968 addTab : function(id, text, content, closable){
24969 var item = new Roo.TabPanelItem(this, id, text, closable);
24970 this.addTabItem(item);
24972 item.setContent(content);
24978 * Returns the {@link Roo.TabPanelItem} with the specified id/index
24979 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
24980 * @return {Roo.TabPanelItem}
24982 getTab : function(id){
24983 return this.items[id];
24987 * Hides the {@link Roo.TabPanelItem} with the specified id/index
24988 * @param {String/Number} id The id or index of the TabPanelItem to hide.
24990 hideTab : function(id){
24991 var t = this.items[id];
24994 this.hiddenCount++;
24995 this.autoSizeTabs();
25000 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25001 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25003 unhideTab : function(id){
25004 var t = this.items[id];
25006 t.setHidden(false);
25007 this.hiddenCount--;
25008 this.autoSizeTabs();
25013 * Adds an existing {@link Roo.TabPanelItem}.
25014 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25016 addTabItem : function(item){
25017 this.items[item.id] = item;
25018 this.items.push(item);
25019 if(this.resizeTabs){
25020 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25021 this.autoSizeTabs();
25028 * Removes a {@link Roo.TabPanelItem}.
25029 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25031 removeTab : function(id){
25032 var items = this.items;
25033 var tab = items[id];
25035 var index = items.indexOf(tab);
25036 if(this.active == tab && items.length > 1){
25037 var newTab = this.getNextAvailable(index);
25038 if(newTab)newTab.activate();
25040 this.stripEl.dom.removeChild(tab.pnode.dom);
25041 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25042 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25044 items.splice(index, 1);
25045 delete this.items[tab.id];
25046 tab.fireEvent("close", tab);
25047 tab.purgeListeners();
25048 this.autoSizeTabs();
25051 getNextAvailable : function(start){
25052 var items = this.items;
25054 // look for a next tab that will slide over to
25055 // replace the one being removed
25056 while(index < items.length){
25057 var item = items[++index];
25058 if(item && !item.isHidden()){
25062 // if one isn't found select the previous tab (on the left)
25065 var item = items[--index];
25066 if(item && !item.isHidden()){
25074 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25075 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25077 disableTab : function(id){
25078 var tab = this.items[id];
25079 if(tab && this.active != tab){
25085 * Enables a {@link Roo.TabPanelItem} that is disabled.
25086 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25088 enableTab : function(id){
25089 var tab = this.items[id];
25094 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25095 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25096 * @return {Roo.TabPanelItem} The TabPanelItem.
25098 activate : function(id){
25099 var tab = this.items[id];
25103 if(tab == this.active || tab.disabled){
25107 this.fireEvent("beforetabchange", this, e, tab);
25108 if(e.cancel !== true && !tab.disabled){
25110 this.active.hide();
25112 this.active = this.items[id];
25113 this.active.show();
25114 this.fireEvent("tabchange", this, this.active);
25120 * Gets the active {@link Roo.TabPanelItem}.
25121 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25123 getActiveTab : function(){
25124 return this.active;
25128 * Updates the tab body element to fit the height of the container element
25129 * for overflow scrolling
25130 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25132 syncHeight : function(targetHeight){
25133 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25134 var bm = this.bodyEl.getMargins();
25135 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25136 this.bodyEl.setHeight(newHeight);
25140 onResize : function(){
25141 if(this.monitorResize){
25142 this.autoSizeTabs();
25147 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25149 beginUpdate : function(){
25150 this.updating = true;
25154 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25156 endUpdate : function(){
25157 this.updating = false;
25158 this.autoSizeTabs();
25162 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25164 autoSizeTabs : function(){
25165 var count = this.items.length;
25166 var vcount = count - this.hiddenCount;
25167 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25168 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25169 var availWidth = Math.floor(w / vcount);
25170 var b = this.stripBody;
25171 if(b.getWidth() > w){
25172 var tabs = this.items;
25173 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25174 if(availWidth < this.minTabWidth){
25175 /*if(!this.sleft){ // incomplete scrolling code
25176 this.createScrollButtons();
25179 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25182 if(this.currentTabWidth < this.preferredTabWidth){
25183 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25189 * Returns the number of tabs in this TabPanel.
25192 getCount : function(){
25193 return this.items.length;
25197 * Resizes all the tabs to the passed width
25198 * @param {Number} The new width
25200 setTabWidth : function(width){
25201 this.currentTabWidth = width;
25202 for(var i = 0, len = this.items.length; i < len; i++) {
25203 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25208 * Destroys this TabPanel
25209 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25211 destroy : function(removeEl){
25212 Roo.EventManager.removeResizeListener(this.onResize, this);
25213 for(var i = 0, len = this.items.length; i < len; i++){
25214 this.items[i].purgeListeners();
25216 if(removeEl === true){
25217 this.el.update("");
25224 * @class Roo.TabPanelItem
25225 * @extends Roo.util.Observable
25226 * Represents an individual item (tab plus body) in a TabPanel.
25227 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25228 * @param {String} id The id of this TabPanelItem
25229 * @param {String} text The text for the tab of this TabPanelItem
25230 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25232 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25234 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25235 * @type Roo.TabPanel
25237 this.tabPanel = tabPanel;
25239 * The id for this TabPanelItem
25244 this.disabled = false;
25248 this.loaded = false;
25249 this.closable = closable;
25252 * The body element for this TabPanelItem.
25253 * @type Roo.Element
25255 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25256 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25257 this.bodyEl.setStyle("display", "block");
25258 this.bodyEl.setStyle("zoom", "1");
25261 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25263 this.el = Roo.get(els.el, true);
25264 this.inner = Roo.get(els.inner, true);
25265 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25266 this.pnode = Roo.get(els.el.parentNode, true);
25267 this.el.on("mousedown", this.onTabMouseDown, this);
25268 this.el.on("click", this.onTabClick, this);
25271 var c = Roo.get(els.close, true);
25272 c.dom.title = this.closeText;
25273 c.addClassOnOver("close-over");
25274 c.on("click", this.closeClick, this);
25280 * Fires when this tab becomes the active tab.
25281 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25282 * @param {Roo.TabPanelItem} this
25286 * @event beforeclose
25287 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25288 * @param {Roo.TabPanelItem} this
25289 * @param {Object} e Set cancel to true on this object to cancel the close.
25291 "beforeclose": true,
25294 * Fires when this tab is closed.
25295 * @param {Roo.TabPanelItem} this
25299 * @event deactivate
25300 * Fires when this tab is no longer the active tab.
25301 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25302 * @param {Roo.TabPanelItem} this
25304 "deactivate" : true
25306 this.hidden = false;
25308 Roo.TabPanelItem.superclass.constructor.call(this);
25311 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25312 purgeListeners : function(){
25313 Roo.util.Observable.prototype.purgeListeners.call(this);
25314 this.el.removeAllListeners();
25317 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25320 this.pnode.addClass("on");
25323 this.tabPanel.stripWrap.repaint();
25325 this.fireEvent("activate", this.tabPanel, this);
25329 * Returns true if this tab is the active tab.
25330 * @return {Boolean}
25332 isActive : function(){
25333 return this.tabPanel.getActiveTab() == this;
25337 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25340 this.pnode.removeClass("on");
25342 this.fireEvent("deactivate", this.tabPanel, this);
25345 hideAction : function(){
25346 this.bodyEl.hide();
25347 this.bodyEl.setStyle("position", "absolute");
25348 this.bodyEl.setLeft("-20000px");
25349 this.bodyEl.setTop("-20000px");
25352 showAction : function(){
25353 this.bodyEl.setStyle("position", "relative");
25354 this.bodyEl.setTop("");
25355 this.bodyEl.setLeft("");
25356 this.bodyEl.show();
25360 * Set the tooltip for the tab.
25361 * @param {String} tooltip The tab's tooltip
25363 setTooltip : function(text){
25364 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25365 this.textEl.dom.qtip = text;
25366 this.textEl.dom.removeAttribute('title');
25368 this.textEl.dom.title = text;
25372 onTabClick : function(e){
25373 e.preventDefault();
25374 this.tabPanel.activate(this.id);
25377 onTabMouseDown : function(e){
25378 e.preventDefault();
25379 this.tabPanel.activate(this.id);
25382 getWidth : function(){
25383 return this.inner.getWidth();
25386 setWidth : function(width){
25387 var iwidth = width - this.pnode.getPadding("lr");
25388 this.inner.setWidth(iwidth);
25389 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25390 this.pnode.setWidth(width);
25394 * Show or hide the tab
25395 * @param {Boolean} hidden True to hide or false to show.
25397 setHidden : function(hidden){
25398 this.hidden = hidden;
25399 this.pnode.setStyle("display", hidden ? "none" : "");
25403 * Returns true if this tab is "hidden"
25404 * @return {Boolean}
25406 isHidden : function(){
25407 return this.hidden;
25411 * Returns the text for this tab
25414 getText : function(){
25418 autoSize : function(){
25419 //this.el.beginMeasure();
25420 this.textEl.setWidth(1);
25421 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25422 //this.el.endMeasure();
25426 * Sets the text for the tab (Note: this also sets the tooltip text)
25427 * @param {String} text The tab's text and tooltip
25429 setText : function(text){
25431 this.textEl.update(text);
25432 this.setTooltip(text);
25433 if(!this.tabPanel.resizeTabs){
25438 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25440 activate : function(){
25441 this.tabPanel.activate(this.id);
25445 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25447 disable : function(){
25448 if(this.tabPanel.active != this){
25449 this.disabled = true;
25450 this.pnode.addClass("disabled");
25455 * Enables this TabPanelItem if it was previously disabled.
25457 enable : function(){
25458 this.disabled = false;
25459 this.pnode.removeClass("disabled");
25463 * Sets the content for this TabPanelItem.
25464 * @param {String} content The content
25465 * @param {Boolean} loadScripts true to look for and load scripts
25467 setContent : function(content, loadScripts){
25468 this.bodyEl.update(content, loadScripts);
25472 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25473 * @return {Roo.UpdateManager} The UpdateManager
25475 getUpdateManager : function(){
25476 return this.bodyEl.getUpdateManager();
25480 * Set a URL to be used to load the content for this TabPanelItem.
25481 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25482 * @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)
25483 * @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)
25484 * @return {Roo.UpdateManager} The UpdateManager
25486 setUrl : function(url, params, loadOnce){
25487 if(this.refreshDelegate){
25488 this.un('activate', this.refreshDelegate);
25490 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25491 this.on("activate", this.refreshDelegate);
25492 return this.bodyEl.getUpdateManager();
25496 _handleRefresh : function(url, params, loadOnce){
25497 if(!loadOnce || !this.loaded){
25498 var updater = this.bodyEl.getUpdateManager();
25499 updater.update(url, params, this._setLoaded.createDelegate(this));
25504 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25505 * Will fail silently if the setUrl method has not been called.
25506 * This does not activate the panel, just updates its content.
25508 refresh : function(){
25509 if(this.refreshDelegate){
25510 this.loaded = false;
25511 this.refreshDelegate();
25516 _setLoaded : function(){
25517 this.loaded = true;
25521 closeClick : function(e){
25524 this.fireEvent("beforeclose", this, o);
25525 if(o.cancel !== true){
25526 this.tabPanel.removeTab(this.id);
25530 * The text displayed in the tooltip for the close icon.
25533 closeText : "Close this tab"
25537 Roo.TabPanel.prototype.createStrip = function(container){
25538 var strip = document.createElement("div");
25539 strip.className = "x-tabs-wrap";
25540 container.appendChild(strip);
25544 Roo.TabPanel.prototype.createStripList = function(strip){
25545 // div wrapper for retard IE
25546 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>';
25547 return strip.firstChild.firstChild.firstChild.firstChild;
25550 Roo.TabPanel.prototype.createBody = function(container){
25551 var body = document.createElement("div");
25552 Roo.id(body, "tab-body");
25553 Roo.fly(body).addClass("x-tabs-body");
25554 container.appendChild(body);
25558 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25559 var body = Roo.getDom(id);
25561 body = document.createElement("div");
25564 Roo.fly(body).addClass("x-tabs-item-body");
25565 bodyEl.insertBefore(body, bodyEl.firstChild);
25569 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25570 var td = document.createElement("td");
25571 stripEl.appendChild(td);
25573 td.className = "x-tabs-closable";
25574 if(!this.closeTpl){
25575 this.closeTpl = new Roo.Template(
25576 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25577 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25578 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25581 var el = this.closeTpl.overwrite(td, {"text": text});
25582 var close = el.getElementsByTagName("div")[0];
25583 var inner = el.getElementsByTagName("em")[0];
25584 return {"el": el, "close": close, "inner": inner};
25587 this.tabTpl = new Roo.Template(
25588 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25589 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25592 var el = this.tabTpl.overwrite(td, {"text": text});
25593 var inner = el.getElementsByTagName("em")[0];
25594 return {"el": el, "inner": inner};
25598 * Ext JS Library 1.1.1
25599 * Copyright(c) 2006-2007, Ext JS, LLC.
25601 * Originally Released Under LGPL - original licence link has changed is not relivant.
25604 * <script type="text/javascript">
25608 * @class Roo.Button
25609 * @extends Roo.util.Observable
25610 * Simple Button class
25611 * @cfg {String} text The button text
25612 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25613 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25614 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25615 * @cfg {Object} scope The scope of the handler
25616 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25617 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25618 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25619 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25620 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25621 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25622 applies if enableToggle = true)
25623 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25624 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25625 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25627 * Create a new button
25628 * @param {Object} config The config object
25630 Roo.Button = function(renderTo, config)
25634 renderTo = config.renderTo || false;
25637 Roo.apply(this, config);
25641 * Fires when this button is clicked
25642 * @param {Button} this
25643 * @param {EventObject} e The click event
25648 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25649 * @param {Button} this
25650 * @param {Boolean} pressed
25655 * Fires when the mouse hovers over the button
25656 * @param {Button} this
25657 * @param {Event} e The event object
25659 'mouseover' : true,
25662 * Fires when the mouse exits the button
25663 * @param {Button} this
25664 * @param {Event} e The event object
25669 * Fires when the button is rendered
25670 * @param {Button} this
25675 this.menu = Roo.menu.MenuMgr.get(this.menu);
25678 this.render(renderTo);
25681 Roo.util.Observable.call(this);
25684 Roo.extend(Roo.Button, Roo.util.Observable, {
25690 * Read-only. True if this button is hidden
25695 * Read-only. True if this button is disabled
25700 * Read-only. True if this button is pressed (only if enableToggle = true)
25706 * @cfg {Number} tabIndex
25707 * The DOM tabIndex for this button (defaults to undefined)
25709 tabIndex : undefined,
25712 * @cfg {Boolean} enableToggle
25713 * True to enable pressed/not pressed toggling (defaults to false)
25715 enableToggle: false,
25717 * @cfg {Mixed} menu
25718 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25722 * @cfg {String} menuAlign
25723 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25725 menuAlign : "tl-bl?",
25728 * @cfg {String} iconCls
25729 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25731 iconCls : undefined,
25733 * @cfg {String} type
25734 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25739 menuClassTarget: 'tr',
25742 * @cfg {String} clickEvent
25743 * The type of event to map to the button's event handler (defaults to 'click')
25745 clickEvent : 'click',
25748 * @cfg {Boolean} handleMouseEvents
25749 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25751 handleMouseEvents : true,
25754 * @cfg {String} tooltipType
25755 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
25757 tooltipType : 'qtip',
25760 * @cfg {String} cls
25761 * A CSS class to apply to the button's main element.
25765 * @cfg {Roo.Template} template (Optional)
25766 * An {@link Roo.Template} with which to create the Button's main element. This Template must
25767 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
25768 * require code modifications if required elements (e.g. a button) aren't present.
25772 render : function(renderTo){
25774 if(this.hideParent){
25775 this.parentEl = Roo.get(renderTo);
25777 if(!this.dhconfig){
25778 if(!this.template){
25779 if(!Roo.Button.buttonTemplate){
25780 // hideous table template
25781 Roo.Button.buttonTemplate = new Roo.Template(
25782 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
25783 '<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>',
25784 "</tr></tbody></table>");
25786 this.template = Roo.Button.buttonTemplate;
25788 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
25789 var btnEl = btn.child("button:first");
25790 btnEl.on('focus', this.onFocus, this);
25791 btnEl.on('blur', this.onBlur, this);
25793 btn.addClass(this.cls);
25796 btnEl.setStyle('background-image', 'url(' +this.icon +')');
25799 btnEl.addClass(this.iconCls);
25801 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
25804 if(this.tabIndex !== undefined){
25805 btnEl.dom.tabIndex = this.tabIndex;
25808 if(typeof this.tooltip == 'object'){
25809 Roo.QuickTips.tips(Roo.apply({
25813 btnEl.dom[this.tooltipType] = this.tooltip;
25817 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
25821 this.el.dom.id = this.el.id = this.id;
25824 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
25825 this.menu.on("show", this.onMenuShow, this);
25826 this.menu.on("hide", this.onMenuHide, this);
25828 btn.addClass("x-btn");
25829 if(Roo.isIE && !Roo.isIE7){
25830 this.autoWidth.defer(1, this);
25834 if(this.handleMouseEvents){
25835 btn.on("mouseover", this.onMouseOver, this);
25836 btn.on("mouseout", this.onMouseOut, this);
25837 btn.on("mousedown", this.onMouseDown, this);
25839 btn.on(this.clickEvent, this.onClick, this);
25840 //btn.on("mouseup", this.onMouseUp, this);
25847 Roo.ButtonToggleMgr.register(this);
25849 this.el.addClass("x-btn-pressed");
25852 var repeater = new Roo.util.ClickRepeater(btn,
25853 typeof this.repeat == "object" ? this.repeat : {}
25855 repeater.on("click", this.onClick, this);
25857 this.fireEvent('render', this);
25861 * Returns the button's underlying element
25862 * @return {Roo.Element} The element
25864 getEl : function(){
25869 * Destroys this Button and removes any listeners.
25871 destroy : function(){
25872 Roo.ButtonToggleMgr.unregister(this);
25873 this.el.removeAllListeners();
25874 this.purgeListeners();
25879 autoWidth : function(){
25881 this.el.setWidth("auto");
25882 if(Roo.isIE7 && Roo.isStrict){
25883 var ib = this.el.child('button');
25884 if(ib && ib.getWidth() > 20){
25886 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
25891 this.el.beginMeasure();
25893 if(this.el.getWidth() < this.minWidth){
25894 this.el.setWidth(this.minWidth);
25897 this.el.endMeasure();
25904 * Assigns this button's click handler
25905 * @param {Function} handler The function to call when the button is clicked
25906 * @param {Object} scope (optional) Scope for the function passed in
25908 setHandler : function(handler, scope){
25909 this.handler = handler;
25910 this.scope = scope;
25914 * Sets this button's text
25915 * @param {String} text The button text
25917 setText : function(text){
25920 this.el.child("td.x-btn-center button.x-btn-text").update(text);
25926 * Gets the text for this button
25927 * @return {String} The button text
25929 getText : function(){
25937 this.hidden = false;
25939 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
25947 this.hidden = true;
25949 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
25954 * Convenience function for boolean show/hide
25955 * @param {Boolean} visible True to show, false to hide
25957 setVisible: function(visible){
25966 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
25967 * @param {Boolean} state (optional) Force a particular state
25969 toggle : function(state){
25970 state = state === undefined ? !this.pressed : state;
25971 if(state != this.pressed){
25973 this.el.addClass("x-btn-pressed");
25974 this.pressed = true;
25975 this.fireEvent("toggle", this, true);
25977 this.el.removeClass("x-btn-pressed");
25978 this.pressed = false;
25979 this.fireEvent("toggle", this, false);
25981 if(this.toggleHandler){
25982 this.toggleHandler.call(this.scope || this, this, state);
25990 focus : function(){
25991 this.el.child('button:first').focus();
25995 * Disable this button
25997 disable : function(){
25999 this.el.addClass("x-btn-disabled");
26001 this.disabled = true;
26005 * Enable this button
26007 enable : function(){
26009 this.el.removeClass("x-btn-disabled");
26011 this.disabled = false;
26015 * Convenience function for boolean enable/disable
26016 * @param {Boolean} enabled True to enable, false to disable
26018 setDisabled : function(v){
26019 this[v !== true ? "enable" : "disable"]();
26023 onClick : function(e){
26025 e.preventDefault();
26030 if(!this.disabled){
26031 if(this.enableToggle){
26034 if(this.menu && !this.menu.isVisible()){
26035 this.menu.show(this.el, this.menuAlign);
26037 this.fireEvent("click", this, e);
26039 this.el.removeClass("x-btn-over");
26040 this.handler.call(this.scope || this, this, e);
26045 onMouseOver : function(e){
26046 if(!this.disabled){
26047 this.el.addClass("x-btn-over");
26048 this.fireEvent('mouseover', this, e);
26052 onMouseOut : function(e){
26053 if(!e.within(this.el, true)){
26054 this.el.removeClass("x-btn-over");
26055 this.fireEvent('mouseout', this, e);
26059 onFocus : function(e){
26060 if(!this.disabled){
26061 this.el.addClass("x-btn-focus");
26065 onBlur : function(e){
26066 this.el.removeClass("x-btn-focus");
26069 onMouseDown : function(e){
26070 if(!this.disabled && e.button == 0){
26071 this.el.addClass("x-btn-click");
26072 Roo.get(document).on('mouseup', this.onMouseUp, this);
26076 onMouseUp : function(e){
26078 this.el.removeClass("x-btn-click");
26079 Roo.get(document).un('mouseup', this.onMouseUp, this);
26083 onMenuShow : function(e){
26084 this.el.addClass("x-btn-menu-active");
26087 onMenuHide : function(e){
26088 this.el.removeClass("x-btn-menu-active");
26092 // Private utility class used by Button
26093 Roo.ButtonToggleMgr = function(){
26096 function toggleGroup(btn, state){
26098 var g = groups[btn.toggleGroup];
26099 for(var i = 0, l = g.length; i < l; i++){
26101 g[i].toggle(false);
26108 register : function(btn){
26109 if(!btn.toggleGroup){
26112 var g = groups[btn.toggleGroup];
26114 g = groups[btn.toggleGroup] = [];
26117 btn.on("toggle", toggleGroup);
26120 unregister : function(btn){
26121 if(!btn.toggleGroup){
26124 var g = groups[btn.toggleGroup];
26127 btn.un("toggle", toggleGroup);
26133 * Ext JS Library 1.1.1
26134 * Copyright(c) 2006-2007, Ext JS, LLC.
26136 * Originally Released Under LGPL - original licence link has changed is not relivant.
26139 * <script type="text/javascript">
26143 * @class Roo.SplitButton
26144 * @extends Roo.Button
26145 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26146 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26147 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26148 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26149 * @cfg {String} arrowTooltip The title attribute of the arrow
26151 * Create a new menu button
26152 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26153 * @param {Object} config The config object
26155 Roo.SplitButton = function(renderTo, config){
26156 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26158 * @event arrowclick
26159 * Fires when this button's arrow is clicked
26160 * @param {SplitButton} this
26161 * @param {EventObject} e The click event
26163 this.addEvents({"arrowclick":true});
26166 Roo.extend(Roo.SplitButton, Roo.Button, {
26167 render : function(renderTo){
26168 // this is one sweet looking template!
26169 var tpl = new Roo.Template(
26170 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26171 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26172 '<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>',
26173 "</tbody></table></td><td>",
26174 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26175 '<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>',
26176 "</tbody></table></td></tr></table>"
26178 var btn = tpl.append(renderTo, [this.text, this.type], true);
26179 var btnEl = btn.child("button");
26181 btn.addClass(this.cls);
26184 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26187 btnEl.addClass(this.iconCls);
26189 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26193 if(this.handleMouseEvents){
26194 btn.on("mouseover", this.onMouseOver, this);
26195 btn.on("mouseout", this.onMouseOut, this);
26196 btn.on("mousedown", this.onMouseDown, this);
26197 btn.on("mouseup", this.onMouseUp, this);
26199 btn.on(this.clickEvent, this.onClick, this);
26201 if(typeof this.tooltip == 'object'){
26202 Roo.QuickTips.tips(Roo.apply({
26206 btnEl.dom[this.tooltipType] = this.tooltip;
26209 if(this.arrowTooltip){
26210 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26219 this.el.addClass("x-btn-pressed");
26221 if(Roo.isIE && !Roo.isIE7){
26222 this.autoWidth.defer(1, this);
26227 this.menu.on("show", this.onMenuShow, this);
26228 this.menu.on("hide", this.onMenuHide, this);
26230 this.fireEvent('render', this);
26234 autoWidth : function(){
26236 var tbl = this.el.child("table:first");
26237 var tbl2 = this.el.child("table:last");
26238 this.el.setWidth("auto");
26239 tbl.setWidth("auto");
26240 if(Roo.isIE7 && Roo.isStrict){
26241 var ib = this.el.child('button:first');
26242 if(ib && ib.getWidth() > 20){
26244 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26249 this.el.beginMeasure();
26251 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26252 tbl.setWidth(this.minWidth-tbl2.getWidth());
26255 this.el.endMeasure();
26258 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26262 * Sets this button's click handler
26263 * @param {Function} handler The function to call when the button is clicked
26264 * @param {Object} scope (optional) Scope for the function passed above
26266 setHandler : function(handler, scope){
26267 this.handler = handler;
26268 this.scope = scope;
26272 * Sets this button's arrow click handler
26273 * @param {Function} handler The function to call when the arrow is clicked
26274 * @param {Object} scope (optional) Scope for the function passed above
26276 setArrowHandler : function(handler, scope){
26277 this.arrowHandler = handler;
26278 this.scope = scope;
26284 focus : function(){
26286 this.el.child("button:first").focus();
26291 onClick : function(e){
26292 e.preventDefault();
26293 if(!this.disabled){
26294 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26295 if(this.menu && !this.menu.isVisible()){
26296 this.menu.show(this.el, this.menuAlign);
26298 this.fireEvent("arrowclick", this, e);
26299 if(this.arrowHandler){
26300 this.arrowHandler.call(this.scope || this, this, e);
26303 this.fireEvent("click", this, e);
26305 this.handler.call(this.scope || this, this, e);
26311 onMouseDown : function(e){
26312 if(!this.disabled){
26313 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26317 onMouseUp : function(e){
26318 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26323 // backwards compat
26324 Roo.MenuButton = Roo.SplitButton;/*
26326 * Ext JS Library 1.1.1
26327 * Copyright(c) 2006-2007, Ext JS, LLC.
26329 * Originally Released Under LGPL - original licence link has changed is not relivant.
26332 * <script type="text/javascript">
26336 * @class Roo.Toolbar
26337 * Basic Toolbar class.
26339 * Creates a new Toolbar
26340 * @param {Object} config The config object
26342 Roo.Toolbar = function(container, buttons, config)
26344 /// old consturctor format still supported..
26345 if(container instanceof Array){ // omit the container for later rendering
26346 buttons = container;
26350 if (typeof(container) == 'object' && container.xtype) {
26351 config = container;
26352 container = config.container;
26353 buttons = config.buttons; // not really - use items!!
26356 if (config && config.items) {
26357 xitems = config.items;
26358 delete config.items;
26360 Roo.apply(this, config);
26361 this.buttons = buttons;
26364 this.render(container);
26366 Roo.each(xitems, function(b) {
26372 Roo.Toolbar.prototype = {
26374 * @cfg {Roo.data.Store} items
26375 * array of button configs or elements to add
26379 * @cfg {String/HTMLElement/Element} container
26380 * The id or element that will contain the toolbar
26383 render : function(ct){
26384 this.el = Roo.get(ct);
26386 this.el.addClass(this.cls);
26388 // using a table allows for vertical alignment
26389 // 100% width is needed by Safari...
26390 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26391 this.tr = this.el.child("tr", true);
26393 this.items = new Roo.util.MixedCollection(false, function(o){
26394 return o.id || ("item" + (++autoId));
26397 this.add.apply(this, this.buttons);
26398 delete this.buttons;
26403 * Adds element(s) to the toolbar -- this function takes a variable number of
26404 * arguments of mixed type and adds them to the toolbar.
26405 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26407 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26408 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26409 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26410 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26411 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26412 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26413 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26414 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26415 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26417 * @param {Mixed} arg2
26418 * @param {Mixed} etc.
26421 var a = arguments, l = a.length;
26422 for(var i = 0; i < l; i++){
26427 _add : function(el) {
26430 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26433 if (el.applyTo){ // some kind of form field
26434 return this.addField(el);
26436 if (el.render){ // some kind of Toolbar.Item
26437 return this.addItem(el);
26439 if (typeof el == "string"){ // string
26440 if(el == "separator" || el == "-"){
26441 return this.addSeparator();
26444 return this.addSpacer();
26447 return this.addFill();
26449 return this.addText(el);
26452 if(el.tagName){ // element
26453 return this.addElement(el);
26455 if(typeof el == "object"){ // must be button config?
26456 return this.addButton(el);
26458 // and now what?!?!
26464 * Add an Xtype element
26465 * @param {Object} xtype Xtype Object
26466 * @return {Object} created Object
26468 addxtype : function(e){
26469 return this.add(e);
26473 * Returns the Element for this toolbar.
26474 * @return {Roo.Element}
26476 getEl : function(){
26482 * @return {Roo.Toolbar.Item} The separator item
26484 addSeparator : function(){
26485 return this.addItem(new Roo.Toolbar.Separator());
26489 * Adds a spacer element
26490 * @return {Roo.Toolbar.Spacer} The spacer item
26492 addSpacer : function(){
26493 return this.addItem(new Roo.Toolbar.Spacer());
26497 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26498 * @return {Roo.Toolbar.Fill} The fill item
26500 addFill : function(){
26501 return this.addItem(new Roo.Toolbar.Fill());
26505 * Adds any standard HTML element to the toolbar
26506 * @param {String/HTMLElement/Element} el The element or id of the element to add
26507 * @return {Roo.Toolbar.Item} The element's item
26509 addElement : function(el){
26510 return this.addItem(new Roo.Toolbar.Item(el));
26513 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26514 * @type Roo.util.MixedCollection
26519 * Adds any Toolbar.Item or subclass
26520 * @param {Roo.Toolbar.Item} item
26521 * @return {Roo.Toolbar.Item} The item
26523 addItem : function(item){
26524 var td = this.nextBlock();
26526 this.items.add(item);
26531 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26532 * @param {Object/Array} config A button config or array of configs
26533 * @return {Roo.Toolbar.Button/Array}
26535 addButton : function(config){
26536 if(config instanceof Array){
26538 for(var i = 0, len = config.length; i < len; i++) {
26539 buttons.push(this.addButton(config[i]));
26544 if(!(config instanceof Roo.Toolbar.Button)){
26546 new Roo.Toolbar.SplitButton(config) :
26547 new Roo.Toolbar.Button(config);
26549 var td = this.nextBlock();
26556 * Adds text to the toolbar
26557 * @param {String} text The text to add
26558 * @return {Roo.Toolbar.Item} The element's item
26560 addText : function(text){
26561 return this.addItem(new Roo.Toolbar.TextItem(text));
26565 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26566 * @param {Number} index The index where the item is to be inserted
26567 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26568 * @return {Roo.Toolbar.Button/Item}
26570 insertButton : function(index, item){
26571 if(item instanceof Array){
26573 for(var i = 0, len = item.length; i < len; i++) {
26574 buttons.push(this.insertButton(index + i, item[i]));
26578 if (!(item instanceof Roo.Toolbar.Button)){
26579 item = new Roo.Toolbar.Button(item);
26581 var td = document.createElement("td");
26582 this.tr.insertBefore(td, this.tr.childNodes[index]);
26584 this.items.insert(index, item);
26589 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26590 * @param {Object} config
26591 * @return {Roo.Toolbar.Item} The element's item
26593 addDom : function(config, returnEl){
26594 var td = this.nextBlock();
26595 Roo.DomHelper.overwrite(td, config);
26596 var ti = new Roo.Toolbar.Item(td.firstChild);
26598 this.items.add(ti);
26603 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26604 * @type Roo.util.MixedCollection
26609 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26610 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26611 * @param {Roo.form.Field} field
26612 * @return {Roo.ToolbarItem}
26616 addField : function(field) {
26617 if (!this.fields) {
26619 this.fields = new Roo.util.MixedCollection(false, function(o){
26620 return o.id || ("item" + (++autoId));
26625 var td = this.nextBlock();
26627 var ti = new Roo.Toolbar.Item(td.firstChild);
26629 this.items.add(ti);
26630 this.fields.add(field);
26641 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26642 this.el.child('div').hide();
26650 this.el.child('div').show();
26654 nextBlock : function(){
26655 var td = document.createElement("td");
26656 this.tr.appendChild(td);
26661 destroy : function(){
26662 if(this.items){ // rendered?
26663 Roo.destroy.apply(Roo, this.items.items);
26665 if(this.fields){ // rendered?
26666 Roo.destroy.apply(Roo, this.fields.items);
26668 Roo.Element.uncache(this.el, this.tr);
26673 * @class Roo.Toolbar.Item
26674 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26676 * Creates a new Item
26677 * @param {HTMLElement} el
26679 Roo.Toolbar.Item = function(el){
26680 this.el = Roo.getDom(el);
26681 this.id = Roo.id(this.el);
26682 this.hidden = false;
26685 Roo.Toolbar.Item.prototype = {
26688 * Get this item's HTML Element
26689 * @return {HTMLElement}
26691 getEl : function(){
26696 render : function(td){
26698 td.appendChild(this.el);
26702 * Removes and destroys this item.
26704 destroy : function(){
26705 this.td.parentNode.removeChild(this.td);
26712 this.hidden = false;
26713 this.td.style.display = "";
26720 this.hidden = true;
26721 this.td.style.display = "none";
26725 * Convenience function for boolean show/hide.
26726 * @param {Boolean} visible true to show/false to hide
26728 setVisible: function(visible){
26737 * Try to focus this item.
26739 focus : function(){
26740 Roo.fly(this.el).focus();
26744 * Disables this item.
26746 disable : function(){
26747 Roo.fly(this.td).addClass("x-item-disabled");
26748 this.disabled = true;
26749 this.el.disabled = true;
26753 * Enables this item.
26755 enable : function(){
26756 Roo.fly(this.td).removeClass("x-item-disabled");
26757 this.disabled = false;
26758 this.el.disabled = false;
26764 * @class Roo.Toolbar.Separator
26765 * @extends Roo.Toolbar.Item
26766 * A simple toolbar separator class
26768 * Creates a new Separator
26770 Roo.Toolbar.Separator = function(){
26771 var s = document.createElement("span");
26772 s.className = "ytb-sep";
26773 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
26775 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
26776 enable:Roo.emptyFn,
26777 disable:Roo.emptyFn,
26782 * @class Roo.Toolbar.Spacer
26783 * @extends Roo.Toolbar.Item
26784 * A simple element that adds extra horizontal space to a toolbar.
26786 * Creates a new Spacer
26788 Roo.Toolbar.Spacer = function(){
26789 var s = document.createElement("div");
26790 s.className = "ytb-spacer";
26791 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
26793 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
26794 enable:Roo.emptyFn,
26795 disable:Roo.emptyFn,
26800 * @class Roo.Toolbar.Fill
26801 * @extends Roo.Toolbar.Spacer
26802 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
26804 * Creates a new Spacer
26806 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
26808 render : function(td){
26809 td.style.width = '100%';
26810 Roo.Toolbar.Fill.superclass.render.call(this, td);
26815 * @class Roo.Toolbar.TextItem
26816 * @extends Roo.Toolbar.Item
26817 * A simple class that renders text directly into a toolbar.
26819 * Creates a new TextItem
26820 * @param {String} text
26822 Roo.Toolbar.TextItem = function(text){
26823 if (typeof(text) == 'object') {
26826 var s = document.createElement("span");
26827 s.className = "ytb-text";
26828 s.innerHTML = text;
26829 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
26831 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
26832 enable:Roo.emptyFn,
26833 disable:Roo.emptyFn,
26838 * @class Roo.Toolbar.Button
26839 * @extends Roo.Button
26840 * A button that renders into a toolbar.
26842 * Creates a new Button
26843 * @param {Object} config A standard {@link Roo.Button} config object
26845 Roo.Toolbar.Button = function(config){
26846 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
26848 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
26849 render : function(td){
26851 Roo.Toolbar.Button.superclass.render.call(this, td);
26855 * Removes and destroys this button
26857 destroy : function(){
26858 Roo.Toolbar.Button.superclass.destroy.call(this);
26859 this.td.parentNode.removeChild(this.td);
26863 * Shows this button
26866 this.hidden = false;
26867 this.td.style.display = "";
26871 * Hides this button
26874 this.hidden = true;
26875 this.td.style.display = "none";
26879 * Disables this item
26881 disable : function(){
26882 Roo.fly(this.td).addClass("x-item-disabled");
26883 this.disabled = true;
26887 * Enables this item
26889 enable : function(){
26890 Roo.fly(this.td).removeClass("x-item-disabled");
26891 this.disabled = false;
26894 // backwards compat
26895 Roo.ToolbarButton = Roo.Toolbar.Button;
26898 * @class Roo.Toolbar.SplitButton
26899 * @extends Roo.SplitButton
26900 * A menu button that renders into a toolbar.
26902 * Creates a new SplitButton
26903 * @param {Object} config A standard {@link Roo.SplitButton} config object
26905 Roo.Toolbar.SplitButton = function(config){
26906 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
26908 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
26909 render : function(td){
26911 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
26915 * Removes and destroys this button
26917 destroy : function(){
26918 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
26919 this.td.parentNode.removeChild(this.td);
26923 * Shows this button
26926 this.hidden = false;
26927 this.td.style.display = "";
26931 * Hides this button
26934 this.hidden = true;
26935 this.td.style.display = "none";
26939 // backwards compat
26940 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
26942 * Ext JS Library 1.1.1
26943 * Copyright(c) 2006-2007, Ext JS, LLC.
26945 * Originally Released Under LGPL - original licence link has changed is not relivant.
26948 * <script type="text/javascript">
26952 * @class Roo.PagingToolbar
26953 * @extends Roo.Toolbar
26954 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26956 * Create a new PagingToolbar
26957 * @param {Object} config The config object
26959 Roo.PagingToolbar = function(el, ds, config)
26961 // old args format still supported... - xtype is prefered..
26962 if (typeof(el) == 'object' && el.xtype) {
26963 // created from xtype...
26965 ds = el.dataSource;
26966 el = config.container;
26970 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
26973 this.renderButtons(this.el);
26977 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
26979 * @cfg {Roo.data.Store} dataSource
26980 * The underlying data store providing the paged data
26983 * @cfg {String/HTMLElement/Element} container
26984 * container The id or element that will contain the toolbar
26987 * @cfg {Boolean} displayInfo
26988 * True to display the displayMsg (defaults to false)
26991 * @cfg {Number} pageSize
26992 * The number of records to display per page (defaults to 20)
26996 * @cfg {String} displayMsg
26997 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26999 displayMsg : 'Displaying {0} - {1} of {2}',
27001 * @cfg {String} emptyMsg
27002 * The message to display when no records are found (defaults to "No data to display")
27004 emptyMsg : 'No data to display',
27006 * Customizable piece of the default paging text (defaults to "Page")
27009 beforePageText : "Page",
27011 * Customizable piece of the default paging text (defaults to "of %0")
27014 afterPageText : "of {0}",
27016 * Customizable piece of the default paging text (defaults to "First Page")
27019 firstText : "First Page",
27021 * Customizable piece of the default paging text (defaults to "Previous Page")
27024 prevText : "Previous Page",
27026 * Customizable piece of the default paging text (defaults to "Next Page")
27029 nextText : "Next Page",
27031 * Customizable piece of the default paging text (defaults to "Last Page")
27034 lastText : "Last Page",
27036 * Customizable piece of the default paging text (defaults to "Refresh")
27039 refreshText : "Refresh",
27042 renderButtons : function(el){
27043 Roo.PagingToolbar.superclass.render.call(this, el);
27044 this.first = this.addButton({
27045 tooltip: this.firstText,
27046 cls: "x-btn-icon x-grid-page-first",
27048 handler: this.onClick.createDelegate(this, ["first"])
27050 this.prev = this.addButton({
27051 tooltip: this.prevText,
27052 cls: "x-btn-icon x-grid-page-prev",
27054 handler: this.onClick.createDelegate(this, ["prev"])
27056 this.addSeparator();
27057 this.add(this.beforePageText);
27058 this.field = Roo.get(this.addDom({
27063 cls: "x-grid-page-number"
27065 this.field.on("keydown", this.onPagingKeydown, this);
27066 this.field.on("focus", function(){this.dom.select();});
27067 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27068 this.field.setHeight(18);
27069 this.addSeparator();
27070 this.next = this.addButton({
27071 tooltip: this.nextText,
27072 cls: "x-btn-icon x-grid-page-next",
27074 handler: this.onClick.createDelegate(this, ["next"])
27076 this.last = this.addButton({
27077 tooltip: this.lastText,
27078 cls: "x-btn-icon x-grid-page-last",
27080 handler: this.onClick.createDelegate(this, ["last"])
27082 this.addSeparator();
27083 this.loading = this.addButton({
27084 tooltip: this.refreshText,
27085 cls: "x-btn-icon x-grid-loading",
27086 handler: this.onClick.createDelegate(this, ["refresh"])
27089 if(this.displayInfo){
27090 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27095 updateInfo : function(){
27096 if(this.displayEl){
27097 var count = this.ds.getCount();
27098 var msg = count == 0 ?
27102 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27104 this.displayEl.update(msg);
27109 onLoad : function(ds, r, o){
27110 this.cursor = o.params ? o.params.start : 0;
27111 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27113 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27114 this.field.dom.value = ap;
27115 this.first.setDisabled(ap == 1);
27116 this.prev.setDisabled(ap == 1);
27117 this.next.setDisabled(ap == ps);
27118 this.last.setDisabled(ap == ps);
27119 this.loading.enable();
27124 getPageData : function(){
27125 var total = this.ds.getTotalCount();
27128 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27129 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27134 onLoadError : function(){
27135 this.loading.enable();
27139 onPagingKeydown : function(e){
27140 var k = e.getKey();
27141 var d = this.getPageData();
27143 var v = this.field.dom.value, pageNum;
27144 if(!v || isNaN(pageNum = parseInt(v, 10))){
27145 this.field.dom.value = d.activePage;
27148 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27149 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27152 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))
27154 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27155 this.field.dom.value = pageNum;
27156 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27159 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27161 var v = this.field.dom.value, pageNum;
27162 var increment = (e.shiftKey) ? 10 : 1;
27163 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27165 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27166 this.field.dom.value = d.activePage;
27169 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27171 this.field.dom.value = parseInt(v, 10) + increment;
27172 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27173 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27180 beforeLoad : function(){
27182 this.loading.disable();
27187 onClick : function(which){
27191 ds.load({params:{start: 0, limit: this.pageSize}});
27194 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27197 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27200 var total = ds.getTotalCount();
27201 var extra = total % this.pageSize;
27202 var lastStart = extra ? (total - extra) : total-this.pageSize;
27203 ds.load({params:{start: lastStart, limit: this.pageSize}});
27206 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27212 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27213 * @param {Roo.data.Store} store The data store to unbind
27215 unbind : function(ds){
27216 ds.un("beforeload", this.beforeLoad, this);
27217 ds.un("load", this.onLoad, this);
27218 ds.un("loadexception", this.onLoadError, this);
27219 ds.un("remove", this.updateInfo, this);
27220 ds.un("add", this.updateInfo, this);
27221 this.ds = undefined;
27225 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27226 * @param {Roo.data.Store} store The data store to bind
27228 bind : function(ds){
27229 ds.on("beforeload", this.beforeLoad, this);
27230 ds.on("load", this.onLoad, this);
27231 ds.on("loadexception", this.onLoadError, this);
27232 ds.on("remove", this.updateInfo, this);
27233 ds.on("add", this.updateInfo, this);
27238 * Ext JS Library 1.1.1
27239 * Copyright(c) 2006-2007, Ext JS, LLC.
27241 * Originally Released Under LGPL - original licence link has changed is not relivant.
27244 * <script type="text/javascript">
27248 * @class Roo.Resizable
27249 * @extends Roo.util.Observable
27250 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27251 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27252 * 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
27253 * the element will be wrapped for you automatically.</p>
27254 * <p>Here is the list of valid resize handles:</p>
27257 ------ -------------------
27268 * <p>Here's an example showing the creation of a typical Resizable:</p>
27270 var resizer = new Roo.Resizable("element-id", {
27278 resizer.on("resize", myHandler);
27280 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27281 * resizer.east.setDisplayed(false);</p>
27282 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27283 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27284 * resize operation's new size (defaults to [0, 0])
27285 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27286 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27287 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27288 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27289 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27290 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27291 * @cfg {Number} width The width of the element in pixels (defaults to null)
27292 * @cfg {Number} height The height of the element in pixels (defaults to null)
27293 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27294 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27295 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27296 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27297 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27298 * in favor of the handles config option (defaults to false)
27299 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27300 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27301 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27302 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27303 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27304 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27305 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27306 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27307 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27308 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27309 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27311 * Create a new resizable component
27312 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27313 * @param {Object} config configuration options
27315 Roo.Resizable = function(el, config){
27316 this.el = Roo.get(el);
27318 if(config && config.wrap){
27319 config.resizeChild = this.el;
27320 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27321 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27322 this.el.setStyle("overflow", "hidden");
27323 this.el.setPositioning(config.resizeChild.getPositioning());
27324 config.resizeChild.clearPositioning();
27325 if(!config.width || !config.height){
27326 var csize = config.resizeChild.getSize();
27327 this.el.setSize(csize.width, csize.height);
27329 if(config.pinned && !config.adjustments){
27330 config.adjustments = "auto";
27334 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27335 this.proxy.unselectable();
27336 this.proxy.enableDisplayMode('block');
27338 Roo.apply(this, config);
27341 this.disableTrackOver = true;
27342 this.el.addClass("x-resizable-pinned");
27344 // if the element isn't positioned, make it relative
27345 var position = this.el.getStyle("position");
27346 if(position != "absolute" && position != "fixed"){
27347 this.el.setStyle("position", "relative");
27349 if(!this.handles){ // no handles passed, must be legacy style
27350 this.handles = 's,e,se';
27351 if(this.multiDirectional){
27352 this.handles += ',n,w';
27355 if(this.handles == "all"){
27356 this.handles = "n s e w ne nw se sw";
27358 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27359 var ps = Roo.Resizable.positions;
27360 for(var i = 0, len = hs.length; i < len; i++){
27361 if(hs[i] && ps[hs[i]]){
27362 var pos = ps[hs[i]];
27363 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27367 this.corner = this.southeast;
27369 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1){
27370 this.updateBox = true;
27373 this.activeHandle = null;
27375 if(this.resizeChild){
27376 if(typeof this.resizeChild == "boolean"){
27377 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27379 this.resizeChild = Roo.get(this.resizeChild, true);
27383 if(this.adjustments == "auto"){
27384 var rc = this.resizeChild;
27385 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27386 if(rc && (hw || hn)){
27387 rc.position("relative");
27388 rc.setLeft(hw ? hw.el.getWidth() : 0);
27389 rc.setTop(hn ? hn.el.getHeight() : 0);
27391 this.adjustments = [
27392 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27393 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27397 if(this.draggable){
27398 this.dd = this.dynamic ?
27399 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27400 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27406 * @event beforeresize
27407 * Fired before resize is allowed. Set enabled to false to cancel resize.
27408 * @param {Roo.Resizable} this
27409 * @param {Roo.EventObject} e The mousedown event
27411 "beforeresize" : true,
27414 * Fired after a resize.
27415 * @param {Roo.Resizable} this
27416 * @param {Number} width The new width
27417 * @param {Number} height The new height
27418 * @param {Roo.EventObject} e The mouseup event
27423 if(this.width !== null && this.height !== null){
27424 this.resizeTo(this.width, this.height);
27426 this.updateChildSize();
27429 this.el.dom.style.zoom = 1;
27431 Roo.Resizable.superclass.constructor.call(this);
27434 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27435 resizeChild : false,
27436 adjustments : [0, 0],
27446 multiDirectional : false,
27447 disableTrackOver : false,
27448 easing : 'easeOutStrong',
27449 widthIncrement : 0,
27450 heightIncrement : 0,
27454 preserveRatio : false,
27455 transparent: false,
27461 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27463 constrainTo: undefined,
27465 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27467 resizeRegion: undefined,
27471 * Perform a manual resize
27472 * @param {Number} width
27473 * @param {Number} height
27475 resizeTo : function(width, height){
27476 this.el.setSize(width, height);
27477 this.updateChildSize();
27478 this.fireEvent("resize", this, width, height, null);
27482 startSizing : function(e, handle){
27483 this.fireEvent("beforeresize", this, e);
27484 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27487 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27488 this.overlay.unselectable();
27489 this.overlay.enableDisplayMode("block");
27490 this.overlay.on("mousemove", this.onMouseMove, this);
27491 this.overlay.on("mouseup", this.onMouseUp, this);
27493 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27495 this.resizing = true;
27496 this.startBox = this.el.getBox();
27497 this.startPoint = e.getXY();
27498 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27499 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27501 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27502 this.overlay.show();
27504 if(this.constrainTo) {
27505 var ct = Roo.get(this.constrainTo);
27506 this.resizeRegion = ct.getRegion().adjust(
27507 ct.getFrameWidth('t'),
27508 ct.getFrameWidth('l'),
27509 -ct.getFrameWidth('b'),
27510 -ct.getFrameWidth('r')
27514 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27516 this.proxy.setBox(this.startBox);
27518 this.proxy.setStyle('visibility', 'visible');
27524 onMouseDown : function(handle, e){
27527 this.activeHandle = handle;
27528 this.startSizing(e, handle);
27533 onMouseUp : function(e){
27534 var size = this.resizeElement();
27535 this.resizing = false;
27537 this.overlay.hide();
27539 this.fireEvent("resize", this, size.width, size.height, e);
27543 updateChildSize : function(){
27544 if(this.resizeChild){
27546 var child = this.resizeChild;
27547 var adj = this.adjustments;
27548 if(el.dom.offsetWidth){
27549 var b = el.getSize(true);
27550 child.setSize(b.width+adj[0], b.height+adj[1]);
27552 // Second call here for IE
27553 // The first call enables instant resizing and
27554 // the second call corrects scroll bars if they
27557 setTimeout(function(){
27558 if(el.dom.offsetWidth){
27559 var b = el.getSize(true);
27560 child.setSize(b.width+adj[0], b.height+adj[1]);
27568 snap : function(value, inc, min){
27569 if(!inc || !value) return value;
27570 var newValue = value;
27571 var m = value % inc;
27574 newValue = value + (inc-m);
27576 newValue = value - m;
27579 return Math.max(min, newValue);
27583 resizeElement : function(){
27584 var box = this.proxy.getBox();
27585 if(this.updateBox){
27586 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27588 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27590 this.updateChildSize();
27598 constrain : function(v, diff, m, mx){
27601 }else if(v - diff > mx){
27608 onMouseMove : function(e){
27610 try{// try catch so if something goes wrong the user doesn't get hung
27612 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27616 //var curXY = this.startPoint;
27617 var curSize = this.curSize || this.startBox;
27618 var x = this.startBox.x, y = this.startBox.y;
27619 var ox = x, oy = y;
27620 var w = curSize.width, h = curSize.height;
27621 var ow = w, oh = h;
27622 var mw = this.minWidth, mh = this.minHeight;
27623 var mxw = this.maxWidth, mxh = this.maxHeight;
27624 var wi = this.widthIncrement;
27625 var hi = this.heightIncrement;
27627 var eventXY = e.getXY();
27628 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27629 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27631 var pos = this.activeHandle.position;
27636 w = Math.min(Math.max(mw, w), mxw);
27640 h = Math.min(Math.max(mh, h), mxh);
27645 w = Math.min(Math.max(mw, w), mxw);
27646 h = Math.min(Math.max(mh, h), mxh);
27649 diffY = this.constrain(h, diffY, mh, mxh);
27654 diffX = this.constrain(w, diffX, mw, mxw);
27660 w = Math.min(Math.max(mw, w), mxw);
27661 diffY = this.constrain(h, diffY, mh, mxh);
27666 diffX = this.constrain(w, diffX, mw, mxw);
27667 diffY = this.constrain(h, diffY, mh, mxh);
27674 diffX = this.constrain(w, diffX, mw, mxw);
27676 h = Math.min(Math.max(mh, h), mxh);
27682 var sw = this.snap(w, wi, mw);
27683 var sh = this.snap(h, hi, mh);
27684 if(sw != w || sh != h){
27707 if(this.preserveRatio){
27712 h = Math.min(Math.max(mh, h), mxh);
27717 w = Math.min(Math.max(mw, w), mxw);
27722 w = Math.min(Math.max(mw, w), mxw);
27728 w = Math.min(Math.max(mw, w), mxw);
27734 h = Math.min(Math.max(mh, h), mxh);
27742 h = Math.min(Math.max(mh, h), mxh);
27752 h = Math.min(Math.max(mh, h), mxh);
27760 this.proxy.setBounds(x, y, w, h);
27762 this.resizeElement();
27769 handleOver : function(){
27771 this.el.addClass("x-resizable-over");
27776 handleOut : function(){
27777 if(!this.resizing){
27778 this.el.removeClass("x-resizable-over");
27783 * Returns the element this component is bound to.
27784 * @return {Roo.Element}
27786 getEl : function(){
27791 * Returns the resizeChild element (or null).
27792 * @return {Roo.Element}
27794 getResizeChild : function(){
27795 return this.resizeChild;
27799 * Destroys this resizable. If the element was wrapped and
27800 * removeEl is not true then the element remains.
27801 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
27803 destroy : function(removeEl){
27804 this.proxy.remove();
27806 this.overlay.removeAllListeners();
27807 this.overlay.remove();
27809 var ps = Roo.Resizable.positions;
27811 if(typeof ps[k] != "function" && this[ps[k]]){
27812 var h = this[ps[k]];
27813 h.el.removeAllListeners();
27818 this.el.update("");
27825 // hash to map config positions to true positions
27826 Roo.Resizable.positions = {
27827 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast"
27831 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
27833 // only initialize the template if resizable is used
27834 var tpl = Roo.DomHelper.createTemplate(
27835 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
27838 Roo.Resizable.Handle.prototype.tpl = tpl;
27840 this.position = pos;
27842 this.el = this.tpl.append(rz.el.dom, [this.position], true);
27843 this.el.unselectable();
27845 this.el.setOpacity(0);
27847 this.el.on("mousedown", this.onMouseDown, this);
27848 if(!disableTrackOver){
27849 this.el.on("mouseover", this.onMouseOver, this);
27850 this.el.on("mouseout", this.onMouseOut, this);
27855 Roo.Resizable.Handle.prototype = {
27856 afterResize : function(rz){
27860 onMouseDown : function(e){
27861 this.rz.onMouseDown(this, e);
27864 onMouseOver : function(e){
27865 this.rz.handleOver(this, e);
27868 onMouseOut : function(e){
27869 this.rz.handleOut(this, e);
27873 * Ext JS Library 1.1.1
27874 * Copyright(c) 2006-2007, Ext JS, LLC.
27876 * Originally Released Under LGPL - original licence link has changed is not relivant.
27879 * <script type="text/javascript">
27883 * @class Roo.Editor
27884 * @extends Roo.Component
27885 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
27887 * Create a new Editor
27888 * @param {Roo.form.Field} field The Field object (or descendant)
27889 * @param {Object} config The config object
27891 Roo.Editor = function(field, config){
27892 Roo.Editor.superclass.constructor.call(this, config);
27893 this.field = field;
27896 * @event beforestartedit
27897 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
27898 * false from the handler of this event.
27899 * @param {Editor} this
27900 * @param {Roo.Element} boundEl The underlying element bound to this editor
27901 * @param {Mixed} value The field value being set
27903 "beforestartedit" : true,
27906 * Fires when this editor is displayed
27907 * @param {Roo.Element} boundEl The underlying element bound to this editor
27908 * @param {Mixed} value The starting field value
27910 "startedit" : true,
27912 * @event beforecomplete
27913 * Fires after a change has been made to the field, but before the change is reflected in the underlying
27914 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
27915 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
27916 * event will not fire since no edit actually occurred.
27917 * @param {Editor} this
27918 * @param {Mixed} value The current field value
27919 * @param {Mixed} startValue The original field value
27921 "beforecomplete" : true,
27924 * Fires after editing is complete and any changed value has been written to the underlying field.
27925 * @param {Editor} this
27926 * @param {Mixed} value The current field value
27927 * @param {Mixed} startValue The original field value
27931 * @event specialkey
27932 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
27933 * {@link Roo.EventObject#getKey} to determine which key was pressed.
27934 * @param {Roo.form.Field} this
27935 * @param {Roo.EventObject} e The event object
27937 "specialkey" : true
27941 Roo.extend(Roo.Editor, Roo.Component, {
27943 * @cfg {Boolean/String} autosize
27944 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
27945 * or "height" to adopt the height only (defaults to false)
27948 * @cfg {Boolean} revertInvalid
27949 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
27950 * validation fails (defaults to true)
27953 * @cfg {Boolean} ignoreNoChange
27954 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
27955 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
27956 * will never be ignored.
27959 * @cfg {Boolean} hideEl
27960 * False to keep the bound element visible while the editor is displayed (defaults to true)
27963 * @cfg {Mixed} value
27964 * The data value of the underlying field (defaults to "")
27968 * @cfg {String} alignment
27969 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
27973 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
27974 * for bottom-right shadow (defaults to "frame")
27978 * @cfg {Boolean} constrain True to constrain the editor to the viewport
27982 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
27984 completeOnEnter : false,
27986 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
27988 cancelOnEsc : false,
27990 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
27995 onRender : function(ct, position){
27996 this.el = new Roo.Layer({
27997 shadow: this.shadow,
28003 constrain: this.constrain
28005 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28006 if(this.field.msgTarget != 'title'){
28007 this.field.msgTarget = 'qtip';
28009 this.field.render(this.el);
28011 this.field.el.dom.setAttribute('autocomplete', 'off');
28013 this.field.on("specialkey", this.onSpecialKey, this);
28014 if(this.swallowKeys){
28015 this.field.el.swallowEvent(['keydown','keypress']);
28018 this.field.on("blur", this.onBlur, this);
28019 if(this.field.grow){
28020 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28024 onSpecialKey : function(field, e){
28025 if(this.completeOnEnter && e.getKey() == e.ENTER){
28027 this.completeEdit();
28028 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
28031 this.fireEvent('specialkey', field, e);
28036 * Starts the editing process and shows the editor.
28037 * @param {String/HTMLElement/Element} el The element to edit
28038 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28039 * to the innerHTML of el.
28041 startEdit : function(el, value){
28043 this.completeEdit();
28045 this.boundEl = Roo.get(el);
28046 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28047 if(!this.rendered){
28048 this.render(this.parentEl || document.body);
28050 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28053 this.startValue = v;
28054 this.field.setValue(v);
28056 var sz = this.boundEl.getSize();
28057 switch(this.autoSize){
28059 this.setSize(sz.width, "");
28062 this.setSize("", sz.height);
28065 this.setSize(sz.width, sz.height);
28068 this.el.alignTo(this.boundEl, this.alignment);
28069 this.editing = true;
28071 Roo.QuickTips.disable();
28077 * Sets the height and width of this editor.
28078 * @param {Number} width The new width
28079 * @param {Number} height The new height
28081 setSize : function(w, h){
28082 this.field.setSize(w, h);
28089 * Realigns the editor to the bound field based on the current alignment config value.
28091 realign : function(){
28092 this.el.alignTo(this.boundEl, this.alignment);
28096 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28097 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28099 completeEdit : function(remainVisible){
28103 var v = this.getValue();
28104 if(this.revertInvalid !== false && !this.field.isValid()){
28105 v = this.startValue;
28106 this.cancelEdit(true);
28108 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28109 this.editing = false;
28113 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28114 this.editing = false;
28115 if(this.updateEl && this.boundEl){
28116 this.boundEl.update(v);
28118 if(remainVisible !== true){
28121 this.fireEvent("complete", this, v, this.startValue);
28126 onShow : function(){
28128 if(this.hideEl !== false){
28129 this.boundEl.hide();
28132 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28133 this.fixIEFocus = true;
28134 this.deferredFocus.defer(50, this);
28136 this.field.focus();
28138 this.fireEvent("startedit", this.boundEl, this.startValue);
28141 deferredFocus : function(){
28143 this.field.focus();
28148 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28149 * reverted to the original starting value.
28150 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28151 * cancel (defaults to false)
28153 cancelEdit : function(remainVisible){
28155 this.setValue(this.startValue);
28156 if(remainVisible !== true){
28163 onBlur : function(){
28164 if(this.allowBlur !== true && this.editing){
28165 this.completeEdit();
28170 onHide : function(){
28172 this.completeEdit();
28176 if(this.field.collapse){
28177 this.field.collapse();
28180 if(this.hideEl !== false){
28181 this.boundEl.show();
28184 Roo.QuickTips.enable();
28189 * Sets the data value of the editor
28190 * @param {Mixed} value Any valid value supported by the underlying field
28192 setValue : function(v){
28193 this.field.setValue(v);
28197 * Gets the data value of the editor
28198 * @return {Mixed} The data value
28200 getValue : function(){
28201 return this.field.getValue();
28205 * Ext JS Library 1.1.1
28206 * Copyright(c) 2006-2007, Ext JS, LLC.
28208 * Originally Released Under LGPL - original licence link has changed is not relivant.
28211 * <script type="text/javascript">
28215 * @class Roo.BasicDialog
28216 * @extends Roo.util.Observable
28217 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28219 var dlg = new Roo.BasicDialog("my-dlg", {
28228 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28229 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28230 dlg.addButton('Cancel', dlg.hide, dlg);
28233 <b>A Dialog should always be a direct child of the body element.</b>
28234 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28235 * @cfg {String} title Default text to display in the title bar (defaults to null)
28236 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28237 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28238 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28239 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28240 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28241 * (defaults to null with no animation)
28242 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28243 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28244 * property for valid values (defaults to 'all')
28245 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28246 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28247 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28248 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28249 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28250 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28251 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28252 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28253 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28254 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28255 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28256 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28257 * draggable = true (defaults to false)
28258 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28259 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28260 * shadow (defaults to false)
28261 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28262 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28263 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28264 * @cfg {Array} buttons Array of buttons
28265 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28267 * Create a new BasicDialog.
28268 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28269 * @param {Object} config Configuration options
28271 Roo.BasicDialog = function(el, config){
28272 this.el = Roo.get(el);
28273 var dh = Roo.DomHelper;
28274 if(!this.el && config && config.autoCreate){
28275 if(typeof config.autoCreate == "object"){
28276 if(!config.autoCreate.id){
28277 config.autoCreate.id = el;
28279 this.el = dh.append(document.body,
28280 config.autoCreate, true);
28282 this.el = dh.append(document.body,
28283 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28287 el.setDisplayed(true);
28288 el.hide = this.hideAction;
28290 el.addClass("x-dlg");
28292 Roo.apply(this, config);
28294 this.proxy = el.createProxy("x-dlg-proxy");
28295 this.proxy.hide = this.hideAction;
28296 this.proxy.setOpacity(.5);
28300 el.setWidth(config.width);
28303 el.setHeight(config.height);
28305 this.size = el.getSize();
28306 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28307 this.xy = [config.x,config.y];
28309 this.xy = el.getCenterXY(true);
28311 /** The header element @type Roo.Element */
28312 this.header = el.child("> .x-dlg-hd");
28313 /** The body element @type Roo.Element */
28314 this.body = el.child("> .x-dlg-bd");
28315 /** The footer element @type Roo.Element */
28316 this.footer = el.child("> .x-dlg-ft");
28319 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28322 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28325 this.header.unselectable();
28327 this.header.update(this.title);
28329 // this element allows the dialog to be focused for keyboard event
28330 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28331 this.focusEl.swallowEvent("click", true);
28333 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28335 // wrap the body and footer for special rendering
28336 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28338 this.bwrap.dom.appendChild(this.footer.dom);
28341 this.bg = this.el.createChild({
28342 tag: "div", cls:"x-dlg-bg",
28343 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28345 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28348 if(this.autoScroll !== false && !this.autoTabs){
28349 this.body.setStyle("overflow", "auto");
28352 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28354 if(this.closable !== false){
28355 this.el.addClass("x-dlg-closable");
28356 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28357 this.close.on("click", this.closeClick, this);
28358 this.close.addClassOnOver("x-dlg-close-over");
28360 if(this.collapsible !== false){
28361 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28362 this.collapseBtn.on("click", this.collapseClick, this);
28363 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28364 this.header.on("dblclick", this.collapseClick, this);
28366 if(this.resizable !== false){
28367 this.el.addClass("x-dlg-resizable");
28368 this.resizer = new Roo.Resizable(el, {
28369 minWidth: this.minWidth || 80,
28370 minHeight:this.minHeight || 80,
28371 handles: this.resizeHandles || "all",
28374 this.resizer.on("beforeresize", this.beforeResize, this);
28375 this.resizer.on("resize", this.onResize, this);
28377 if(this.draggable !== false){
28378 el.addClass("x-dlg-draggable");
28379 if (!this.proxyDrag) {
28380 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28383 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28385 dd.setHandleElId(this.header.id);
28386 dd.endDrag = this.endMove.createDelegate(this);
28387 dd.startDrag = this.startMove.createDelegate(this);
28388 dd.onDrag = this.onDrag.createDelegate(this);
28393 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28394 this.mask.enableDisplayMode("block");
28396 this.el.addClass("x-dlg-modal");
28399 this.shadow = new Roo.Shadow({
28400 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28401 offset : this.shadowOffset
28404 this.shadowOffset = 0;
28406 if(Roo.useShims && this.shim !== false){
28407 this.shim = this.el.createShim();
28408 this.shim.hide = this.hideAction;
28416 if (this.buttons) {
28417 var bts= this.buttons;
28419 Roo.each(bts, function(b) {
28428 * Fires when a key is pressed
28429 * @param {Roo.BasicDialog} this
28430 * @param {Roo.EventObject} e
28435 * Fires when this dialog is moved by the user.
28436 * @param {Roo.BasicDialog} this
28437 * @param {Number} x The new page X
28438 * @param {Number} y The new page Y
28443 * Fires when this dialog is resized by the user.
28444 * @param {Roo.BasicDialog} this
28445 * @param {Number} width The new width
28446 * @param {Number} height The new height
28450 * @event beforehide
28451 * Fires before this dialog is hidden.
28452 * @param {Roo.BasicDialog} this
28454 "beforehide" : true,
28457 * Fires when this dialog is hidden.
28458 * @param {Roo.BasicDialog} this
28462 * @event beforeshow
28463 * Fires before this dialog is shown.
28464 * @param {Roo.BasicDialog} this
28466 "beforeshow" : true,
28469 * Fires when this dialog is shown.
28470 * @param {Roo.BasicDialog} this
28474 el.on("keydown", this.onKeyDown, this);
28475 el.on("mousedown", this.toFront, this);
28476 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28478 Roo.DialogManager.register(this);
28479 Roo.BasicDialog.superclass.constructor.call(this);
28482 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28483 shadowOffset: Roo.isIE ? 6 : 5,
28486 minButtonWidth: 75,
28487 defaultButton: null,
28488 buttonAlign: "right",
28493 * Sets the dialog title text
28494 * @param {String} text The title text to display
28495 * @return {Roo.BasicDialog} this
28497 setTitle : function(text){
28498 this.header.update(text);
28503 closeClick : function(){
28508 collapseClick : function(){
28509 this[this.collapsed ? "expand" : "collapse"]();
28513 * Collapses the dialog to its minimized state (only the title bar is visible).
28514 * Equivalent to the user clicking the collapse dialog button.
28516 collapse : function(){
28517 if(!this.collapsed){
28518 this.collapsed = true;
28519 this.el.addClass("x-dlg-collapsed");
28520 this.restoreHeight = this.el.getHeight();
28521 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28526 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28527 * clicking the expand dialog button.
28529 expand : function(){
28530 if(this.collapsed){
28531 this.collapsed = false;
28532 this.el.removeClass("x-dlg-collapsed");
28533 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28538 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28539 * @return {Roo.TabPanel} The tabs component
28541 initTabs : function(){
28542 var tabs = this.getTabs();
28543 while(tabs.getTab(0)){
28546 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28548 tabs.addTab(Roo.id(dom), dom.title);
28556 beforeResize : function(){
28557 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28561 onResize : function(){
28562 this.refreshSize();
28563 this.syncBodyHeight();
28564 this.adjustAssets();
28566 this.fireEvent("resize", this, this.size.width, this.size.height);
28570 onKeyDown : function(e){
28571 if(this.isVisible()){
28572 this.fireEvent("keydown", this, e);
28577 * Resizes the dialog.
28578 * @param {Number} width
28579 * @param {Number} height
28580 * @return {Roo.BasicDialog} this
28582 resizeTo : function(width, height){
28583 this.el.setSize(width, height);
28584 this.size = {width: width, height: height};
28585 this.syncBodyHeight();
28586 if(this.fixedcenter){
28589 if(this.isVisible()){
28590 this.constrainXY();
28591 this.adjustAssets();
28593 this.fireEvent("resize", this, width, height);
28599 * Resizes the dialog to fit the specified content size.
28600 * @param {Number} width
28601 * @param {Number} height
28602 * @return {Roo.BasicDialog} this
28604 setContentSize : function(w, h){
28605 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28606 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28607 //if(!this.el.isBorderBox()){
28608 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28609 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28612 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28613 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28615 this.resizeTo(w, h);
28620 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28621 * executed in response to a particular key being pressed while the dialog is active.
28622 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28623 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28624 * @param {Function} fn The function to call
28625 * @param {Object} scope (optional) The scope of the function
28626 * @return {Roo.BasicDialog} this
28628 addKeyListener : function(key, fn, scope){
28629 var keyCode, shift, ctrl, alt;
28630 if(typeof key == "object" && !(key instanceof Array)){
28631 keyCode = key["key"];
28632 shift = key["shift"];
28633 ctrl = key["ctrl"];
28638 var handler = function(dlg, e){
28639 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28640 var k = e.getKey();
28641 if(keyCode instanceof Array){
28642 for(var i = 0, len = keyCode.length; i < len; i++){
28643 if(keyCode[i] == k){
28644 fn.call(scope || window, dlg, k, e);
28650 fn.call(scope || window, dlg, k, e);
28655 this.on("keydown", handler);
28660 * Returns the TabPanel component (creates it if it doesn't exist).
28661 * Note: If you wish to simply check for the existence of tabs without creating them,
28662 * check for a null 'tabs' property.
28663 * @return {Roo.TabPanel} The tabs component
28665 getTabs : function(){
28667 this.el.addClass("x-dlg-auto-tabs");
28668 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28669 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28675 * Adds a button to the footer section of the dialog.
28676 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28677 * object or a valid Roo.DomHelper element config
28678 * @param {Function} handler The function called when the button is clicked
28679 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28680 * @return {Roo.Button} The new button
28682 addButton : function(config, handler, scope){
28683 var dh = Roo.DomHelper;
28685 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28687 if(!this.btnContainer){
28688 var tb = this.footer.createChild({
28690 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28691 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28693 this.btnContainer = tb.firstChild.firstChild.firstChild;
28698 minWidth: this.minButtonWidth,
28701 if(typeof config == "string"){
28702 bconfig.text = config;
28705 bconfig.dhconfig = config;
28707 Roo.apply(bconfig, config);
28711 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
28712 bconfig.position = Math.max(0, bconfig.position);
28713 fc = this.btnContainer.childNodes[bconfig.position];
28716 var btn = new Roo.Button(
28718 this.btnContainer.insertBefore(document.createElement("td"),fc)
28719 : this.btnContainer.appendChild(document.createElement("td")),
28720 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
28723 this.syncBodyHeight();
28726 * Array of all the buttons that have been added to this dialog via addButton
28731 this.buttons.push(btn);
28736 * Sets the default button to be focused when the dialog is displayed.
28737 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
28738 * @return {Roo.BasicDialog} this
28740 setDefaultButton : function(btn){
28741 this.defaultButton = btn;
28746 getHeaderFooterHeight : function(safe){
28749 height += this.header.getHeight();
28752 var fm = this.footer.getMargins();
28753 height += (this.footer.getHeight()+fm.top+fm.bottom);
28755 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
28756 height += this.centerBg.getPadding("tb");
28761 syncBodyHeight : function(){
28762 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
28763 var height = this.size.height - this.getHeaderFooterHeight(false);
28764 bd.setHeight(height-bd.getMargins("tb"));
28765 var hh = this.header.getHeight();
28766 var h = this.size.height-hh;
28768 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
28769 bw.setHeight(h-cb.getPadding("tb"));
28770 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
28771 bd.setWidth(bw.getWidth(true));
28773 this.tabs.syncHeight();
28775 this.tabs.el.repaint();
28781 * Restores the previous state of the dialog if Roo.state is configured.
28782 * @return {Roo.BasicDialog} this
28784 restoreState : function(){
28785 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
28786 if(box && box.width){
28787 this.xy = [box.x, box.y];
28788 this.resizeTo(box.width, box.height);
28794 beforeShow : function(){
28796 if(this.fixedcenter){
28797 this.xy = this.el.getCenterXY(true);
28800 Roo.get(document.body).addClass("x-body-masked");
28801 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28804 this.constrainXY();
28808 animShow : function(){
28809 var b = Roo.get(this.animateTarget, true).getBox();
28810 this.proxy.setSize(b.width, b.height);
28811 this.proxy.setLocation(b.x, b.y);
28813 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
28814 true, .35, this.showEl.createDelegate(this));
28818 * Shows the dialog.
28819 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
28820 * @return {Roo.BasicDialog} this
28822 show : function(animateTarget){
28823 if (this.fireEvent("beforeshow", this) === false){
28826 if(this.syncHeightBeforeShow){
28827 this.syncBodyHeight();
28828 }else if(this.firstShow){
28829 this.firstShow = false;
28830 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
28832 this.animateTarget = animateTarget || this.animateTarget;
28833 if(!this.el.isVisible()){
28835 if(this.animateTarget){
28845 showEl : function(){
28847 this.el.setXY(this.xy);
28849 this.adjustAssets(true);
28852 // IE peekaboo bug - fix found by Dave Fenwick
28856 this.fireEvent("show", this);
28860 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
28861 * dialog itself will receive focus.
28863 focus : function(){
28864 if(this.defaultButton){
28865 this.defaultButton.focus();
28867 this.focusEl.focus();
28872 constrainXY : function(){
28873 if(this.constraintoviewport !== false){
28874 if(!this.viewSize){
28875 if(this.container){
28876 var s = this.container.getSize();
28877 this.viewSize = [s.width, s.height];
28879 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
28882 var s = Roo.get(this.container||document).getScroll();
28884 var x = this.xy[0], y = this.xy[1];
28885 var w = this.size.width, h = this.size.height;
28886 var vw = this.viewSize[0], vh = this.viewSize[1];
28887 // only move it if it needs it
28889 // first validate right/bottom
28890 if(x + w > vw+s.left){
28894 if(y + h > vh+s.top){
28898 // then make sure top/left isn't negative
28910 if(this.isVisible()){
28911 this.el.setLocation(x, y);
28912 this.adjustAssets();
28919 onDrag : function(){
28920 if(!this.proxyDrag){
28921 this.xy = this.el.getXY();
28922 this.adjustAssets();
28927 adjustAssets : function(doShow){
28928 var x = this.xy[0], y = this.xy[1];
28929 var w = this.size.width, h = this.size.height;
28930 if(doShow === true){
28932 this.shadow.show(this.el);
28938 if(this.shadow && this.shadow.isVisible()){
28939 this.shadow.show(this.el);
28941 if(this.shim && this.shim.isVisible()){
28942 this.shim.setBounds(x, y, w, h);
28947 adjustViewport : function(w, h){
28949 w = Roo.lib.Dom.getViewWidth();
28950 h = Roo.lib.Dom.getViewHeight();
28953 this.viewSize = [w, h];
28954 if(this.modal && this.mask.isVisible()){
28955 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
28956 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28958 if(this.isVisible()){
28959 this.constrainXY();
28964 * Destroys this dialog and all its supporting elements (including any tabs, shim,
28965 * shadow, proxy, mask, etc.) Also removes all event listeners.
28966 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28968 destroy : function(removeEl){
28969 if(this.isVisible()){
28970 this.animateTarget = null;
28973 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
28975 this.tabs.destroy(removeEl);
28988 for(var i = 0, len = this.buttons.length; i < len; i++){
28989 this.buttons[i].destroy();
28992 this.el.removeAllListeners();
28993 if(removeEl === true){
28994 this.el.update("");
28997 Roo.DialogManager.unregister(this);
29001 startMove : function(){
29002 if(this.proxyDrag){
29005 if(this.constraintoviewport !== false){
29006 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29011 endMove : function(){
29012 if(!this.proxyDrag){
29013 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29015 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29018 this.refreshSize();
29019 this.adjustAssets();
29021 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29025 * Brings this dialog to the front of any other visible dialogs
29026 * @return {Roo.BasicDialog} this
29028 toFront : function(){
29029 Roo.DialogManager.bringToFront(this);
29034 * Sends this dialog to the back (under) of any other visible dialogs
29035 * @return {Roo.BasicDialog} this
29037 toBack : function(){
29038 Roo.DialogManager.sendToBack(this);
29043 * Centers this dialog in the viewport
29044 * @return {Roo.BasicDialog} this
29046 center : function(){
29047 var xy = this.el.getCenterXY(true);
29048 this.moveTo(xy[0], xy[1]);
29053 * Moves the dialog's top-left corner to the specified point
29054 * @param {Number} x
29055 * @param {Number} y
29056 * @return {Roo.BasicDialog} this
29058 moveTo : function(x, y){
29060 if(this.isVisible()){
29061 this.el.setXY(this.xy);
29062 this.adjustAssets();
29068 * Aligns the dialog to the specified element
29069 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29070 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29071 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29072 * @return {Roo.BasicDialog} this
29074 alignTo : function(element, position, offsets){
29075 this.xy = this.el.getAlignToXY(element, position, offsets);
29076 if(this.isVisible()){
29077 this.el.setXY(this.xy);
29078 this.adjustAssets();
29084 * Anchors an element to another element and realigns it when the window is resized.
29085 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29086 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29087 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29088 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29089 * is a number, it is used as the buffer delay (defaults to 50ms).
29090 * @return {Roo.BasicDialog} this
29092 anchorTo : function(el, alignment, offsets, monitorScroll){
29093 var action = function(){
29094 this.alignTo(el, alignment, offsets);
29096 Roo.EventManager.onWindowResize(action, this);
29097 var tm = typeof monitorScroll;
29098 if(tm != 'undefined'){
29099 Roo.EventManager.on(window, 'scroll', action, this,
29100 {buffer: tm == 'number' ? monitorScroll : 50});
29107 * Returns true if the dialog is visible
29108 * @return {Boolean}
29110 isVisible : function(){
29111 return this.el.isVisible();
29115 animHide : function(callback){
29116 var b = Roo.get(this.animateTarget).getBox();
29118 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29120 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29121 this.hideEl.createDelegate(this, [callback]));
29125 * Hides the dialog.
29126 * @param {Function} callback (optional) Function to call when the dialog is hidden
29127 * @return {Roo.BasicDialog} this
29129 hide : function(callback){
29130 if (this.fireEvent("beforehide", this) === false){
29134 this.shadow.hide();
29139 if(this.animateTarget){
29140 this.animHide(callback);
29143 this.hideEl(callback);
29149 hideEl : function(callback){
29153 Roo.get(document.body).removeClass("x-body-masked");
29155 this.fireEvent("hide", this);
29156 if(typeof callback == "function"){
29162 hideAction : function(){
29163 this.setLeft("-10000px");
29164 this.setTop("-10000px");
29165 this.setStyle("visibility", "hidden");
29169 refreshSize : function(){
29170 this.size = this.el.getSize();
29171 this.xy = this.el.getXY();
29172 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29176 // z-index is managed by the DialogManager and may be overwritten at any time
29177 setZIndex : function(index){
29179 this.mask.setStyle("z-index", index);
29182 this.shim.setStyle("z-index", ++index);
29185 this.shadow.setZIndex(++index);
29187 this.el.setStyle("z-index", ++index);
29189 this.proxy.setStyle("z-index", ++index);
29192 this.resizer.proxy.setStyle("z-index", ++index);
29195 this.lastZIndex = index;
29199 * Returns the element for this dialog
29200 * @return {Roo.Element} The underlying dialog Element
29202 getEl : function(){
29208 * @class Roo.DialogManager
29209 * Provides global access to BasicDialogs that have been created and
29210 * support for z-indexing (layering) multiple open dialogs.
29212 Roo.DialogManager = function(){
29214 var accessList = [];
29218 var sortDialogs = function(d1, d2){
29219 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29223 var orderDialogs = function(){
29224 accessList.sort(sortDialogs);
29225 var seed = Roo.DialogManager.zseed;
29226 for(var i = 0, len = accessList.length; i < len; i++){
29227 var dlg = accessList[i];
29229 dlg.setZIndex(seed + (i*10));
29236 * The starting z-index for BasicDialogs (defaults to 9000)
29237 * @type Number The z-index value
29242 register : function(dlg){
29243 list[dlg.id] = dlg;
29244 accessList.push(dlg);
29248 unregister : function(dlg){
29249 delete list[dlg.id];
29252 if(!accessList.indexOf){
29253 for( i = 0, len = accessList.length; i < len; i++){
29254 if(accessList[i] == dlg){
29255 accessList.splice(i, 1);
29260 i = accessList.indexOf(dlg);
29262 accessList.splice(i, 1);
29268 * Gets a registered dialog by id
29269 * @param {String/Object} id The id of the dialog or a dialog
29270 * @return {Roo.BasicDialog} this
29272 get : function(id){
29273 return typeof id == "object" ? id : list[id];
29277 * Brings the specified dialog to the front
29278 * @param {String/Object} dlg The id of the dialog or a dialog
29279 * @return {Roo.BasicDialog} this
29281 bringToFront : function(dlg){
29282 dlg = this.get(dlg);
29285 dlg._lastAccess = new Date().getTime();
29292 * Sends the specified dialog to the back
29293 * @param {String/Object} dlg The id of the dialog or a dialog
29294 * @return {Roo.BasicDialog} this
29296 sendToBack : function(dlg){
29297 dlg = this.get(dlg);
29298 dlg._lastAccess = -(new Date().getTime());
29304 * Hides all dialogs
29306 hideAll : function(){
29307 for(var id in list){
29308 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29317 * @class Roo.LayoutDialog
29318 * @extends Roo.BasicDialog
29319 * Dialog which provides adjustments for working with a layout in a Dialog.
29320 * Add your necessary layout config options to the dialog's config.<br>
29321 * Example usage (including a nested layout):
29324 dialog = new Roo.LayoutDialog("download-dlg", {
29333 // layout config merges with the dialog config
29335 tabPosition: "top",
29336 alwaysShowTabs: true
29339 dialog.addKeyListener(27, dialog.hide, dialog);
29340 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29341 dialog.addButton("Build It!", this.getDownload, this);
29343 // we can even add nested layouts
29344 var innerLayout = new Roo.BorderLayout("dl-inner", {
29354 innerLayout.beginUpdate();
29355 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29356 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29357 innerLayout.endUpdate(true);
29359 var layout = dialog.getLayout();
29360 layout.beginUpdate();
29361 layout.add("center", new Roo.ContentPanel("standard-panel",
29362 {title: "Download the Source", fitToFrame:true}));
29363 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29364 {title: "Build your own roo.js"}));
29365 layout.getRegion("center").showPanel(sp);
29366 layout.endUpdate();
29370 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29371 * @param {Object} config configuration options
29373 Roo.LayoutDialog = function(el, cfg){
29376 if (typeof(cfg) == 'undefined') {
29377 config = Roo.apply({}, el);
29378 el = Roo.get( document.documentElement || document.body).createChild();
29379 //config.autoCreate = true;
29383 config.autoTabs = false;
29384 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29385 this.body.setStyle({overflow:"hidden", position:"relative"});
29386 this.layout = new Roo.BorderLayout(this.body.dom, config);
29387 this.layout.monitorWindowResize = false;
29388 this.el.addClass("x-dlg-auto-layout");
29389 // fix case when center region overwrites center function
29390 this.center = Roo.BasicDialog.prototype.center;
29391 this.on("show", this.layout.layout, this.layout, true);
29392 if (config.items) {
29393 var xitems = config.items;
29394 delete config.items;
29395 Roo.each(xitems, this.addxtype, this);
29400 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29402 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29405 endUpdate : function(){
29406 this.layout.endUpdate();
29410 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29413 beginUpdate : function(){
29414 this.layout.beginUpdate();
29418 * Get the BorderLayout for this dialog
29419 * @return {Roo.BorderLayout}
29421 getLayout : function(){
29422 return this.layout;
29425 showEl : function(){
29426 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29428 this.layout.layout();
29433 // Use the syncHeightBeforeShow config option to control this automatically
29434 syncBodyHeight : function(){
29435 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29436 if(this.layout){this.layout.layout();}
29440 * Add an xtype element (actually adds to the layout.)
29441 * @return {Object} xdata xtype object data.
29444 addxtype : function(c) {
29445 return this.layout.addxtype(c);
29449 * Ext JS Library 1.1.1
29450 * Copyright(c) 2006-2007, Ext JS, LLC.
29452 * Originally Released Under LGPL - original licence link has changed is not relivant.
29455 * <script type="text/javascript">
29459 * @class Roo.MessageBox
29460 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29464 Roo.Msg.alert('Status', 'Changes saved successfully.');
29466 // Prompt for user data:
29467 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29469 // process text value...
29473 // Show a dialog using config options:
29475 title:'Save Changes?',
29476 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29477 buttons: Roo.Msg.YESNOCANCEL,
29484 Roo.MessageBox = function(){
29485 var dlg, opt, mask, waitTimer;
29486 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29487 var buttons, activeTextEl, bwidth;
29490 var handleButton = function(button){
29492 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29496 var handleHide = function(){
29497 if(opt && opt.cls){
29498 dlg.el.removeClass(opt.cls);
29501 Roo.TaskMgr.stop(waitTimer);
29507 var updateButtons = function(b){
29510 buttons["ok"].hide();
29511 buttons["cancel"].hide();
29512 buttons["yes"].hide();
29513 buttons["no"].hide();
29514 dlg.footer.dom.style.display = 'none';
29517 dlg.footer.dom.style.display = '';
29518 for(var k in buttons){
29519 if(typeof buttons[k] != "function"){
29522 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29523 width += buttons[k].el.getWidth()+15;
29533 var handleEsc = function(d, k, e){
29534 if(opt && opt.closable !== false){
29544 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29545 * @return {Roo.BasicDialog} The BasicDialog element
29547 getDialog : function(){
29549 dlg = new Roo.BasicDialog("x-msg-box", {
29554 constraintoviewport:false,
29556 collapsible : false,
29559 width:400, height:100,
29560 buttonAlign:"center",
29561 closeClick : function(){
29562 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29563 handleButton("no");
29565 handleButton("cancel");
29569 dlg.on("hide", handleHide);
29571 dlg.addKeyListener(27, handleEsc);
29573 var bt = this.buttonText;
29574 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29575 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29576 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29577 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29578 bodyEl = dlg.body.createChild({
29580 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>'
29582 msgEl = bodyEl.dom.firstChild;
29583 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29584 textboxEl.enableDisplayMode();
29585 textboxEl.addKeyListener([10,13], function(){
29586 if(dlg.isVisible() && opt && opt.buttons){
29587 if(opt.buttons.ok){
29588 handleButton("ok");
29589 }else if(opt.buttons.yes){
29590 handleButton("yes");
29594 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29595 textareaEl.enableDisplayMode();
29596 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29597 progressEl.enableDisplayMode();
29598 var pf = progressEl.dom.firstChild;
29600 pp = Roo.get(pf.firstChild);
29601 pp.setHeight(pf.offsetHeight);
29609 * Updates the message box body text
29610 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29611 * the XHTML-compliant non-breaking space character '&#160;')
29612 * @return {Roo.MessageBox} This message box
29614 updateText : function(text){
29615 if(!dlg.isVisible() && !opt.width){
29616 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29618 msgEl.innerHTML = text || ' ';
29619 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29620 Math.max(opt.minWidth || this.minWidth, bwidth));
29622 activeTextEl.setWidth(w);
29624 if(dlg.isVisible()){
29625 dlg.fixedcenter = false;
29627 dlg.setContentSize(w, bodyEl.getHeight());
29628 if(dlg.isVisible()){
29629 dlg.fixedcenter = true;
29635 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29636 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29637 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29638 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29639 * @return {Roo.MessageBox} This message box
29641 updateProgress : function(value, text){
29643 this.updateText(text);
29645 if (pp) { // weird bug on my firefox - for some reason this is not defined
29646 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29652 * Returns true if the message box is currently displayed
29653 * @return {Boolean} True if the message box is visible, else false
29655 isVisible : function(){
29656 return dlg && dlg.isVisible();
29660 * Hides the message box if it is displayed
29663 if(this.isVisible()){
29669 * Displays a new message box, or reinitializes an existing message box, based on the config options
29670 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29671 * The following config object properties are supported:
29673 Property Type Description
29674 ---------- --------------- ------------------------------------------------------------------------------------
29675 animEl String/Element An id or Element from which the message box should animate as it opens and
29676 closes (defaults to undefined)
29677 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29678 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29679 closable Boolean False to hide the top-right close button (defaults to true). Note that
29680 progress and wait dialogs will ignore this property and always hide the
29681 close button as they can only be closed programmatically.
29682 cls String A custom CSS class to apply to the message box element
29683 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29684 displayed (defaults to 75)
29685 fn Function A callback function to execute after closing the dialog. The arguments to the
29686 function will be btn (the name of the button that was clicked, if applicable,
29687 e.g. "ok"), and text (the value of the active text field, if applicable).
29688 Progress and wait dialogs will ignore this option since they do not respond to
29689 user actions and can only be closed programmatically, so any required function
29690 should be called by the same code after it closes the dialog.
29691 icon String A CSS class that provides a background image to be used as an icon for
29692 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29693 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29694 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29695 modal Boolean False to allow user interaction with the page while the message box is
29696 displayed (defaults to true)
29697 msg String A string that will replace the existing message box body text (defaults
29698 to the XHTML-compliant non-breaking space character ' ')
29699 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
29700 progress Boolean True to display a progress bar (defaults to false)
29701 progressText String The text to display inside the progress bar if progress = true (defaults to '')
29702 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
29703 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
29704 title String The title text
29705 value String The string value to set into the active textbox element if displayed
29706 wait Boolean True to display a progress bar (defaults to false)
29707 width Number The width of the dialog in pixels
29714 msg: 'Please enter your address:',
29716 buttons: Roo.MessageBox.OKCANCEL,
29719 animEl: 'addAddressBtn'
29722 * @param {Object} config Configuration options
29723 * @return {Roo.MessageBox} This message box
29725 show : function(options){
29726 if(this.isVisible()){
29729 var d = this.getDialog();
29731 d.setTitle(opt.title || " ");
29732 d.close.setDisplayed(opt.closable !== false);
29733 activeTextEl = textboxEl;
29734 opt.prompt = opt.prompt || (opt.multiline ? true : false);
29739 textareaEl.setHeight(typeof opt.multiline == "number" ?
29740 opt.multiline : this.defaultTextHeight);
29741 activeTextEl = textareaEl;
29750 progressEl.setDisplayed(opt.progress === true);
29751 this.updateProgress(0);
29752 activeTextEl.dom.value = opt.value || "";
29754 dlg.setDefaultButton(activeTextEl);
29756 var bs = opt.buttons;
29759 db = buttons["ok"];
29760 }else if(bs && bs.yes){
29761 db = buttons["yes"];
29763 dlg.setDefaultButton(db);
29765 bwidth = updateButtons(opt.buttons);
29766 this.updateText(opt.msg);
29768 d.el.addClass(opt.cls);
29770 d.proxyDrag = opt.proxyDrag === true;
29771 d.modal = opt.modal !== false;
29772 d.mask = opt.modal !== false ? mask : false;
29773 if(!d.isVisible()){
29774 // force it to the end of the z-index stack so it gets a cursor in FF
29775 document.body.appendChild(dlg.el.dom);
29776 d.animateTarget = null;
29777 d.show(options.animEl);
29783 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
29784 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
29785 * and closing the message box when the process is complete.
29786 * @param {String} title The title bar text
29787 * @param {String} msg The message box body text
29788 * @return {Roo.MessageBox} This message box
29790 progress : function(title, msg){
29797 minWidth: this.minProgressWidth,
29804 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
29805 * If a callback function is passed it will be called after the user clicks the button, and the
29806 * id of the button that was clicked will be passed as the only parameter to the callback
29807 * (could also be the top-right close button).
29808 * @param {String} title The title bar text
29809 * @param {String} msg The message box body text
29810 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29811 * @param {Object} scope (optional) The scope of the callback function
29812 * @return {Roo.MessageBox} This message box
29814 alert : function(title, msg, fn, scope){
29827 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
29828 * interaction while waiting for a long-running process to complete that does not have defined intervals.
29829 * You are responsible for closing the message box when the process is complete.
29830 * @param {String} msg The message box body text
29831 * @param {String} title (optional) The title bar text
29832 * @return {Roo.MessageBox} This message box
29834 wait : function(msg, title){
29845 waitTimer = Roo.TaskMgr.start({
29847 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
29855 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
29856 * If a callback function is passed it will be called after the user clicks either button, and the id of the
29857 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
29858 * @param {String} title The title bar text
29859 * @param {String} msg The message box body text
29860 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29861 * @param {Object} scope (optional) The scope of the callback function
29862 * @return {Roo.MessageBox} This message box
29864 confirm : function(title, msg, fn, scope){
29868 buttons: this.YESNO,
29877 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
29878 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
29879 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
29880 * (could also be the top-right close button) and the text that was entered will be passed as the two
29881 * parameters to the callback.
29882 * @param {String} title The title bar text
29883 * @param {String} msg The message box body text
29884 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29885 * @param {Object} scope (optional) The scope of the callback function
29886 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
29887 * property, or the height in pixels to create the textbox (defaults to false / single-line)
29888 * @return {Roo.MessageBox} This message box
29890 prompt : function(title, msg, fn, scope, multiline){
29894 buttons: this.OKCANCEL,
29899 multiline: multiline,
29906 * Button config that displays a single OK button
29911 * Button config that displays Yes and No buttons
29914 YESNO : {yes:true, no:true},
29916 * Button config that displays OK and Cancel buttons
29919 OKCANCEL : {ok:true, cancel:true},
29921 * Button config that displays Yes, No and Cancel buttons
29924 YESNOCANCEL : {yes:true, no:true, cancel:true},
29927 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
29930 defaultTextHeight : 75,
29932 * The maximum width in pixels of the message box (defaults to 600)
29937 * The minimum width in pixels of the message box (defaults to 100)
29942 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
29943 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
29946 minProgressWidth : 250,
29948 * An object containing the default button text strings that can be overriden for localized language support.
29949 * Supported properties are: ok, cancel, yes and no.
29950 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
29963 * Shorthand for {@link Roo.MessageBox}
29965 Roo.Msg = Roo.MessageBox;/*
29967 * Ext JS Library 1.1.1
29968 * Copyright(c) 2006-2007, Ext JS, LLC.
29970 * Originally Released Under LGPL - original licence link has changed is not relivant.
29973 * <script type="text/javascript">
29976 * @class Roo.QuickTips
29977 * Provides attractive and customizable tooltips for any element.
29980 Roo.QuickTips = function(){
29981 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
29982 var ce, bd, xy, dd;
29983 var visible = false, disabled = true, inited = false;
29984 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
29986 var onOver = function(e){
29990 var t = e.getTarget();
29991 if(!t || t.nodeType !== 1 || t == document || t == document.body){
29994 if(ce && t == ce.el){
29995 clearTimeout(hideProc);
29998 if(t && tagEls[t.id]){
29999 tagEls[t.id].el = t;
30000 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30003 var ttp, et = Roo.fly(t);
30004 var ns = cfg.namespace;
30005 if(tm.interceptTitles && t.title){
30008 t.removeAttribute("title");
30009 e.preventDefault();
30011 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30014 showProc = show.defer(tm.showDelay, tm, [{
30017 width: et.getAttributeNS(ns, cfg.width),
30018 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30019 title: et.getAttributeNS(ns, cfg.title),
30020 cls: et.getAttributeNS(ns, cfg.cls)
30025 var onOut = function(e){
30026 clearTimeout(showProc);
30027 var t = e.getTarget();
30028 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30029 hideProc = setTimeout(hide, tm.hideDelay);
30033 var onMove = function(e){
30039 if(tm.trackMouse && ce){
30044 var onDown = function(e){
30045 clearTimeout(showProc);
30046 clearTimeout(hideProc);
30048 if(tm.hideOnClick){
30051 tm.enable.defer(100, tm);
30056 var getPad = function(){
30057 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30060 var show = function(o){
30064 clearTimeout(dismissProc);
30066 if(removeCls){ // in case manually hidden
30067 el.removeClass(removeCls);
30071 el.addClass(ce.cls);
30072 removeCls = ce.cls;
30075 tipTitle.update(ce.title);
30078 tipTitle.update('');
30081 el.dom.style.width = tm.maxWidth+'px';
30082 //tipBody.dom.style.width = '';
30083 tipBodyText.update(o.text);
30084 var p = getPad(), w = ce.width;
30086 var td = tipBodyText.dom;
30087 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30088 if(aw > tm.maxWidth){
30090 }else if(aw < tm.minWidth){
30096 //tipBody.setWidth(w);
30097 el.setWidth(parseInt(w, 10) + p);
30098 if(ce.autoHide === false){
30099 close.setDisplayed(true);
30104 close.setDisplayed(false);
30110 el.avoidY = xy[1]-18;
30115 el.setStyle("visibility", "visible");
30116 el.fadeIn({callback: afterShow});
30122 var afterShow = function(){
30126 if(tm.autoDismiss && ce.autoHide !== false){
30127 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30132 var hide = function(noanim){
30133 clearTimeout(dismissProc);
30134 clearTimeout(hideProc);
30136 if(el.isVisible()){
30138 if(noanim !== true && tm.animate){
30139 el.fadeOut({callback: afterHide});
30146 var afterHide = function(){
30149 el.removeClass(removeCls);
30156 * @cfg {Number} minWidth
30157 * The minimum width of the quick tip (defaults to 40)
30161 * @cfg {Number} maxWidth
30162 * The maximum width of the quick tip (defaults to 300)
30166 * @cfg {Boolean} interceptTitles
30167 * True to automatically use the element's DOM title value if available (defaults to false)
30169 interceptTitles : false,
30171 * @cfg {Boolean} trackMouse
30172 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30174 trackMouse : false,
30176 * @cfg {Boolean} hideOnClick
30177 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30179 hideOnClick : true,
30181 * @cfg {Number} showDelay
30182 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30186 * @cfg {Number} hideDelay
30187 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30191 * @cfg {Boolean} autoHide
30192 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30193 * Used in conjunction with hideDelay.
30198 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30199 * (defaults to true). Used in conjunction with autoDismissDelay.
30201 autoDismiss : true,
30204 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30206 autoDismissDelay : 5000,
30208 * @cfg {Boolean} animate
30209 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30214 * @cfg {String} title
30215 * Title text to display (defaults to ''). This can be any valid HTML markup.
30219 * @cfg {String} text
30220 * Body text to display (defaults to ''). This can be any valid HTML markup.
30224 * @cfg {String} cls
30225 * A CSS class to apply to the base quick tip element (defaults to '').
30229 * @cfg {Number} width
30230 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30231 * minWidth or maxWidth.
30236 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30237 * or display QuickTips in a page.
30240 tm = Roo.QuickTips;
30241 cfg = tm.tagConfig;
30243 if(!Roo.isReady){ // allow calling of init() before onReady
30244 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30247 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30248 el.fxDefaults = {stopFx: true};
30249 // maximum custom styling
30250 //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>');
30251 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>');
30252 tipTitle = el.child('h3');
30253 tipTitle.enableDisplayMode("block");
30254 tipBody = el.child('div.x-tip-bd');
30255 tipBodyText = el.child('div.x-tip-bd-inner');
30256 //bdLeft = el.child('div.x-tip-bd-left');
30257 //bdRight = el.child('div.x-tip-bd-right');
30258 close = el.child('div.x-tip-close');
30259 close.enableDisplayMode("block");
30260 close.on("click", hide);
30261 var d = Roo.get(document);
30262 d.on("mousedown", onDown);
30263 d.on("mouseover", onOver);
30264 d.on("mouseout", onOut);
30265 d.on("mousemove", onMove);
30266 esc = d.addKeyListener(27, hide);
30269 dd = el.initDD("default", null, {
30270 onDrag : function(){
30274 dd.setHandleElId(tipTitle.id);
30283 * Configures a new quick tip instance and assigns it to a target element. The following config options
30286 Property Type Description
30287 ---------- --------------------- ------------------------------------------------------------------------
30288 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30290 * @param {Object} config The config object
30292 register : function(config){
30293 var cs = config instanceof Array ? config : arguments;
30294 for(var i = 0, len = cs.length; i < len; i++) {
30296 var target = c.target;
30298 if(target instanceof Array){
30299 for(var j = 0, jlen = target.length; j < jlen; j++){
30300 tagEls[target[j]] = c;
30303 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30310 * Removes this quick tip from its element and destroys it.
30311 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30313 unregister : function(el){
30314 delete tagEls[Roo.id(el)];
30318 * Enable this quick tip.
30320 enable : function(){
30321 if(inited && disabled){
30323 if(locks.length < 1){
30330 * Disable this quick tip.
30332 disable : function(){
30334 clearTimeout(showProc);
30335 clearTimeout(hideProc);
30336 clearTimeout(dismissProc);
30344 * Returns true if the quick tip is enabled, else false.
30346 isEnabled : function(){
30353 attribute : "qtip",
30363 // backwards compat
30364 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30366 * Ext JS Library 1.1.1
30367 * Copyright(c) 2006-2007, Ext JS, LLC.
30369 * Originally Released Under LGPL - original licence link has changed is not relivant.
30372 * <script type="text/javascript">
30377 * @class Roo.tree.TreePanel
30378 * @extends Roo.data.Tree
30380 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30381 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30382 * @cfg {Boolean} enableDD true to enable drag and drop
30383 * @cfg {Boolean} enableDrag true to enable just drag
30384 * @cfg {Boolean} enableDrop true to enable just drop
30385 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30386 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30387 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30388 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30389 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30390 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30391 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30392 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30393 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30394 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30395 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30396 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30397 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30398 * @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>
30399 * @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>
30402 * @param {String/HTMLElement/Element} el The container element
30403 * @param {Object} config
30405 Roo.tree.TreePanel = function(el, config){
30407 var loader = false;
30409 root = config.root;
30410 delete config.root;
30412 if (config.loader) {
30413 loader = config.loader;
30414 delete config.loader;
30417 Roo.apply(this, config);
30418 Roo.tree.TreePanel.superclass.constructor.call(this);
30419 this.el = Roo.get(el);
30420 this.el.addClass('x-tree');
30421 //console.log(root);
30423 this.setRootNode( Roo.factory(root, Roo.tree));
30426 this.loader = Roo.factory(loader, Roo.tree);
30429 * Read-only. The id of the container element becomes this TreePanel's id.
30431 this.id = this.el.id;
30434 * @event beforeload
30435 * Fires before a node is loaded, return false to cancel
30436 * @param {Node} node The node being loaded
30438 "beforeload" : true,
30441 * Fires when a node is loaded
30442 * @param {Node} node The node that was loaded
30446 * @event textchange
30447 * Fires when the text for a node is changed
30448 * @param {Node} node The node
30449 * @param {String} text The new text
30450 * @param {String} oldText The old text
30452 "textchange" : true,
30454 * @event beforeexpand
30455 * Fires before a node is expanded, return false to cancel.
30456 * @param {Node} node The node
30457 * @param {Boolean} deep
30458 * @param {Boolean} anim
30460 "beforeexpand" : true,
30462 * @event beforecollapse
30463 * Fires before a node is collapsed, return false to cancel.
30464 * @param {Node} node The node
30465 * @param {Boolean} deep
30466 * @param {Boolean} anim
30468 "beforecollapse" : true,
30471 * Fires when a node is expanded
30472 * @param {Node} node The node
30476 * @event disabledchange
30477 * Fires when the disabled status of a node changes
30478 * @param {Node} node The node
30479 * @param {Boolean} disabled
30481 "disabledchange" : true,
30484 * Fires when a node is collapsed
30485 * @param {Node} node The node
30489 * @event beforeclick
30490 * Fires before click processing on a node. Return false to cancel the default action.
30491 * @param {Node} node The node
30492 * @param {Roo.EventObject} e The event object
30494 "beforeclick":true,
30496 * @event checkchange
30497 * Fires when a node with a checkbox's checked property changes
30498 * @param {Node} this This node
30499 * @param {Boolean} checked
30501 "checkchange":true,
30504 * Fires when a node is clicked
30505 * @param {Node} node The node
30506 * @param {Roo.EventObject} e The event object
30511 * Fires when a node is double clicked
30512 * @param {Node} node The node
30513 * @param {Roo.EventObject} e The event object
30517 * @event contextmenu
30518 * Fires when a node is right clicked
30519 * @param {Node} node The node
30520 * @param {Roo.EventObject} e The event object
30522 "contextmenu":true,
30524 * @event beforechildrenrendered
30525 * Fires right before the child nodes for a node are rendered
30526 * @param {Node} node The node
30528 "beforechildrenrendered":true,
30531 * Fires when a node starts being dragged
30532 * @param {Roo.tree.TreePanel} this
30533 * @param {Roo.tree.TreeNode} node
30534 * @param {event} e The raw browser event
30536 "startdrag" : true,
30539 * Fires when a drag operation is complete
30540 * @param {Roo.tree.TreePanel} this
30541 * @param {Roo.tree.TreeNode} node
30542 * @param {event} e The raw browser event
30547 * Fires when a dragged node is dropped on a valid DD target
30548 * @param {Roo.tree.TreePanel} this
30549 * @param {Roo.tree.TreeNode} node
30550 * @param {DD} dd The dd it was dropped on
30551 * @param {event} e The raw browser event
30555 * @event beforenodedrop
30556 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30557 * passed to handlers has the following properties:<br />
30558 * <ul style="padding:5px;padding-left:16px;">
30559 * <li>tree - The TreePanel</li>
30560 * <li>target - The node being targeted for the drop</li>
30561 * <li>data - The drag data from the drag source</li>
30562 * <li>point - The point of the drop - append, above or below</li>
30563 * <li>source - The drag source</li>
30564 * <li>rawEvent - Raw mouse event</li>
30565 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30566 * to be inserted by setting them on this object.</li>
30567 * <li>cancel - Set this to true to cancel the drop.</li>
30569 * @param {Object} dropEvent
30571 "beforenodedrop" : true,
30574 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30575 * passed to handlers has the following properties:<br />
30576 * <ul style="padding:5px;padding-left:16px;">
30577 * <li>tree - The TreePanel</li>
30578 * <li>target - The node being targeted for the drop</li>
30579 * <li>data - The drag data from the drag source</li>
30580 * <li>point - The point of the drop - append, above or below</li>
30581 * <li>source - The drag source</li>
30582 * <li>rawEvent - Raw mouse event</li>
30583 * <li>dropNode - Dropped node(s).</li>
30585 * @param {Object} dropEvent
30589 * @event nodedragover
30590 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30591 * passed to handlers has the following properties:<br />
30592 * <ul style="padding:5px;padding-left:16px;">
30593 * <li>tree - The TreePanel</li>
30594 * <li>target - The node being targeted for the drop</li>
30595 * <li>data - The drag data from the drag source</li>
30596 * <li>point - The point of the drop - append, above or below</li>
30597 * <li>source - The drag source</li>
30598 * <li>rawEvent - Raw mouse event</li>
30599 * <li>dropNode - Drop node(s) provided by the source.</li>
30600 * <li>cancel - Set this to true to signal drop not allowed.</li>
30602 * @param {Object} dragOverEvent
30604 "nodedragover" : true
30607 if(this.singleExpand){
30608 this.on("beforeexpand", this.restrictExpand, this);
30611 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30612 rootVisible : true,
30613 animate: Roo.enableFx,
30616 hlDrop : Roo.enableFx,
30620 rendererTip: false,
30622 restrictExpand : function(node){
30623 var p = node.parentNode;
30625 if(p.expandedChild && p.expandedChild.parentNode == p){
30626 p.expandedChild.collapse();
30628 p.expandedChild = node;
30632 // private override
30633 setRootNode : function(node){
30634 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30635 if(!this.rootVisible){
30636 node.ui = new Roo.tree.RootTreeNodeUI(node);
30642 * Returns the container element for this TreePanel
30644 getEl : function(){
30649 * Returns the default TreeLoader for this TreePanel
30651 getLoader : function(){
30652 return this.loader;
30658 expandAll : function(){
30659 this.root.expand(true);
30663 * Collapse all nodes
30665 collapseAll : function(){
30666 this.root.collapse(true);
30670 * Returns the selection model used by this TreePanel
30672 getSelectionModel : function(){
30673 if(!this.selModel){
30674 this.selModel = new Roo.tree.DefaultSelectionModel();
30676 return this.selModel;
30680 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30681 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30682 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30685 getChecked : function(a, startNode){
30686 startNode = startNode || this.root;
30688 var f = function(){
30689 if(this.attributes.checked){
30690 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30693 startNode.cascade(f);
30698 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30699 * @param {String} path
30700 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30701 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
30702 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
30704 expandPath : function(path, attr, callback){
30705 attr = attr || "id";
30706 var keys = path.split(this.pathSeparator);
30707 var curNode = this.root;
30708 if(curNode.attributes[attr] != keys[1]){ // invalid root
30710 callback(false, null);
30715 var f = function(){
30716 if(++index == keys.length){
30718 callback(true, curNode);
30722 var c = curNode.findChild(attr, keys[index]);
30725 callback(false, curNode);
30730 c.expand(false, false, f);
30732 curNode.expand(false, false, f);
30736 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30737 * @param {String} path
30738 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30739 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
30740 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
30742 selectPath : function(path, attr, callback){
30743 attr = attr || "id";
30744 var keys = path.split(this.pathSeparator);
30745 var v = keys.pop();
30746 if(keys.length > 0){
30747 var f = function(success, node){
30748 if(success && node){
30749 var n = node.findChild(attr, v);
30755 }else if(callback){
30756 callback(false, n);
30760 callback(false, n);
30764 this.expandPath(keys.join(this.pathSeparator), attr, f);
30766 this.root.select();
30768 callback(true, this.root);
30773 getTreeEl : function(){
30778 * Trigger rendering of this TreePanel
30780 render : function(){
30781 if (this.innerCt) {
30782 return this; // stop it rendering more than once!!
30785 this.innerCt = this.el.createChild({tag:"ul",
30786 cls:"x-tree-root-ct " +
30787 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
30789 if(this.containerScroll){
30790 Roo.dd.ScrollManager.register(this.el);
30792 if((this.enableDD || this.enableDrop) && !this.dropZone){
30794 * The dropZone used by this tree if drop is enabled
30795 * @type Roo.tree.TreeDropZone
30797 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
30798 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
30801 if((this.enableDD || this.enableDrag) && !this.dragZone){
30803 * The dragZone used by this tree if drag is enabled
30804 * @type Roo.tree.TreeDragZone
30806 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
30807 ddGroup: this.ddGroup || "TreeDD",
30808 scroll: this.ddScroll
30811 this.getSelectionModel().init(this);
30813 console.log("ROOT not set in tree");
30816 this.root.render();
30817 if(!this.rootVisible){
30818 this.root.renderChildren();
30824 * Ext JS Library 1.1.1
30825 * Copyright(c) 2006-2007, Ext JS, LLC.
30827 * Originally Released Under LGPL - original licence link has changed is not relivant.
30830 * <script type="text/javascript">
30835 * @class Roo.tree.DefaultSelectionModel
30836 * @extends Roo.util.Observable
30837 * The default single selection for a TreePanel.
30839 Roo.tree.DefaultSelectionModel = function(){
30840 this.selNode = null;
30844 * @event selectionchange
30845 * Fires when the selected node changes
30846 * @param {DefaultSelectionModel} this
30847 * @param {TreeNode} node the new selection
30849 "selectionchange" : true,
30852 * @event beforeselect
30853 * Fires before the selected node changes, return false to cancel the change
30854 * @param {DefaultSelectionModel} this
30855 * @param {TreeNode} node the new selection
30856 * @param {TreeNode} node the old selection
30858 "beforeselect" : true
30862 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
30863 init : function(tree){
30865 tree.getTreeEl().on("keydown", this.onKeyDown, this);
30866 tree.on("click", this.onNodeClick, this);
30869 onNodeClick : function(node, e){
30870 if (e.ctrlKey && this.selNode == node) {
30871 this.unselect(node);
30879 * @param {TreeNode} node The node to select
30880 * @return {TreeNode} The selected node
30882 select : function(node){
30883 var last = this.selNode;
30884 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
30886 last.ui.onSelectedChange(false);
30888 this.selNode = node;
30889 node.ui.onSelectedChange(true);
30890 this.fireEvent("selectionchange", this, node, last);
30897 * @param {TreeNode} node The node to unselect
30899 unselect : function(node){
30900 if(this.selNode == node){
30901 this.clearSelections();
30906 * Clear all selections
30908 clearSelections : function(){
30909 var n = this.selNode;
30911 n.ui.onSelectedChange(false);
30912 this.selNode = null;
30913 this.fireEvent("selectionchange", this, null);
30919 * Get the selected node
30920 * @return {TreeNode} The selected node
30922 getSelectedNode : function(){
30923 return this.selNode;
30927 * Returns true if the node is selected
30928 * @param {TreeNode} node The node to check
30929 * @return {Boolean}
30931 isSelected : function(node){
30932 return this.selNode == node;
30936 * Selects the node above the selected node in the tree, intelligently walking the nodes
30937 * @return TreeNode The new selection
30939 selectPrevious : function(){
30940 var s = this.selNode || this.lastSelNode;
30944 var ps = s.previousSibling;
30946 if(!ps.isExpanded() || ps.childNodes.length < 1){
30947 return this.select(ps);
30949 var lc = ps.lastChild;
30950 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
30953 return this.select(lc);
30955 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
30956 return this.select(s.parentNode);
30962 * Selects the node above the selected node in the tree, intelligently walking the nodes
30963 * @return TreeNode The new selection
30965 selectNext : function(){
30966 var s = this.selNode || this.lastSelNode;
30970 if(s.firstChild && s.isExpanded()){
30971 return this.select(s.firstChild);
30972 }else if(s.nextSibling){
30973 return this.select(s.nextSibling);
30974 }else if(s.parentNode){
30976 s.parentNode.bubble(function(){
30977 if(this.nextSibling){
30978 newS = this.getOwnerTree().selModel.select(this.nextSibling);
30987 onKeyDown : function(e){
30988 var s = this.selNode || this.lastSelNode;
30989 // undesirable, but required
30994 var k = e.getKey();
31002 this.selectPrevious();
31005 e.preventDefault();
31006 if(s.hasChildNodes()){
31007 if(!s.isExpanded()){
31009 }else if(s.firstChild){
31010 this.select(s.firstChild, e);
31015 e.preventDefault();
31016 if(s.hasChildNodes() && s.isExpanded()){
31018 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31019 this.select(s.parentNode, e);
31027 * @class Roo.tree.MultiSelectionModel
31028 * @extends Roo.util.Observable
31029 * Multi selection for a TreePanel.
31031 Roo.tree.MultiSelectionModel = function(){
31032 this.selNodes = [];
31036 * @event selectionchange
31037 * Fires when the selected nodes change
31038 * @param {MultiSelectionModel} this
31039 * @param {Array} nodes Array of the selected nodes
31041 "selectionchange" : true
31045 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31046 init : function(tree){
31048 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31049 tree.on("click", this.onNodeClick, this);
31052 onNodeClick : function(node, e){
31053 this.select(node, e, e.ctrlKey);
31058 * @param {TreeNode} node The node to select
31059 * @param {EventObject} e (optional) An event associated with the selection
31060 * @param {Boolean} keepExisting True to retain existing selections
31061 * @return {TreeNode} The selected node
31063 select : function(node, e, keepExisting){
31064 if(keepExisting !== true){
31065 this.clearSelections(true);
31067 if(this.isSelected(node)){
31068 this.lastSelNode = node;
31071 this.selNodes.push(node);
31072 this.selMap[node.id] = node;
31073 this.lastSelNode = node;
31074 node.ui.onSelectedChange(true);
31075 this.fireEvent("selectionchange", this, this.selNodes);
31081 * @param {TreeNode} node The node to unselect
31083 unselect : function(node){
31084 if(this.selMap[node.id]){
31085 node.ui.onSelectedChange(false);
31086 var sn = this.selNodes;
31089 index = sn.indexOf(node);
31091 for(var i = 0, len = sn.length; i < len; i++){
31099 this.selNodes.splice(index, 1);
31101 delete this.selMap[node.id];
31102 this.fireEvent("selectionchange", this, this.selNodes);
31107 * Clear all selections
31109 clearSelections : function(suppressEvent){
31110 var sn = this.selNodes;
31112 for(var i = 0, len = sn.length; i < len; i++){
31113 sn[i].ui.onSelectedChange(false);
31115 this.selNodes = [];
31117 if(suppressEvent !== true){
31118 this.fireEvent("selectionchange", this, this.selNodes);
31124 * Returns true if the node is selected
31125 * @param {TreeNode} node The node to check
31126 * @return {Boolean}
31128 isSelected : function(node){
31129 return this.selMap[node.id] ? true : false;
31133 * Returns an array of the selected nodes
31136 getSelectedNodes : function(){
31137 return this.selNodes;
31140 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31142 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31144 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31147 * Ext JS Library 1.1.1
31148 * Copyright(c) 2006-2007, Ext JS, LLC.
31150 * Originally Released Under LGPL - original licence link has changed is not relivant.
31153 * <script type="text/javascript">
31157 * @class Roo.tree.TreeNode
31158 * @extends Roo.data.Node
31159 * @cfg {String} text The text for this node
31160 * @cfg {Boolean} expanded true to start the node expanded
31161 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31162 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31163 * @cfg {Boolean} disabled true to start the node disabled
31164 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31165 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31166 * @cfg {String} cls A css class to be added to the node
31167 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31168 * @cfg {String} href URL of the link used for the node (defaults to #)
31169 * @cfg {String} hrefTarget target frame for the link
31170 * @cfg {String} qtip An Ext QuickTip for the node
31171 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31172 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31173 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31174 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31175 * (defaults to undefined with no checkbox rendered)
31177 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31179 Roo.tree.TreeNode = function(attributes){
31180 attributes = attributes || {};
31181 if(typeof attributes == "string"){
31182 attributes = {text: attributes};
31184 this.childrenRendered = false;
31185 this.rendered = false;
31186 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31187 this.expanded = attributes.expanded === true;
31188 this.isTarget = attributes.isTarget !== false;
31189 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31190 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31193 * Read-only. The text for this node. To change it use setText().
31196 this.text = attributes.text;
31198 * True if this node is disabled.
31201 this.disabled = attributes.disabled === true;
31205 * @event textchange
31206 * Fires when the text for this node is changed
31207 * @param {Node} this This node
31208 * @param {String} text The new text
31209 * @param {String} oldText The old text
31211 "textchange" : true,
31213 * @event beforeexpand
31214 * Fires before this node is expanded, return false to cancel.
31215 * @param {Node} this This node
31216 * @param {Boolean} deep
31217 * @param {Boolean} anim
31219 "beforeexpand" : true,
31221 * @event beforecollapse
31222 * Fires before this node is collapsed, return false to cancel.
31223 * @param {Node} this This node
31224 * @param {Boolean} deep
31225 * @param {Boolean} anim
31227 "beforecollapse" : true,
31230 * Fires when this node is expanded
31231 * @param {Node} this This node
31235 * @event disabledchange
31236 * Fires when the disabled status of this node changes
31237 * @param {Node} this This node
31238 * @param {Boolean} disabled
31240 "disabledchange" : true,
31243 * Fires when this node is collapsed
31244 * @param {Node} this This node
31248 * @event beforeclick
31249 * Fires before click processing. Return false to cancel the default action.
31250 * @param {Node} this This node
31251 * @param {Roo.EventObject} e The event object
31253 "beforeclick":true,
31255 * @event checkchange
31256 * Fires when a node with a checkbox's checked property changes
31257 * @param {Node} this This node
31258 * @param {Boolean} checked
31260 "checkchange":true,
31263 * Fires when this node is clicked
31264 * @param {Node} this This node
31265 * @param {Roo.EventObject} e The event object
31270 * Fires when this node is double clicked
31271 * @param {Node} this This node
31272 * @param {Roo.EventObject} e The event object
31276 * @event contextmenu
31277 * Fires when this node is right clicked
31278 * @param {Node} this This node
31279 * @param {Roo.EventObject} e The event object
31281 "contextmenu":true,
31283 * @event beforechildrenrendered
31284 * Fires right before the child nodes for this node are rendered
31285 * @param {Node} this This node
31287 "beforechildrenrendered":true
31290 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31293 * Read-only. The UI for this node
31296 this.ui = new uiClass(this);
31298 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31299 preventHScroll: true,
31301 * Returns true if this node is expanded
31302 * @return {Boolean}
31304 isExpanded : function(){
31305 return this.expanded;
31309 * Returns the UI object for this node
31310 * @return {TreeNodeUI}
31312 getUI : function(){
31316 // private override
31317 setFirstChild : function(node){
31318 var of = this.firstChild;
31319 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31320 if(this.childrenRendered && of && node != of){
31321 of.renderIndent(true, true);
31324 this.renderIndent(true, true);
31328 // private override
31329 setLastChild : function(node){
31330 var ol = this.lastChild;
31331 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31332 if(this.childrenRendered && ol && node != ol){
31333 ol.renderIndent(true, true);
31336 this.renderIndent(true, true);
31340 // these methods are overridden to provide lazy rendering support
31341 // private override
31342 appendChild : function(){
31343 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31344 if(node && this.childrenRendered){
31347 this.ui.updateExpandIcon();
31351 // private override
31352 removeChild : function(node){
31353 this.ownerTree.getSelectionModel().unselect(node);
31354 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31355 // if it's been rendered remove dom node
31356 if(this.childrenRendered){
31359 if(this.childNodes.length < 1){
31360 this.collapse(false, false);
31362 this.ui.updateExpandIcon();
31364 if(!this.firstChild) {
31365 this.childrenRendered = false;
31370 // private override
31371 insertBefore : function(node, refNode){
31372 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31373 if(newNode && refNode && this.childrenRendered){
31376 this.ui.updateExpandIcon();
31381 * Sets the text for this node
31382 * @param {String} text
31384 setText : function(text){
31385 var oldText = this.text;
31387 this.attributes.text = text;
31388 if(this.rendered){ // event without subscribing
31389 this.ui.onTextChange(this, text, oldText);
31391 this.fireEvent("textchange", this, text, oldText);
31395 * Triggers selection of this node
31397 select : function(){
31398 this.getOwnerTree().getSelectionModel().select(this);
31402 * Triggers deselection of this node
31404 unselect : function(){
31405 this.getOwnerTree().getSelectionModel().unselect(this);
31409 * Returns true if this node is selected
31410 * @return {Boolean}
31412 isSelected : function(){
31413 return this.getOwnerTree().getSelectionModel().isSelected(this);
31417 * Expand this node.
31418 * @param {Boolean} deep (optional) True to expand all children as well
31419 * @param {Boolean} anim (optional) false to cancel the default animation
31420 * @param {Function} callback (optional) A callback to be called when
31421 * expanding this node completes (does not wait for deep expand to complete).
31422 * Called with 1 parameter, this node.
31424 expand : function(deep, anim, callback){
31425 if(!this.expanded){
31426 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31429 if(!this.childrenRendered){
31430 this.renderChildren();
31432 this.expanded = true;
31433 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31434 this.ui.animExpand(function(){
31435 this.fireEvent("expand", this);
31436 if(typeof callback == "function"){
31440 this.expandChildNodes(true);
31442 }.createDelegate(this));
31446 this.fireEvent("expand", this);
31447 if(typeof callback == "function"){
31452 if(typeof callback == "function"){
31457 this.expandChildNodes(true);
31461 isHiddenRoot : function(){
31462 return this.isRoot && !this.getOwnerTree().rootVisible;
31466 * Collapse this node.
31467 * @param {Boolean} deep (optional) True to collapse all children as well
31468 * @param {Boolean} anim (optional) false to cancel the default animation
31470 collapse : function(deep, anim){
31471 if(this.expanded && !this.isHiddenRoot()){
31472 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31475 this.expanded = false;
31476 if((this.getOwnerTree().animate && anim !== false) || anim){
31477 this.ui.animCollapse(function(){
31478 this.fireEvent("collapse", this);
31480 this.collapseChildNodes(true);
31482 }.createDelegate(this));
31485 this.ui.collapse();
31486 this.fireEvent("collapse", this);
31490 var cs = this.childNodes;
31491 for(var i = 0, len = cs.length; i < len; i++) {
31492 cs[i].collapse(true, false);
31498 delayedExpand : function(delay){
31499 if(!this.expandProcId){
31500 this.expandProcId = this.expand.defer(delay, this);
31505 cancelExpand : function(){
31506 if(this.expandProcId){
31507 clearTimeout(this.expandProcId);
31509 this.expandProcId = false;
31513 * Toggles expanded/collapsed state of the node
31515 toggle : function(){
31524 * Ensures all parent nodes are expanded
31526 ensureVisible : function(callback){
31527 var tree = this.getOwnerTree();
31528 tree.expandPath(this.parentNode.getPath(), false, function(){
31529 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31530 Roo.callback(callback);
31531 }.createDelegate(this));
31535 * Expand all child nodes
31536 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31538 expandChildNodes : function(deep){
31539 var cs = this.childNodes;
31540 for(var i = 0, len = cs.length; i < len; i++) {
31541 cs[i].expand(deep);
31546 * Collapse all child nodes
31547 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31549 collapseChildNodes : function(deep){
31550 var cs = this.childNodes;
31551 for(var i = 0, len = cs.length; i < len; i++) {
31552 cs[i].collapse(deep);
31557 * Disables this node
31559 disable : function(){
31560 this.disabled = true;
31562 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31563 this.ui.onDisableChange(this, true);
31565 this.fireEvent("disabledchange", this, true);
31569 * Enables this node
31571 enable : function(){
31572 this.disabled = false;
31573 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31574 this.ui.onDisableChange(this, false);
31576 this.fireEvent("disabledchange", this, false);
31580 renderChildren : function(suppressEvent){
31581 if(suppressEvent !== false){
31582 this.fireEvent("beforechildrenrendered", this);
31584 var cs = this.childNodes;
31585 for(var i = 0, len = cs.length; i < len; i++){
31586 cs[i].render(true);
31588 this.childrenRendered = true;
31592 sort : function(fn, scope){
31593 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31594 if(this.childrenRendered){
31595 var cs = this.childNodes;
31596 for(var i = 0, len = cs.length; i < len; i++){
31597 cs[i].render(true);
31603 render : function(bulkRender){
31604 this.ui.render(bulkRender);
31605 if(!this.rendered){
31606 this.rendered = true;
31608 this.expanded = false;
31609 this.expand(false, false);
31615 renderIndent : function(deep, refresh){
31617 this.ui.childIndent = null;
31619 this.ui.renderIndent();
31620 if(deep === true && this.childrenRendered){
31621 var cs = this.childNodes;
31622 for(var i = 0, len = cs.length; i < len; i++){
31623 cs[i].renderIndent(true, refresh);
31629 * Ext JS Library 1.1.1
31630 * Copyright(c) 2006-2007, Ext JS, LLC.
31632 * Originally Released Under LGPL - original licence link has changed is not relivant.
31635 * <script type="text/javascript">
31639 * @class Roo.tree.AsyncTreeNode
31640 * @extends Roo.tree.TreeNode
31641 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31643 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31645 Roo.tree.AsyncTreeNode = function(config){
31646 this.loaded = false;
31647 this.loading = false;
31648 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31650 * @event beforeload
31651 * Fires before this node is loaded, return false to cancel
31652 * @param {Node} this This node
31654 this.addEvents({'beforeload':true, 'load': true});
31657 * Fires when this node is loaded
31658 * @param {Node} this This node
31661 * The loader used by this node (defaults to using the tree's defined loader)
31666 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31667 expand : function(deep, anim, callback){
31668 if(this.loading){ // if an async load is already running, waiting til it's done
31670 var f = function(){
31671 if(!this.loading){ // done loading
31672 clearInterval(timer);
31673 this.expand(deep, anim, callback);
31675 }.createDelegate(this);
31676 timer = setInterval(f, 200);
31680 if(this.fireEvent("beforeload", this) === false){
31683 this.loading = true;
31684 this.ui.beforeLoad(this);
31685 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31687 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31691 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31695 * Returns true if this node is currently loading
31696 * @return {Boolean}
31698 isLoading : function(){
31699 return this.loading;
31702 loadComplete : function(deep, anim, callback){
31703 this.loading = false;
31704 this.loaded = true;
31705 this.ui.afterLoad(this);
31706 this.fireEvent("load", this);
31707 this.expand(deep, anim, callback);
31711 * Returns true if this node has been loaded
31712 * @return {Boolean}
31714 isLoaded : function(){
31715 return this.loaded;
31718 hasChildNodes : function(){
31719 if(!this.isLeaf() && !this.loaded){
31722 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
31727 * Trigger a reload for this node
31728 * @param {Function} callback
31730 reload : function(callback){
31731 this.collapse(false, false);
31732 while(this.firstChild){
31733 this.removeChild(this.firstChild);
31735 this.childrenRendered = false;
31736 this.loaded = false;
31737 if(this.isHiddenRoot()){
31738 this.expanded = false;
31740 this.expand(false, false, callback);
31744 * Ext JS Library 1.1.1
31745 * Copyright(c) 2006-2007, Ext JS, LLC.
31747 * Originally Released Under LGPL - original licence link has changed is not relivant.
31750 * <script type="text/javascript">
31754 * @class Roo.tree.TreeNodeUI
31756 * @param {Object} node The node to render
31757 * The TreeNode UI implementation is separate from the
31758 * tree implementation. Unless you are customizing the tree UI,
31759 * you should never have to use this directly.
31761 Roo.tree.TreeNodeUI = function(node){
31763 this.rendered = false;
31764 this.animating = false;
31765 this.emptyIcon = Roo.BLANK_IMAGE_URL;
31768 Roo.tree.TreeNodeUI.prototype = {
31769 removeChild : function(node){
31771 this.ctNode.removeChild(node.ui.getEl());
31775 beforeLoad : function(){
31776 this.addClass("x-tree-node-loading");
31779 afterLoad : function(){
31780 this.removeClass("x-tree-node-loading");
31783 onTextChange : function(node, text, oldText){
31785 this.textNode.innerHTML = text;
31789 onDisableChange : function(node, state){
31790 this.disabled = state;
31792 this.addClass("x-tree-node-disabled");
31794 this.removeClass("x-tree-node-disabled");
31798 onSelectedChange : function(state){
31801 this.addClass("x-tree-selected");
31804 this.removeClass("x-tree-selected");
31808 onMove : function(tree, node, oldParent, newParent, index, refNode){
31809 this.childIndent = null;
31811 var targetNode = newParent.ui.getContainer();
31812 if(!targetNode){//target not rendered
31813 this.holder = document.createElement("div");
31814 this.holder.appendChild(this.wrap);
31817 var insertBefore = refNode ? refNode.ui.getEl() : null;
31819 targetNode.insertBefore(this.wrap, insertBefore);
31821 targetNode.appendChild(this.wrap);
31823 this.node.renderIndent(true);
31827 addClass : function(cls){
31829 Roo.fly(this.elNode).addClass(cls);
31833 removeClass : function(cls){
31835 Roo.fly(this.elNode).removeClass(cls);
31839 remove : function(){
31841 this.holder = document.createElement("div");
31842 this.holder.appendChild(this.wrap);
31846 fireEvent : function(){
31847 return this.node.fireEvent.apply(this.node, arguments);
31850 initEvents : function(){
31851 this.node.on("move", this.onMove, this);
31852 var E = Roo.EventManager;
31853 var a = this.anchor;
31855 var el = Roo.fly(a, '_treeui');
31857 if(Roo.isOpera){ // opera render bug ignores the CSS
31858 el.setStyle("text-decoration", "none");
31861 el.on("click", this.onClick, this);
31862 el.on("dblclick", this.onDblClick, this);
31865 Roo.EventManager.on(this.checkbox,
31866 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
31869 el.on("contextmenu", this.onContextMenu, this);
31871 var icon = Roo.fly(this.iconNode);
31872 icon.on("click", this.onClick, this);
31873 icon.on("dblclick", this.onDblClick, this);
31874 icon.on("contextmenu", this.onContextMenu, this);
31875 E.on(this.ecNode, "click", this.ecClick, this, true);
31877 if(this.node.disabled){
31878 this.addClass("x-tree-node-disabled");
31880 if(this.node.hidden){
31881 this.addClass("x-tree-node-disabled");
31883 var ot = this.node.getOwnerTree();
31884 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
31885 if(dd && (!this.node.isRoot || ot.rootVisible)){
31886 Roo.dd.Registry.register(this.elNode, {
31888 handles: this.getDDHandles(),
31894 getDDHandles : function(){
31895 return [this.iconNode, this.textNode];
31900 this.wrap.style.display = "none";
31906 this.wrap.style.display = "";
31910 onContextMenu : function(e){
31911 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
31912 e.preventDefault();
31914 this.fireEvent("contextmenu", this.node, e);
31918 onClick : function(e){
31923 if(this.fireEvent("beforeclick", this.node, e) !== false){
31924 if(!this.disabled && this.node.attributes.href){
31925 this.fireEvent("click", this.node, e);
31928 e.preventDefault();
31933 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
31934 this.node.toggle();
31937 this.fireEvent("click", this.node, e);
31943 onDblClick : function(e){
31944 e.preventDefault();
31949 this.toggleCheck();
31951 if(!this.animating && this.node.hasChildNodes()){
31952 this.node.toggle();
31954 this.fireEvent("dblclick", this.node, e);
31957 onCheckChange : function(){
31958 var checked = this.checkbox.checked;
31959 this.node.attributes.checked = checked;
31960 this.fireEvent('checkchange', this.node, checked);
31963 ecClick : function(e){
31964 if(!this.animating && this.node.hasChildNodes()){
31965 this.node.toggle();
31969 startDrop : function(){
31970 this.dropping = true;
31973 // delayed drop so the click event doesn't get fired on a drop
31974 endDrop : function(){
31975 setTimeout(function(){
31976 this.dropping = false;
31977 }.createDelegate(this), 50);
31980 expand : function(){
31981 this.updateExpandIcon();
31982 this.ctNode.style.display = "";
31985 focus : function(){
31986 if(!this.node.preventHScroll){
31987 try{this.anchor.focus();
31989 }else if(!Roo.isIE){
31991 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
31992 var l = noscroll.scrollLeft;
31993 this.anchor.focus();
31994 noscroll.scrollLeft = l;
31999 toggleCheck : function(value){
32000 var cb = this.checkbox;
32002 cb.checked = (value === undefined ? !cb.checked : value);
32008 this.anchor.blur();
32012 animExpand : function(callback){
32013 var ct = Roo.get(this.ctNode);
32015 if(!this.node.hasChildNodes()){
32016 this.updateExpandIcon();
32017 this.ctNode.style.display = "";
32018 Roo.callback(callback);
32021 this.animating = true;
32022 this.updateExpandIcon();
32025 callback : function(){
32026 this.animating = false;
32027 Roo.callback(callback);
32030 duration: this.node.ownerTree.duration || .25
32034 highlight : function(){
32035 var tree = this.node.getOwnerTree();
32036 Roo.fly(this.wrap).highlight(
32037 tree.hlColor || "C3DAF9",
32038 {endColor: tree.hlBaseColor}
32042 collapse : function(){
32043 this.updateExpandIcon();
32044 this.ctNode.style.display = "none";
32047 animCollapse : function(callback){
32048 var ct = Roo.get(this.ctNode);
32049 ct.enableDisplayMode('block');
32052 this.animating = true;
32053 this.updateExpandIcon();
32056 callback : function(){
32057 this.animating = false;
32058 Roo.callback(callback);
32061 duration: this.node.ownerTree.duration || .25
32065 getContainer : function(){
32066 return this.ctNode;
32069 getEl : function(){
32073 appendDDGhost : function(ghostNode){
32074 ghostNode.appendChild(this.elNode.cloneNode(true));
32077 getDDRepairXY : function(){
32078 return Roo.lib.Dom.getXY(this.iconNode);
32081 onRender : function(){
32085 render : function(bulkRender){
32086 var n = this.node, a = n.attributes;
32087 var targetNode = n.parentNode ?
32088 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32090 if(!this.rendered){
32091 this.rendered = true;
32093 this.renderElements(n, a, targetNode, bulkRender);
32096 if(this.textNode.setAttributeNS){
32097 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32099 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32102 this.textNode.setAttribute("ext:qtip", a.qtip);
32104 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32107 }else if(a.qtipCfg){
32108 a.qtipCfg.target = Roo.id(this.textNode);
32109 Roo.QuickTips.register(a.qtipCfg);
32112 if(!this.node.expanded){
32113 this.updateExpandIcon();
32116 if(bulkRender === true) {
32117 targetNode.appendChild(this.wrap);
32122 renderElements : function(n, a, targetNode, bulkRender){
32123 // add some indent caching, this helps performance when rendering a large tree
32124 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32125 var t = n.getOwnerTree();
32126 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32127 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32128 var cb = typeof a.checked == 'boolean';
32129 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32130 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32131 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32132 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32133 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32134 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32135 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32136 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32137 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32138 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32141 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32142 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32143 n.nextSibling.ui.getEl(), buf.join(""));
32145 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32148 this.elNode = this.wrap.childNodes[0];
32149 this.ctNode = this.wrap.childNodes[1];
32150 var cs = this.elNode.childNodes;
32151 this.indentNode = cs[0];
32152 this.ecNode = cs[1];
32153 this.iconNode = cs[2];
32156 this.checkbox = cs[3];
32159 this.anchor = cs[index];
32160 this.textNode = cs[index].firstChild;
32163 getAnchor : function(){
32164 return this.anchor;
32167 getTextEl : function(){
32168 return this.textNode;
32171 getIconEl : function(){
32172 return this.iconNode;
32175 isChecked : function(){
32176 return this.checkbox ? this.checkbox.checked : false;
32179 updateExpandIcon : function(){
32181 var n = this.node, c1, c2;
32182 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32183 var hasChild = n.hasChildNodes();
32187 c1 = "x-tree-node-collapsed";
32188 c2 = "x-tree-node-expanded";
32191 c1 = "x-tree-node-expanded";
32192 c2 = "x-tree-node-collapsed";
32195 this.removeClass("x-tree-node-leaf");
32196 this.wasLeaf = false;
32198 if(this.c1 != c1 || this.c2 != c2){
32199 Roo.fly(this.elNode).replaceClass(c1, c2);
32200 this.c1 = c1; this.c2 = c2;
32204 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32207 this.wasLeaf = true;
32210 var ecc = "x-tree-ec-icon "+cls;
32211 if(this.ecc != ecc){
32212 this.ecNode.className = ecc;
32218 getChildIndent : function(){
32219 if(!this.childIndent){
32223 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32225 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32227 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32232 this.childIndent = buf.join("");
32234 return this.childIndent;
32237 renderIndent : function(){
32240 var p = this.node.parentNode;
32242 indent = p.ui.getChildIndent();
32244 if(this.indentMarkup != indent){ // don't rerender if not required
32245 this.indentNode.innerHTML = indent;
32246 this.indentMarkup = indent;
32248 this.updateExpandIcon();
32253 Roo.tree.RootTreeNodeUI = function(){
32254 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32256 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32257 render : function(){
32258 if(!this.rendered){
32259 var targetNode = this.node.ownerTree.innerCt.dom;
32260 this.node.expanded = true;
32261 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32262 this.wrap = this.ctNode = targetNode.firstChild;
32265 collapse : function(){
32267 expand : function(){
32271 * Ext JS Library 1.1.1
32272 * Copyright(c) 2006-2007, Ext JS, LLC.
32274 * Originally Released Under LGPL - original licence link has changed is not relivant.
32277 * <script type="text/javascript">
32280 * @class Roo.tree.TreeLoader
32281 * @extends Roo.util.Observable
32282 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32283 * nodes from a specified URL. The response must be a javascript Array definition
32284 * who's elements are node definition objects. eg:
32286 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32287 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32290 * A server request is sent, and child nodes are loaded only when a node is expanded.
32291 * The loading node's id is passed to the server under the parameter name "node" to
32292 * enable the server to produce the correct child nodes.
32294 * To pass extra parameters, an event handler may be attached to the "beforeload"
32295 * event, and the parameters specified in the TreeLoader's baseParams property:
32297 myTreeLoader.on("beforeload", function(treeLoader, node) {
32298 this.baseParams.category = node.attributes.category;
32301 * This would pass an HTTP parameter called "category" to the server containing
32302 * the value of the Node's "category" attribute.
32304 * Creates a new Treeloader.
32305 * @param {Object} config A config object containing config properties.
32307 Roo.tree.TreeLoader = function(config){
32308 this.baseParams = {};
32309 this.requestMethod = "POST";
32310 Roo.apply(this, config);
32315 * @event beforeload
32316 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32317 * @param {Object} This TreeLoader object.
32318 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32319 * @param {Object} callback The callback function specified in the {@link #load} call.
32324 * Fires when the node has been successfuly loaded.
32325 * @param {Object} This TreeLoader object.
32326 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32327 * @param {Object} response The response object containing the data from the server.
32331 * @event loadexception
32332 * Fires if the network request failed.
32333 * @param {Object} This TreeLoader object.
32334 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32335 * @param {Object} response The response object containing the data from the server.
32337 loadexception : true,
32340 * Fires before a node is created, enabling you to return custom Node types
32341 * @param {Object} This TreeLoader object.
32342 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32347 Roo.tree.TreeLoader.superclass.constructor.call(this);
32350 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32352 * @cfg {String} dataUrl The URL from which to request a Json string which
32353 * specifies an array of node definition object representing the child nodes
32357 * @cfg {Object} baseParams (optional) An object containing properties which
32358 * specify HTTP parameters to be passed to each request for child nodes.
32361 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32362 * created by this loader. If the attributes sent by the server have an attribute in this object,
32363 * they take priority.
32366 * @cfg {Object} uiProviders (optional) An object containing properties which
32368 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
32369 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32370 * <i>uiProvider</i> attribute of a returned child node is a string rather
32371 * than a reference to a TreeNodeUI implementation, this that string value
32372 * is used as a property name in the uiProviders object. You can define the provider named
32373 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32378 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32379 * child nodes before loading.
32381 clearOnLoad : true,
32384 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32385 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32386 * Grid query { data : [ .....] }
32391 * @cfg {String} queryParam (optional)
32392 * Name of the query as it will be passed on the querystring (defaults to 'node')
32393 * eg. the request will be ?node=[id]
32400 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32401 * This is called automatically when a node is expanded, but may be used to reload
32402 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32403 * @param {Roo.tree.TreeNode} node
32404 * @param {Function} callback
32406 load : function(node, callback){
32407 if(this.clearOnLoad){
32408 while(node.firstChild){
32409 node.removeChild(node.firstChild);
32412 if(node.attributes.children){ // preloaded json children
32413 var cs = node.attributes.children;
32414 for(var i = 0, len = cs.length; i < len; i++){
32415 node.appendChild(this.createNode(cs[i]));
32417 if(typeof callback == "function"){
32420 }else if(this.dataUrl){
32421 this.requestData(node, callback);
32425 getParams: function(node){
32426 var buf = [], bp = this.baseParams;
32427 for(var key in bp){
32428 if(typeof bp[key] != "function"){
32429 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32432 var n = this.queryParam === false ? 'node' : this.queryParam;
32433 buf.push(n + "=", encodeURIComponent(node.id));
32434 return buf.join("");
32437 requestData : function(node, callback){
32438 if(this.fireEvent("beforeload", this, node, callback) !== false){
32439 this.transId = Roo.Ajax.request({
32440 method:this.requestMethod,
32441 url: this.dataUrl||this.url,
32442 success: this.handleResponse,
32443 failure: this.handleFailure,
32445 argument: {callback: callback, node: node},
32446 params: this.getParams(node)
32449 // if the load is cancelled, make sure we notify
32450 // the node that we are done
32451 if(typeof callback == "function"){
32457 isLoading : function(){
32458 return this.transId ? true : false;
32461 abort : function(){
32462 if(this.isLoading()){
32463 Roo.Ajax.abort(this.transId);
32468 createNode : function(attr){
32469 // apply baseAttrs, nice idea Corey!
32470 if(this.baseAttrs){
32471 Roo.applyIf(attr, this.baseAttrs);
32473 if(this.applyLoader !== false){
32474 attr.loader = this;
32476 // uiProvider = depreciated..
32478 if(typeof(attr.uiProvider) == 'string'){
32479 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32480 /** eval:var:attr */ eval(attr.uiProvider);
32482 if(typeof(this.uiProviders['default']) != 'undefined') {
32483 attr.uiProvider = this.uiProviders['default'];
32486 this.fireEvent('create', this, attr);
32488 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32490 new Roo.tree.TreeNode(attr) :
32491 new Roo.tree.AsyncTreeNode(attr));
32494 processResponse : function(response, node, callback){
32495 var json = response.responseText;
32498 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32499 if (this.root !== false) {
32503 for(var i = 0, len = o.length; i < len; i++){
32504 var n = this.createNode(o[i]);
32506 node.appendChild(n);
32509 if(typeof callback == "function"){
32510 callback(this, node);
32513 this.handleFailure(response);
32517 handleResponse : function(response){
32518 this.transId = false;
32519 var a = response.argument;
32520 this.processResponse(response, a.node, a.callback);
32521 this.fireEvent("load", this, a.node, response);
32524 handleFailure : function(response){
32525 this.transId = false;
32526 var a = response.argument;
32527 this.fireEvent("loadexception", this, a.node, response);
32528 if(typeof a.callback == "function"){
32529 a.callback(this, a.node);
32534 * Ext JS Library 1.1.1
32535 * Copyright(c) 2006-2007, Ext JS, LLC.
32537 * Originally Released Under LGPL - original licence link has changed is not relivant.
32540 * <script type="text/javascript">
32544 * @class Roo.tree.TreeFilter
32545 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32546 * @param {TreePanel} tree
32547 * @param {Object} config (optional)
32549 Roo.tree.TreeFilter = function(tree, config){
32551 this.filtered = {};
32552 Roo.apply(this, config);
32555 Roo.tree.TreeFilter.prototype = {
32562 * Filter the data by a specific attribute.
32563 * @param {String/RegExp} value Either string that the attribute value
32564 * should start with or a RegExp to test against the attribute
32565 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32566 * @param {TreeNode} startNode (optional) The node to start the filter at.
32568 filter : function(value, attr, startNode){
32569 attr = attr || "text";
32571 if(typeof value == "string"){
32572 var vlen = value.length;
32573 // auto clear empty filter
32574 if(vlen == 0 && this.clearBlank){
32578 value = value.toLowerCase();
32580 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32582 }else if(value.exec){ // regex?
32584 return value.test(n.attributes[attr]);
32587 throw 'Illegal filter type, must be string or regex';
32589 this.filterBy(f, null, startNode);
32593 * Filter by a function. The passed function will be called with each
32594 * node in the tree (or from the startNode). If the function returns true, the node is kept
32595 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32596 * @param {Function} fn The filter function
32597 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32599 filterBy : function(fn, scope, startNode){
32600 startNode = startNode || this.tree.root;
32601 if(this.autoClear){
32604 var af = this.filtered, rv = this.reverse;
32605 var f = function(n){
32606 if(n == startNode){
32612 var m = fn.call(scope || n, n);
32620 startNode.cascade(f);
32623 if(typeof id != "function"){
32625 if(n && n.parentNode){
32626 n.parentNode.removeChild(n);
32634 * Clears the current filter. Note: with the "remove" option
32635 * set a filter cannot be cleared.
32637 clear : function(){
32639 var af = this.filtered;
32641 if(typeof id != "function"){
32648 this.filtered = {};
32653 * Ext JS Library 1.1.1
32654 * Copyright(c) 2006-2007, Ext JS, LLC.
32656 * Originally Released Under LGPL - original licence link has changed is not relivant.
32659 * <script type="text/javascript">
32664 * @class Roo.tree.TreeSorter
32665 * Provides sorting of nodes in a TreePanel
32667 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32668 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32669 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32670 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32671 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32672 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32674 * @param {TreePanel} tree
32675 * @param {Object} config
32677 Roo.tree.TreeSorter = function(tree, config){
32678 Roo.apply(this, config);
32679 tree.on("beforechildrenrendered", this.doSort, this);
32680 tree.on("append", this.updateSort, this);
32681 tree.on("insert", this.updateSort, this);
32683 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32684 var p = this.property || "text";
32685 var sortType = this.sortType;
32686 var fs = this.folderSort;
32687 var cs = this.caseSensitive === true;
32688 var leafAttr = this.leafAttr || 'leaf';
32690 this.sortFn = function(n1, n2){
32692 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32695 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
32699 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
32700 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
32702 return dsc ? +1 : -1;
32704 return dsc ? -1 : +1;
32711 Roo.tree.TreeSorter.prototype = {
32712 doSort : function(node){
32713 node.sort(this.sortFn);
32716 compareNodes : function(n1, n2){
32717 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
32720 updateSort : function(tree, node){
32721 if(node.childrenRendered){
32722 this.doSort.defer(1, this, [node]);
32727 * Ext JS Library 1.1.1
32728 * Copyright(c) 2006-2007, Ext JS, LLC.
32730 * Originally Released Under LGPL - original licence link has changed is not relivant.
32733 * <script type="text/javascript">
32736 if(Roo.dd.DropZone){
32738 Roo.tree.TreeDropZone = function(tree, config){
32739 this.allowParentInsert = false;
32740 this.allowContainerDrop = false;
32741 this.appendOnly = false;
32742 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
32744 this.lastInsertClass = "x-tree-no-status";
32745 this.dragOverData = {};
32748 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
32749 ddGroup : "TreeDD",
32751 expandDelay : 1000,
32753 expandNode : function(node){
32754 if(node.hasChildNodes() && !node.isExpanded()){
32755 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
32759 queueExpand : function(node){
32760 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
32763 cancelExpand : function(){
32764 if(this.expandProcId){
32765 clearTimeout(this.expandProcId);
32766 this.expandProcId = false;
32770 isValidDropPoint : function(n, pt, dd, e, data){
32771 if(!n || !data){ return false; }
32772 var targetNode = n.node;
32773 var dropNode = data.node;
32774 // default drop rules
32775 if(!(targetNode && targetNode.isTarget && pt)){
32778 if(pt == "append" && targetNode.allowChildren === false){
32781 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
32784 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
32787 // reuse the object
32788 var overEvent = this.dragOverData;
32789 overEvent.tree = this.tree;
32790 overEvent.target = targetNode;
32791 overEvent.data = data;
32792 overEvent.point = pt;
32793 overEvent.source = dd;
32794 overEvent.rawEvent = e;
32795 overEvent.dropNode = dropNode;
32796 overEvent.cancel = false;
32797 var result = this.tree.fireEvent("nodedragover", overEvent);
32798 return overEvent.cancel === false && result !== false;
32801 getDropPoint : function(e, n, dd){
32804 return tn.allowChildren !== false ? "append" : false; // always append for root
32806 var dragEl = n.ddel;
32807 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
32808 var y = Roo.lib.Event.getPageY(e);
32809 var noAppend = tn.allowChildren === false || tn.isLeaf();
32810 if(this.appendOnly || tn.parentNode.allowChildren === false){
32811 return noAppend ? false : "append";
32813 var noBelow = false;
32814 if(!this.allowParentInsert){
32815 noBelow = tn.hasChildNodes() && tn.isExpanded();
32817 var q = (b - t) / (noAppend ? 2 : 3);
32818 if(y >= t && y < (t + q)){
32820 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
32827 onNodeEnter : function(n, dd, e, data){
32828 this.cancelExpand();
32831 onNodeOver : function(n, dd, e, data){
32832 var pt = this.getDropPoint(e, n, dd);
32835 // auto node expand check
32836 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
32837 this.queueExpand(node);
32838 }else if(pt != "append"){
32839 this.cancelExpand();
32842 // set the insert point style on the target node
32843 var returnCls = this.dropNotAllowed;
32844 if(this.isValidDropPoint(n, pt, dd, e, data)){
32849 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
32850 cls = "x-tree-drag-insert-above";
32851 }else if(pt == "below"){
32852 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
32853 cls = "x-tree-drag-insert-below";
32855 returnCls = "x-tree-drop-ok-append";
32856 cls = "x-tree-drag-append";
32858 if(this.lastInsertClass != cls){
32859 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
32860 this.lastInsertClass = cls;
32867 onNodeOut : function(n, dd, e, data){
32868 this.cancelExpand();
32869 this.removeDropIndicators(n);
32872 onNodeDrop : function(n, dd, e, data){
32873 var point = this.getDropPoint(e, n, dd);
32874 var targetNode = n.node;
32875 targetNode.ui.startDrop();
32876 if(!this.isValidDropPoint(n, point, dd, e, data)){
32877 targetNode.ui.endDrop();
32880 // first try to find the drop node
32881 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
32884 target: targetNode,
32889 dropNode: dropNode,
32892 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
32893 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
32894 targetNode.ui.endDrop();
32897 // allow target changing
32898 targetNode = dropEvent.target;
32899 if(point == "append" && !targetNode.isExpanded()){
32900 targetNode.expand(false, null, function(){
32901 this.completeDrop(dropEvent);
32902 }.createDelegate(this));
32904 this.completeDrop(dropEvent);
32909 completeDrop : function(de){
32910 var ns = de.dropNode, p = de.point, t = de.target;
32911 if(!(ns instanceof Array)){
32915 for(var i = 0, len = ns.length; i < len; i++){
32918 t.parentNode.insertBefore(n, t);
32919 }else if(p == "below"){
32920 t.parentNode.insertBefore(n, t.nextSibling);
32926 if(this.tree.hlDrop){
32930 this.tree.fireEvent("nodedrop", de);
32933 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
32934 if(this.tree.hlDrop){
32935 dropNode.ui.focus();
32936 dropNode.ui.highlight();
32938 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
32941 getTree : function(){
32945 removeDropIndicators : function(n){
32948 Roo.fly(el).removeClass([
32949 "x-tree-drag-insert-above",
32950 "x-tree-drag-insert-below",
32951 "x-tree-drag-append"]);
32952 this.lastInsertClass = "_noclass";
32956 beforeDragDrop : function(target, e, id){
32957 this.cancelExpand();
32961 afterRepair : function(data){
32962 if(data && Roo.enableFx){
32963 data.node.ui.highlight();
32971 * Ext JS Library 1.1.1
32972 * Copyright(c) 2006-2007, Ext JS, LLC.
32974 * Originally Released Under LGPL - original licence link has changed is not relivant.
32977 * <script type="text/javascript">
32981 if(Roo.dd.DragZone){
32982 Roo.tree.TreeDragZone = function(tree, config){
32983 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
32987 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
32988 ddGroup : "TreeDD",
32990 onBeforeDrag : function(data, e){
32992 return n && n.draggable && !n.disabled;
32995 onInitDrag : function(e){
32996 var data = this.dragData;
32997 this.tree.getSelectionModel().select(data.node);
32998 this.proxy.update("");
32999 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33000 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33003 getRepairXY : function(e, data){
33004 return data.node.ui.getDDRepairXY();
33007 onEndDrag : function(data, e){
33008 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33011 onValidDrop : function(dd, e, id){
33012 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33016 beforeInvalidDrop : function(e, id){
33017 // this scrolls the original position back into view
33018 var sm = this.tree.getSelectionModel();
33019 sm.clearSelections();
33020 sm.select(this.dragData.node);
33025 * Ext JS Library 1.1.1
33026 * Copyright(c) 2006-2007, Ext JS, LLC.
33028 * Originally Released Under LGPL - original licence link has changed is not relivant.
33031 * <script type="text/javascript">
33034 * @class Roo.tree.TreeEditor
33035 * @extends Roo.Editor
33036 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33037 * as the editor field.
33039 * @param {TreePanel} tree
33040 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33042 Roo.tree.TreeEditor = function(tree, config){
33043 config = config || {};
33044 var field = config.events ? config : new Roo.form.TextField(config);
33045 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
33049 tree.on('beforeclick', this.beforeNodeClick, this);
33050 tree.getTreeEl().on('mousedown', this.hide, this);
33051 this.on('complete', this.updateNode, this);
33052 this.on('beforestartedit', this.fitToTree, this);
33053 this.on('startedit', this.bindScroll, this, {delay:10});
33054 this.on('specialkey', this.onSpecialKey, this);
33057 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33059 * @cfg {String} alignment
33060 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33066 * @cfg {Boolean} hideEl
33067 * True to hide the bound element while the editor is displayed (defaults to false)
33071 * @cfg {String} cls
33072 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33074 cls: "x-small-editor x-tree-editor",
33076 * @cfg {Boolean} shim
33077 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33083 * @cfg {Number} maxWidth
33084 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33085 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33086 * scroll and client offsets into account prior to each edit.
33093 fitToTree : function(ed, el){
33094 var td = this.tree.getTreeEl().dom, nd = el.dom;
33095 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33096 td.scrollLeft = nd.offsetLeft;
33100 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33101 this.setSize(w, '');
33105 triggerEdit : function(node){
33106 this.completeEdit();
33107 this.editNode = node;
33108 this.startEdit(node.ui.textNode, node.text);
33112 bindScroll : function(){
33113 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33117 beforeNodeClick : function(node, e){
33118 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33119 this.lastClick = new Date();
33120 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33122 this.triggerEdit(node);
33128 updateNode : function(ed, value){
33129 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33130 this.editNode.setText(value);
33134 onHide : function(){
33135 Roo.tree.TreeEditor.superclass.onHide.call(this);
33137 this.editNode.ui.focus();
33142 onSpecialKey : function(field, e){
33143 var k = e.getKey();
33147 }else if(k == e.ENTER && !e.hasModifier()){
33149 this.completeEdit();
33152 });//<Script type="text/javascript">
33155 * Ext JS Library 1.1.1
33156 * Copyright(c) 2006-2007, Ext JS, LLC.
33158 * Originally Released Under LGPL - original licence link has changed is not relivant.
33161 * <script type="text/javascript">
33165 * Not documented??? - probably should be...
33168 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33169 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33171 renderElements : function(n, a, targetNode, bulkRender){
33172 //consel.log("renderElements?");
33173 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33175 var t = n.getOwnerTree();
33176 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33178 var cols = t.columns;
33179 var bw = t.borderWidth;
33181 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33182 var cb = typeof a.checked == "boolean";
33183 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33184 var colcls = 'x-t-' + tid + '-c0';
33186 '<li class="x-tree-node">',
33189 '<div class="x-tree-node-el ', a.cls,'">',
33191 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33194 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33195 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33196 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33197 (a.icon ? ' x-tree-node-inline-icon' : ''),
33198 (a.iconCls ? ' '+a.iconCls : ''),
33199 '" unselectable="on" />',
33200 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33201 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33203 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33204 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33205 '<span unselectable="on" qtip="' + tx + '">',
33209 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33210 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33213 for(var i = 1, len = cols.length; i < len; i++){
33215 colcls = 'x-t-' + tid + '-c' +i;
33216 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33217 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33218 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33224 '<div class="x-clear"></div></div>',
33225 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33228 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33229 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33230 n.nextSibling.ui.getEl(), buf.join(""));
33232 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33234 var el = this.wrap.firstChild;
33236 this.elNode = el.firstChild;
33237 this.ranchor = el.childNodes[1];
33238 this.ctNode = this.wrap.childNodes[1];
33239 var cs = el.firstChild.childNodes;
33240 this.indentNode = cs[0];
33241 this.ecNode = cs[1];
33242 this.iconNode = cs[2];
33245 this.checkbox = cs[3];
33248 this.anchor = cs[index];
33250 this.textNode = cs[index].firstChild;
33252 //el.on("click", this.onClick, this);
33253 //el.on("dblclick", this.onDblClick, this);
33256 // console.log(this);
33258 initEvents : function(){
33259 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33262 var a = this.ranchor;
33264 var el = Roo.get(a);
33266 if(Roo.isOpera){ // opera render bug ignores the CSS
33267 el.setStyle("text-decoration", "none");
33270 el.on("click", this.onClick, this);
33271 el.on("dblclick", this.onDblClick, this);
33272 el.on("contextmenu", this.onContextMenu, this);
33276 /*onSelectedChange : function(state){
33279 this.addClass("x-tree-selected");
33282 this.removeClass("x-tree-selected");
33285 addClass : function(cls){
33287 Roo.fly(this.elRow).addClass(cls);
33293 removeClass : function(cls){
33295 Roo.fly(this.elRow).removeClass(cls);
33301 });//<Script type="text/javascript">
33305 * Ext JS Library 1.1.1
33306 * Copyright(c) 2006-2007, Ext JS, LLC.
33308 * Originally Released Under LGPL - original licence link has changed is not relivant.
33311 * <script type="text/javascript">
33316 * @class Roo.tree.ColumnTree
33317 * @extends Roo.data.TreePanel
33318 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33319 * @cfg {int} borderWidth compined right/left border allowance
33321 * @param {String/HTMLElement/Element} el The container element
33322 * @param {Object} config
33324 Roo.tree.ColumnTree = function(el, config)
33326 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33330 * Fire this event on a container when it resizes
33331 * @param {int} w Width
33332 * @param {int} h Height
33336 this.on('resize', this.onResize, this);
33339 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33343 borderWidth: Roo.isBorderBox ? 0 : 2,
33346 render : function(){
33347 // add the header.....
33349 Roo.tree.ColumnTree.superclass.render.apply(this);
33351 this.el.addClass('x-column-tree');
33353 this.headers = this.el.createChild(
33354 {cls:'x-tree-headers'},this.innerCt.dom);
33356 var cols = this.columns, c;
33357 var totalWidth = 0;
33359 var len = cols.length;
33360 for(var i = 0; i < len; i++){
33362 totalWidth += c.width;
33363 this.headEls.push(this.headers.createChild({
33364 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33366 cls:'x-tree-hd-text',
33369 style:'width:'+(c.width-this.borderWidth)+'px;'
33372 this.headers.createChild({cls:'x-clear'});
33373 // prevent floats from wrapping when clipped
33374 this.headers.setWidth(totalWidth);
33375 //this.innerCt.setWidth(totalWidth);
33376 this.innerCt.setStyle({ overflow: 'auto' });
33377 this.onResize(this.width, this.height);
33381 onResize : function(w,h)
33386 this.innerCt.setWidth(this.width);
33387 this.innerCt.setHeight(this.height-20);
33390 var cols = this.columns, c;
33391 var totalWidth = 0;
33393 var len = cols.length;
33394 for(var i = 0; i < len; i++){
33396 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33397 // it's the expander..
33398 expEl = this.headEls[i];
33401 totalWidth += c.width;
33405 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33407 this.headers.setWidth(w-20);
33416 * Ext JS Library 1.1.1
33417 * Copyright(c) 2006-2007, Ext JS, LLC.
33419 * Originally Released Under LGPL - original licence link has changed is not relivant.
33422 * <script type="text/javascript">
33426 * @class Roo.menu.Menu
33427 * @extends Roo.util.Observable
33428 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33429 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33431 * Creates a new Menu
33432 * @param {Object} config Configuration options
33434 Roo.menu.Menu = function(config){
33435 Roo.apply(this, config);
33436 this.id = this.id || Roo.id();
33439 * @event beforeshow
33440 * Fires before this menu is displayed
33441 * @param {Roo.menu.Menu} this
33445 * @event beforehide
33446 * Fires before this menu is hidden
33447 * @param {Roo.menu.Menu} this
33452 * Fires after this menu is displayed
33453 * @param {Roo.menu.Menu} this
33458 * Fires after this menu is hidden
33459 * @param {Roo.menu.Menu} this
33464 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33465 * @param {Roo.menu.Menu} this
33466 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33467 * @param {Roo.EventObject} e
33472 * Fires when the mouse is hovering over this menu
33473 * @param {Roo.menu.Menu} this
33474 * @param {Roo.EventObject} e
33475 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33480 * Fires when the mouse exits this menu
33481 * @param {Roo.menu.Menu} this
33482 * @param {Roo.EventObject} e
33483 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33488 * Fires when a menu item contained in this menu is clicked
33489 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33490 * @param {Roo.EventObject} e
33494 if (this.registerMenu) {
33495 Roo.menu.MenuMgr.register(this);
33498 var mis = this.items;
33499 this.items = new Roo.util.MixedCollection();
33501 this.add.apply(this, mis);
33505 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33507 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33511 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33512 * for bottom-right shadow (defaults to "sides")
33516 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33517 * this menu (defaults to "tl-tr?")
33519 subMenuAlign : "tl-tr?",
33521 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33522 * relative to its element of origin (defaults to "tl-bl?")
33524 defaultAlign : "tl-bl?",
33526 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33528 allowOtherMenus : false,
33530 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33532 registerMenu : true,
33537 render : function(){
33541 var el = this.el = new Roo.Layer({
33543 shadow:this.shadow,
33545 parentEl: this.parentEl || document.body,
33549 this.keyNav = new Roo.menu.MenuNav(this);
33552 el.addClass("x-menu-plain");
33555 el.addClass(this.cls);
33557 // generic focus element
33558 this.focusEl = el.createChild({
33559 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33561 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33562 ul.on("click", this.onClick, this);
33563 ul.on("mouseover", this.onMouseOver, this);
33564 ul.on("mouseout", this.onMouseOut, this);
33565 this.items.each(function(item){
33566 var li = document.createElement("li");
33567 li.className = "x-menu-list-item";
33568 ul.dom.appendChild(li);
33569 item.render(li, this);
33576 autoWidth : function(){
33577 var el = this.el, ul = this.ul;
33581 var w = this.width;
33584 }else if(Roo.isIE){
33585 el.setWidth(this.minWidth);
33586 var t = el.dom.offsetWidth; // force recalc
33587 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33592 delayAutoWidth : function(){
33595 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33597 this.awTask.delay(20);
33602 findTargetItem : function(e){
33603 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33604 if(t && t.menuItemId){
33605 return this.items.get(t.menuItemId);
33610 onClick : function(e){
33612 if(t = this.findTargetItem(e)){
33614 this.fireEvent("click", this, t, e);
33619 setActiveItem : function(item, autoExpand){
33620 if(item != this.activeItem){
33621 if(this.activeItem){
33622 this.activeItem.deactivate();
33624 this.activeItem = item;
33625 item.activate(autoExpand);
33626 }else if(autoExpand){
33632 tryActivate : function(start, step){
33633 var items = this.items;
33634 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33635 var item = items.get(i);
33636 if(!item.disabled && item.canActivate){
33637 this.setActiveItem(item, false);
33645 onMouseOver : function(e){
33647 if(t = this.findTargetItem(e)){
33648 if(t.canActivate && !t.disabled){
33649 this.setActiveItem(t, true);
33652 this.fireEvent("mouseover", this, e, t);
33656 onMouseOut : function(e){
33658 if(t = this.findTargetItem(e)){
33659 if(t == this.activeItem && t.shouldDeactivate(e)){
33660 this.activeItem.deactivate();
33661 delete this.activeItem;
33664 this.fireEvent("mouseout", this, e, t);
33668 * Read-only. Returns true if the menu is currently displayed, else false.
33671 isVisible : function(){
33672 return this.el && !this.hidden;
33676 * Displays this menu relative to another element
33677 * @param {String/HTMLElement/Roo.Element} element The element to align to
33678 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33679 * the element (defaults to this.defaultAlign)
33680 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33682 show : function(el, pos, parentMenu){
33683 this.parentMenu = parentMenu;
33687 this.fireEvent("beforeshow", this);
33688 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33692 * Displays this menu at a specific xy position
33693 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
33694 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33696 showAt : function(xy, parentMenu, /* private: */_e){
33697 this.parentMenu = parentMenu;
33702 this.fireEvent("beforeshow", this);
33703 xy = this.el.adjustForConstraints(xy);
33707 this.hidden = false;
33709 this.fireEvent("show", this);
33712 focus : function(){
33714 this.doFocus.defer(50, this);
33718 doFocus : function(){
33720 this.focusEl.focus();
33725 * Hides this menu and optionally all parent menus
33726 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
33728 hide : function(deep){
33729 if(this.el && this.isVisible()){
33730 this.fireEvent("beforehide", this);
33731 if(this.activeItem){
33732 this.activeItem.deactivate();
33733 this.activeItem = null;
33736 this.hidden = true;
33737 this.fireEvent("hide", this);
33739 if(deep === true && this.parentMenu){
33740 this.parentMenu.hide(true);
33745 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
33746 * Any of the following are valid:
33748 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
33749 * <li>An HTMLElement object which will be converted to a menu item</li>
33750 * <li>A menu item config object that will be created as a new menu item</li>
33751 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
33752 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
33757 var menu = new Roo.menu.Menu();
33759 // Create a menu item to add by reference
33760 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
33762 // Add a bunch of items at once using different methods.
33763 // Only the last item added will be returned.
33764 var item = menu.add(
33765 menuItem, // add existing item by ref
33766 'Dynamic Item', // new TextItem
33767 '-', // new separator
33768 { text: 'Config Item' } // new item by config
33771 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
33772 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
33775 var a = arguments, l = a.length, item;
33776 for(var i = 0; i < l; i++){
33778 if(el.render){ // some kind of Item
33779 item = this.addItem(el);
33780 }else if(typeof el == "string"){ // string
33781 if(el == "separator" || el == "-"){
33782 item = this.addSeparator();
33784 item = this.addText(el);
33786 }else if(el.tagName || el.el){ // element
33787 item = this.addElement(el);
33788 }else if(typeof el == "object"){ // must be menu item config?
33789 item = this.addMenuItem(el);
33796 * Returns this menu's underlying {@link Roo.Element} object
33797 * @return {Roo.Element} The element
33799 getEl : function(){
33807 * Adds a separator bar to the menu
33808 * @return {Roo.menu.Item} The menu item that was added
33810 addSeparator : function(){
33811 return this.addItem(new Roo.menu.Separator());
33815 * Adds an {@link Roo.Element} object to the menu
33816 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
33817 * @return {Roo.menu.Item} The menu item that was added
33819 addElement : function(el){
33820 return this.addItem(new Roo.menu.BaseItem(el));
33824 * Adds an existing object based on {@link Roo.menu.Item} to the menu
33825 * @param {Roo.menu.Item} item The menu item to add
33826 * @return {Roo.menu.Item} The menu item that was added
33828 addItem : function(item){
33829 this.items.add(item);
33831 var li = document.createElement("li");
33832 li.className = "x-menu-list-item";
33833 this.ul.dom.appendChild(li);
33834 item.render(li, this);
33835 this.delayAutoWidth();
33841 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
33842 * @param {Object} config A MenuItem config object
33843 * @return {Roo.menu.Item} The menu item that was added
33845 addMenuItem : function(config){
33846 if(!(config instanceof Roo.menu.Item)){
33847 if(typeof config.checked == "boolean"){ // must be check menu item config?
33848 config = new Roo.menu.CheckItem(config);
33850 config = new Roo.menu.Item(config);
33853 return this.addItem(config);
33857 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
33858 * @param {String} text The text to display in the menu item
33859 * @return {Roo.menu.Item} The menu item that was added
33861 addText : function(text){
33862 return this.addItem(new Roo.menu.TextItem(text));
33866 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
33867 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
33868 * @param {Roo.menu.Item} item The menu item to add
33869 * @return {Roo.menu.Item} The menu item that was added
33871 insert : function(index, item){
33872 this.items.insert(index, item);
33874 var li = document.createElement("li");
33875 li.className = "x-menu-list-item";
33876 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
33877 item.render(li, this);
33878 this.delayAutoWidth();
33884 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
33885 * @param {Roo.menu.Item} item The menu item to remove
33887 remove : function(item){
33888 this.items.removeKey(item.id);
33893 * Removes and destroys all items in the menu
33895 removeAll : function(){
33897 while(f = this.items.first()){
33903 // MenuNav is a private utility class used internally by the Menu
33904 Roo.menu.MenuNav = function(menu){
33905 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
33906 this.scope = this.menu = menu;
33909 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
33910 doRelay : function(e, h){
33911 var k = e.getKey();
33912 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
33913 this.menu.tryActivate(0, 1);
33916 return h.call(this.scope || this, e, this.menu);
33919 up : function(e, m){
33920 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
33921 m.tryActivate(m.items.length-1, -1);
33925 down : function(e, m){
33926 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
33927 m.tryActivate(0, 1);
33931 right : function(e, m){
33933 m.activeItem.expandMenu(true);
33937 left : function(e, m){
33939 if(m.parentMenu && m.parentMenu.activeItem){
33940 m.parentMenu.activeItem.activate();
33944 enter : function(e, m){
33946 e.stopPropagation();
33947 m.activeItem.onClick(e);
33948 m.fireEvent("click", this, m.activeItem);
33954 * Ext JS Library 1.1.1
33955 * Copyright(c) 2006-2007, Ext JS, LLC.
33957 * Originally Released Under LGPL - original licence link has changed is not relivant.
33960 * <script type="text/javascript">
33964 * @class Roo.menu.MenuMgr
33965 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
33968 Roo.menu.MenuMgr = function(){
33969 var menus, active, groups = {}, attached = false, lastShow = new Date();
33971 // private - called when first menu is created
33974 active = new Roo.util.MixedCollection();
33975 Roo.get(document).addKeyListener(27, function(){
33976 if(active.length > 0){
33983 function hideAll(){
33984 if(active && active.length > 0){
33985 var c = active.clone();
33986 c.each(function(m){
33993 function onHide(m){
33995 if(active.length < 1){
33996 Roo.get(document).un("mousedown", onMouseDown);
34002 function onShow(m){
34003 var last = active.last();
34004 lastShow = new Date();
34007 Roo.get(document).on("mousedown", onMouseDown);
34011 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34012 m.parentMenu.activeChild = m;
34013 }else if(last && last.isVisible()){
34014 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34019 function onBeforeHide(m){
34021 m.activeChild.hide();
34023 if(m.autoHideTimer){
34024 clearTimeout(m.autoHideTimer);
34025 delete m.autoHideTimer;
34030 function onBeforeShow(m){
34031 var pm = m.parentMenu;
34032 if(!pm && !m.allowOtherMenus){
34034 }else if(pm && pm.activeChild && active != m){
34035 pm.activeChild.hide();
34040 function onMouseDown(e){
34041 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34047 function onBeforeCheck(mi, state){
34049 var g = groups[mi.group];
34050 for(var i = 0, l = g.length; i < l; i++){
34052 g[i].setChecked(false);
34061 * Hides all menus that are currently visible
34063 hideAll : function(){
34068 register : function(menu){
34072 menus[menu.id] = menu;
34073 menu.on("beforehide", onBeforeHide);
34074 menu.on("hide", onHide);
34075 menu.on("beforeshow", onBeforeShow);
34076 menu.on("show", onShow);
34077 var g = menu.group;
34078 if(g && menu.events["checkchange"]){
34082 groups[g].push(menu);
34083 menu.on("checkchange", onCheck);
34088 * Returns a {@link Roo.menu.Menu} object
34089 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34090 * be used to generate and return a new Menu instance.
34092 get : function(menu){
34093 if(typeof menu == "string"){ // menu id
34094 return menus[menu];
34095 }else if(menu.events){ // menu instance
34097 }else if(typeof menu.length == 'number'){ // array of menu items?
34098 return new Roo.menu.Menu({items:menu});
34099 }else{ // otherwise, must be a config
34100 return new Roo.menu.Menu(menu);
34105 unregister : function(menu){
34106 delete menus[menu.id];
34107 menu.un("beforehide", onBeforeHide);
34108 menu.un("hide", onHide);
34109 menu.un("beforeshow", onBeforeShow);
34110 menu.un("show", onShow);
34111 var g = menu.group;
34112 if(g && menu.events["checkchange"]){
34113 groups[g].remove(menu);
34114 menu.un("checkchange", onCheck);
34119 registerCheckable : function(menuItem){
34120 var g = menuItem.group;
34125 groups[g].push(menuItem);
34126 menuItem.on("beforecheckchange", onBeforeCheck);
34131 unregisterCheckable : function(menuItem){
34132 var g = menuItem.group;
34134 groups[g].remove(menuItem);
34135 menuItem.un("beforecheckchange", onBeforeCheck);
34141 * Ext JS Library 1.1.1
34142 * Copyright(c) 2006-2007, Ext JS, LLC.
34144 * Originally Released Under LGPL - original licence link has changed is not relivant.
34147 * <script type="text/javascript">
34152 * @class Roo.menu.BaseItem
34153 * @extends Roo.Component
34154 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34155 * management and base configuration options shared by all menu components.
34157 * Creates a new BaseItem
34158 * @param {Object} config Configuration options
34160 Roo.menu.BaseItem = function(config){
34161 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34166 * Fires when this item is clicked
34167 * @param {Roo.menu.BaseItem} this
34168 * @param {Roo.EventObject} e
34173 * Fires when this item is activated
34174 * @param {Roo.menu.BaseItem} this
34178 * @event deactivate
34179 * Fires when this item is deactivated
34180 * @param {Roo.menu.BaseItem} this
34186 this.on("click", this.handler, this.scope, true);
34190 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34192 * @cfg {Function} handler
34193 * A function that will handle the click event of this menu item (defaults to undefined)
34196 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34198 canActivate : false,
34200 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34202 activeClass : "x-menu-item-active",
34204 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34206 hideOnClick : true,
34208 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34213 ctype: "Roo.menu.BaseItem",
34216 actionMode : "container",
34219 render : function(container, parentMenu){
34220 this.parentMenu = parentMenu;
34221 Roo.menu.BaseItem.superclass.render.call(this, container);
34222 this.container.menuItemId = this.id;
34226 onRender : function(container, position){
34227 this.el = Roo.get(this.el);
34228 container.dom.appendChild(this.el.dom);
34232 onClick : function(e){
34233 if(!this.disabled && this.fireEvent("click", this, e) !== false
34234 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34235 this.handleClick(e);
34242 activate : function(){
34246 var li = this.container;
34247 li.addClass(this.activeClass);
34248 this.region = li.getRegion().adjust(2, 2, -2, -2);
34249 this.fireEvent("activate", this);
34254 deactivate : function(){
34255 this.container.removeClass(this.activeClass);
34256 this.fireEvent("deactivate", this);
34260 shouldDeactivate : function(e){
34261 return !this.region || !this.region.contains(e.getPoint());
34265 handleClick : function(e){
34266 if(this.hideOnClick){
34267 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34272 expandMenu : function(autoActivate){
34277 hideMenu : function(){
34282 * Ext JS Library 1.1.1
34283 * Copyright(c) 2006-2007, Ext JS, LLC.
34285 * Originally Released Under LGPL - original licence link has changed is not relivant.
34288 * <script type="text/javascript">
34292 * @class Roo.menu.Adapter
34293 * @extends Roo.menu.BaseItem
34294 * 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.
34295 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34297 * Creates a new Adapter
34298 * @param {Object} config Configuration options
34300 Roo.menu.Adapter = function(component, config){
34301 Roo.menu.Adapter.superclass.constructor.call(this, config);
34302 this.component = component;
34304 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34306 canActivate : true,
34309 onRender : function(container, position){
34310 this.component.render(container);
34311 this.el = this.component.getEl();
34315 activate : function(){
34319 this.component.focus();
34320 this.fireEvent("activate", this);
34325 deactivate : function(){
34326 this.fireEvent("deactivate", this);
34330 disable : function(){
34331 this.component.disable();
34332 Roo.menu.Adapter.superclass.disable.call(this);
34336 enable : function(){
34337 this.component.enable();
34338 Roo.menu.Adapter.superclass.enable.call(this);
34342 * Ext JS Library 1.1.1
34343 * Copyright(c) 2006-2007, Ext JS, LLC.
34345 * Originally Released Under LGPL - original licence link has changed is not relivant.
34348 * <script type="text/javascript">
34352 * @class Roo.menu.TextItem
34353 * @extends Roo.menu.BaseItem
34354 * Adds a static text string to a menu, usually used as either a heading or group separator.
34356 * Creates a new TextItem
34357 * @param {String} text The text to display
34359 Roo.menu.TextItem = function(text){
34361 Roo.menu.TextItem.superclass.constructor.call(this);
34364 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34366 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34368 hideOnClick : false,
34370 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34372 itemCls : "x-menu-text",
34375 onRender : function(){
34376 var s = document.createElement("span");
34377 s.className = this.itemCls;
34378 s.innerHTML = this.text;
34380 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
34384 * Ext JS Library 1.1.1
34385 * Copyright(c) 2006-2007, Ext JS, LLC.
34387 * Originally Released Under LGPL - original licence link has changed is not relivant.
34390 * <script type="text/javascript">
34394 * @class Roo.menu.Separator
34395 * @extends Roo.menu.BaseItem
34396 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34397 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34399 * @param {Object} config Configuration options
34401 Roo.menu.Separator = function(config){
34402 Roo.menu.Separator.superclass.constructor.call(this, config);
34405 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34407 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34409 itemCls : "x-menu-sep",
34411 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34413 hideOnClick : false,
34416 onRender : function(li){
34417 var s = document.createElement("span");
34418 s.className = this.itemCls;
34419 s.innerHTML = " ";
34421 li.addClass("x-menu-sep-li");
34422 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34426 * Ext JS Library 1.1.1
34427 * Copyright(c) 2006-2007, Ext JS, LLC.
34429 * Originally Released Under LGPL - original licence link has changed is not relivant.
34432 * <script type="text/javascript">
34435 * @class Roo.menu.Item
34436 * @extends Roo.menu.BaseItem
34437 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34438 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34439 * activation and click handling.
34441 * Creates a new Item
34442 * @param {Object} config Configuration options
34444 Roo.menu.Item = function(config){
34445 Roo.menu.Item.superclass.constructor.call(this, config);
34447 this.menu = Roo.menu.MenuMgr.get(this.menu);
34450 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34452 * @cfg {String} icon
34453 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34456 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34458 itemCls : "x-menu-item",
34460 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34462 canActivate : true,
34464 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34467 // doc'd in BaseItem
34471 ctype: "Roo.menu.Item",
34474 onRender : function(container, position){
34475 var el = document.createElement("a");
34476 el.hideFocus = true;
34477 el.unselectable = "on";
34478 el.href = this.href || "#";
34479 if(this.hrefTarget){
34480 el.target = this.hrefTarget;
34482 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34483 el.innerHTML = String.format(
34484 '<img src="{0}" class="x-menu-item-icon {2}" />{1}',
34485 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || '');
34487 Roo.menu.Item.superclass.onRender.call(this, container, position);
34491 * Sets the text to display in this menu item
34492 * @param {String} text The text to display
34494 setText : function(text){
34497 this.el.update(String.format(
34498 '<img src="{0}" class="x-menu-item-icon {2}">{1}',
34499 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34500 this.parentMenu.autoWidth();
34505 handleClick : function(e){
34506 if(!this.href){ // if no link defined, stop the event automatically
34509 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34513 activate : function(autoExpand){
34514 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34524 shouldDeactivate : function(e){
34525 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34526 if(this.menu && this.menu.isVisible()){
34527 return !this.menu.getEl().getRegion().contains(e.getPoint());
34535 deactivate : function(){
34536 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34541 expandMenu : function(autoActivate){
34542 if(!this.disabled && this.menu){
34543 clearTimeout(this.hideTimer);
34544 delete this.hideTimer;
34545 if(!this.menu.isVisible() && !this.showTimer){
34546 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34547 }else if (this.menu.isVisible() && autoActivate){
34548 this.menu.tryActivate(0, 1);
34554 deferExpand : function(autoActivate){
34555 delete this.showTimer;
34556 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34558 this.menu.tryActivate(0, 1);
34563 hideMenu : function(){
34564 clearTimeout(this.showTimer);
34565 delete this.showTimer;
34566 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34567 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34572 deferHide : function(){
34573 delete this.hideTimer;
34578 * Ext JS Library 1.1.1
34579 * Copyright(c) 2006-2007, Ext JS, LLC.
34581 * Originally Released Under LGPL - original licence link has changed is not relivant.
34584 * <script type="text/javascript">
34588 * @class Roo.menu.CheckItem
34589 * @extends Roo.menu.Item
34590 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34592 * Creates a new CheckItem
34593 * @param {Object} config Configuration options
34595 Roo.menu.CheckItem = function(config){
34596 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34599 * @event beforecheckchange
34600 * Fires before the checked value is set, providing an opportunity to cancel if needed
34601 * @param {Roo.menu.CheckItem} this
34602 * @param {Boolean} checked The new checked value that will be set
34604 "beforecheckchange" : true,
34606 * @event checkchange
34607 * Fires after the checked value has been set
34608 * @param {Roo.menu.CheckItem} this
34609 * @param {Boolean} checked The checked value that was set
34611 "checkchange" : true
34613 if(this.checkHandler){
34614 this.on('checkchange', this.checkHandler, this.scope);
34617 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34619 * @cfg {String} group
34620 * All check items with the same group name will automatically be grouped into a single-select
34621 * radio button group (defaults to '')
34624 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34626 itemCls : "x-menu-item x-menu-check-item",
34628 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34630 groupClass : "x-menu-group-item",
34633 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34634 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34635 * initialized with checked = true will be rendered as checked.
34640 ctype: "Roo.menu.CheckItem",
34643 onRender : function(c){
34644 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34646 this.el.addClass(this.groupClass);
34648 Roo.menu.MenuMgr.registerCheckable(this);
34650 this.checked = false;
34651 this.setChecked(true, true);
34656 destroy : function(){
34658 Roo.menu.MenuMgr.unregisterCheckable(this);
34660 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
34664 * Set the checked state of this item
34665 * @param {Boolean} checked The new checked value
34666 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
34668 setChecked : function(state, suppressEvent){
34669 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
34670 if(this.container){
34671 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
34673 this.checked = state;
34674 if(suppressEvent !== true){
34675 this.fireEvent("checkchange", this, state);
34681 handleClick : function(e){
34682 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
34683 this.setChecked(!this.checked);
34685 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
34689 * Ext JS Library 1.1.1
34690 * Copyright(c) 2006-2007, Ext JS, LLC.
34692 * Originally Released Under LGPL - original licence link has changed is not relivant.
34695 * <script type="text/javascript">
34699 * @class Roo.menu.DateItem
34700 * @extends Roo.menu.Adapter
34701 * A menu item that wraps the {@link Roo.DatPicker} component.
34703 * Creates a new DateItem
34704 * @param {Object} config Configuration options
34706 Roo.menu.DateItem = function(config){
34707 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
34708 /** The Roo.DatePicker object @type Roo.DatePicker */
34709 this.picker = this.component;
34710 this.addEvents({select: true});
34712 this.picker.on("render", function(picker){
34713 picker.getEl().swallowEvent("click");
34714 picker.container.addClass("x-menu-date-item");
34717 this.picker.on("select", this.onSelect, this);
34720 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
34722 onSelect : function(picker, date){
34723 this.fireEvent("select", this, date, picker);
34724 Roo.menu.DateItem.superclass.handleClick.call(this);
34728 * Ext JS Library 1.1.1
34729 * Copyright(c) 2006-2007, Ext JS, LLC.
34731 * Originally Released Under LGPL - original licence link has changed is not relivant.
34734 * <script type="text/javascript">
34738 * @class Roo.menu.ColorItem
34739 * @extends Roo.menu.Adapter
34740 * A menu item that wraps the {@link Roo.ColorPalette} component.
34742 * Creates a new ColorItem
34743 * @param {Object} config Configuration options
34745 Roo.menu.ColorItem = function(config){
34746 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
34747 /** The Roo.ColorPalette object @type Roo.ColorPalette */
34748 this.palette = this.component;
34749 this.relayEvents(this.palette, ["select"]);
34750 if(this.selectHandler){
34751 this.on('select', this.selectHandler, this.scope);
34754 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
34756 * Ext JS Library 1.1.1
34757 * Copyright(c) 2006-2007, Ext JS, LLC.
34759 * Originally Released Under LGPL - original licence link has changed is not relivant.
34762 * <script type="text/javascript">
34767 * @class Roo.menu.DateMenu
34768 * @extends Roo.menu.Menu
34769 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
34771 * Creates a new DateMenu
34772 * @param {Object} config Configuration options
34774 Roo.menu.DateMenu = function(config){
34775 Roo.menu.DateMenu.superclass.constructor.call(this, config);
34777 var di = new Roo.menu.DateItem(config);
34780 * The {@link Roo.DatePicker} instance for this DateMenu
34783 this.picker = di.picker;
34786 * @param {DatePicker} picker
34787 * @param {Date} date
34789 this.relayEvents(di, ["select"]);
34791 this.on('beforeshow', function(){
34793 this.picker.hideMonthPicker(true);
34797 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
34801 * Ext JS Library 1.1.1
34802 * Copyright(c) 2006-2007, Ext JS, LLC.
34804 * Originally Released Under LGPL - original licence link has changed is not relivant.
34807 * <script type="text/javascript">
34812 * @class Roo.menu.ColorMenu
34813 * @extends Roo.menu.Menu
34814 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
34816 * Creates a new ColorMenu
34817 * @param {Object} config Configuration options
34819 Roo.menu.ColorMenu = function(config){
34820 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
34822 var ci = new Roo.menu.ColorItem(config);
34825 * The {@link Roo.ColorPalette} instance for this ColorMenu
34826 * @type ColorPalette
34828 this.palette = ci.palette;
34831 * @param {ColorPalette} palette
34832 * @param {String} color
34834 this.relayEvents(ci, ["select"]);
34836 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
34838 * Ext JS Library 1.1.1
34839 * Copyright(c) 2006-2007, Ext JS, LLC.
34841 * Originally Released Under LGPL - original licence link has changed is not relivant.
34844 * <script type="text/javascript">
34848 * @class Roo.form.Field
34849 * @extends Roo.BoxComponent
34850 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
34852 * Creates a new Field
34853 * @param {Object} config Configuration options
34855 Roo.form.Field = function(config){
34856 Roo.form.Field.superclass.constructor.call(this, config);
34859 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
34861 * @cfg {String} fieldLabel Label to use when rendering a form.
34864 * @cfg {String} qtip Mouse over tip
34868 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
34870 invalidClass : "x-form-invalid",
34872 * @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")
34874 invalidText : "The value in this field is invalid",
34876 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
34878 focusClass : "x-form-focus",
34880 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
34881 automatic validation (defaults to "keyup").
34883 validationEvent : "keyup",
34885 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
34887 validateOnBlur : true,
34889 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
34891 validationDelay : 250,
34893 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
34894 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
34896 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
34898 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
34900 fieldClass : "x-form-field",
34902 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
34905 ----------- ----------------------------------------------------------------------
34906 qtip Display a quick tip when the user hovers over the field
34907 title Display a default browser title attribute popup
34908 under Add a block div beneath the field containing the error text
34909 side Add an error icon to the right of the field with a popup on hover
34910 [element id] Add the error text directly to the innerHTML of the specified element
34913 msgTarget : 'qtip',
34915 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
34920 * @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.
34925 * @cfg {Boolean} disabled True to disable the field (defaults to false).
34930 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
34932 inputType : undefined,
34935 * @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).
34937 tabIndex : undefined,
34940 isFormField : true,
34945 * @property {Roo.Element} fieldEl
34946 * Element Containing the rendered Field (with label etc.)
34949 * @cfg {Mixed} value A value to initialize this field with.
34954 * @cfg {String} name The field's HTML name attribute.
34957 * @cfg {String} cls A CSS class to apply to the field's underlying element.
34961 initComponent : function(){
34962 Roo.form.Field.superclass.initComponent.call(this);
34966 * Fires when this field receives input focus.
34967 * @param {Roo.form.Field} this
34972 * Fires when this field loses input focus.
34973 * @param {Roo.form.Field} this
34977 * @event specialkey
34978 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
34979 * {@link Roo.EventObject#getKey} to determine which key was pressed.
34980 * @param {Roo.form.Field} this
34981 * @param {Roo.EventObject} e The event object
34986 * Fires just before the field blurs if the field value has changed.
34987 * @param {Roo.form.Field} this
34988 * @param {Mixed} newValue The new value
34989 * @param {Mixed} oldValue The original value
34994 * Fires after the field has been marked as invalid.
34995 * @param {Roo.form.Field} this
34996 * @param {String} msg The validation message
35001 * Fires after the field has been validated with no errors.
35002 * @param {Roo.form.Field} this
35009 * Returns the name attribute of the field if available
35010 * @return {String} name The field name
35012 getName: function(){
35013 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35017 onRender : function(ct, position){
35018 Roo.form.Field.superclass.onRender.call(this, ct, position);
35020 var cfg = this.getAutoCreate();
35022 cfg.name = this.name || this.id;
35024 if(this.inputType){
35025 cfg.type = this.inputType;
35027 this.el = ct.createChild(cfg, position);
35029 var type = this.el.dom.type;
35031 if(type == 'password'){
35034 this.el.addClass('x-form-'+type);
35037 this.el.dom.readOnly = true;
35039 if(this.tabIndex !== undefined){
35040 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35043 this.el.addClass([this.fieldClass, this.cls]);
35048 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35049 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35050 * @return {Roo.form.Field} this
35052 applyTo : function(target){
35053 this.allowDomMove = false;
35054 this.el = Roo.get(target);
35055 this.render(this.el.dom.parentNode);
35060 initValue : function(){
35061 if(this.value !== undefined){
35062 this.setValue(this.value);
35063 }else if(this.el.dom.value.length > 0){
35064 this.setValue(this.el.dom.value);
35069 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35071 isDirty : function() {
35072 if(this.disabled) {
35075 return String(this.getValue()) !== String(this.originalValue);
35079 afterRender : function(){
35080 Roo.form.Field.superclass.afterRender.call(this);
35085 fireKey : function(e){
35086 if(e.isNavKeyPress()){
35087 this.fireEvent("specialkey", this, e);
35092 * Resets the current field value to the originally loaded value and clears any validation messages
35094 reset : function(){
35095 this.setValue(this.originalValue);
35096 this.clearInvalid();
35100 initEvents : function(){
35101 this.el.on(Roo.isIE ? "keydown" : "keypress", this.fireKey, this);
35102 this.el.on("focus", this.onFocus, this);
35103 this.el.on("blur", this.onBlur, this);
35105 // reference to original value for reset
35106 this.originalValue = this.getValue();
35110 onFocus : function(){
35111 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35112 this.el.addClass(this.focusClass);
35114 if(!this.hasFocus){
35115 this.hasFocus = true;
35116 this.startValue = this.getValue();
35117 this.fireEvent("focus", this);
35121 beforeBlur : Roo.emptyFn,
35124 onBlur : function(){
35126 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35127 this.el.removeClass(this.focusClass);
35129 this.hasFocus = false;
35130 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35133 var v = this.getValue();
35134 if(String(v) !== String(this.startValue)){
35135 this.fireEvent('change', this, v, this.startValue);
35137 this.fireEvent("blur", this);
35141 * Returns whether or not the field value is currently valid
35142 * @param {Boolean} preventMark True to disable marking the field invalid
35143 * @return {Boolean} True if the value is valid, else false
35145 isValid : function(preventMark){
35149 var restore = this.preventMark;
35150 this.preventMark = preventMark === true;
35151 var v = this.validateValue(this.processValue(this.getRawValue()));
35152 this.preventMark = restore;
35157 * Validates the field value
35158 * @return {Boolean} True if the value is valid, else false
35160 validate : function(){
35161 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35162 this.clearInvalid();
35168 processValue : function(value){
35173 // Subclasses should provide the validation implementation by overriding this
35174 validateValue : function(value){
35179 * Mark this field as invalid
35180 * @param {String} msg The validation message
35182 markInvalid : function(msg){
35183 if(!this.rendered || this.preventMark){ // not rendered
35186 this.el.addClass(this.invalidClass);
35187 msg = msg || this.invalidText;
35188 switch(this.msgTarget){
35190 this.el.dom.qtip = msg;
35191 this.el.dom.qclass = 'x-form-invalid-tip';
35192 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35193 Roo.QuickTips.enable();
35197 this.el.dom.title = msg;
35201 var elp = this.el.findParent('.x-form-element', 5, true);
35202 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35203 this.errorEl.setWidth(elp.getWidth(true)-20);
35205 this.errorEl.update(msg);
35206 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35209 if(!this.errorIcon){
35210 var elp = this.el.findParent('.x-form-element', 5, true);
35211 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35213 this.alignErrorIcon();
35214 this.errorIcon.dom.qtip = msg;
35215 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35216 this.errorIcon.show();
35217 this.on('resize', this.alignErrorIcon, this);
35220 var t = Roo.getDom(this.msgTarget);
35222 t.style.display = this.msgDisplay;
35225 this.fireEvent('invalid', this, msg);
35229 alignErrorIcon : function(){
35230 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35234 * Clear any invalid styles/messages for this field
35236 clearInvalid : function(){
35237 if(!this.rendered || this.preventMark){ // not rendered
35240 this.el.removeClass(this.invalidClass);
35241 switch(this.msgTarget){
35243 this.el.dom.qtip = '';
35246 this.el.dom.title = '';
35250 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35254 if(this.errorIcon){
35255 this.errorIcon.dom.qtip = '';
35256 this.errorIcon.hide();
35257 this.un('resize', this.alignErrorIcon, this);
35261 var t = Roo.getDom(this.msgTarget);
35263 t.style.display = 'none';
35266 this.fireEvent('valid', this);
35270 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35271 * @return {Mixed} value The field value
35273 getRawValue : function(){
35274 var v = this.el.getValue();
35275 if(v === this.emptyText){
35282 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35283 * @return {Mixed} value The field value
35285 getValue : function(){
35286 var v = this.el.getValue();
35287 if(v === this.emptyText || v === undefined){
35294 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35295 * @param {Mixed} value The value to set
35297 setRawValue : function(v){
35298 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35302 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35303 * @param {Mixed} value The value to set
35305 setValue : function(v){
35308 this.el.dom.value = (v === null || v === undefined ? '' : v);
35313 adjustSize : function(w, h){
35314 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35315 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35319 adjustWidth : function(tag, w){
35320 tag = tag.toLowerCase();
35321 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35322 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35323 if(tag == 'input'){
35326 if(tag = 'textarea'){
35329 }else if(Roo.isOpera){
35330 if(tag == 'input'){
35333 if(tag = 'textarea'){
35343 // anything other than normal should be considered experimental
35344 Roo.form.Field.msgFx = {
35346 show: function(msgEl, f){
35347 msgEl.setDisplayed('block');
35350 hide : function(msgEl, f){
35351 msgEl.setDisplayed(false).update('');
35356 show: function(msgEl, f){
35357 msgEl.slideIn('t', {stopFx:true});
35360 hide : function(msgEl, f){
35361 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35366 show: function(msgEl, f){
35367 msgEl.fixDisplay();
35368 msgEl.alignTo(f.el, 'tl-tr');
35369 msgEl.slideIn('l', {stopFx:true});
35372 hide : function(msgEl, f){
35373 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35378 * Ext JS Library 1.1.1
35379 * Copyright(c) 2006-2007, Ext JS, LLC.
35381 * Originally Released Under LGPL - original licence link has changed is not relivant.
35384 * <script type="text/javascript">
35389 * @class Roo.form.TextField
35390 * @extends Roo.form.Field
35391 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35392 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35394 * Creates a new TextField
35395 * @param {Object} config Configuration options
35397 Roo.form.TextField = function(config){
35398 Roo.form.TextField.superclass.constructor.call(this, config);
35402 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35403 * according to the default logic, but this event provides a hook for the developer to apply additional
35404 * logic at runtime to resize the field if needed.
35405 * @param {Roo.form.Field} this This text field
35406 * @param {Number} width The new field width
35412 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35414 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35418 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35422 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35426 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35430 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35434 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35436 disableKeyFilter : false,
35438 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35442 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35446 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35448 maxLength : Number.MAX_VALUE,
35450 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35452 minLengthText : "The minimum length for this field is {0}",
35454 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35456 maxLengthText : "The maximum length for this field is {0}",
35458 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35460 selectOnFocus : false,
35462 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35464 blankText : "This field is required",
35466 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35467 * If available, this function will be called only after the basic validators all return true, and will be passed the
35468 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35472 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35473 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35474 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35478 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35482 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35486 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35487 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35489 emptyClass : 'x-form-empty-field',
35492 initEvents : function(){
35493 Roo.form.TextField.superclass.initEvents.call(this);
35494 if(this.validationEvent == 'keyup'){
35495 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35496 this.el.on('keyup', this.filterValidation, this);
35498 else if(this.validationEvent !== false){
35499 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35501 if(this.selectOnFocus || this.emptyText){
35502 this.on("focus", this.preFocus, this);
35503 if(this.emptyText){
35504 this.on('blur', this.postBlur, this);
35505 this.applyEmptyText();
35508 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35509 this.el.on("keypress", this.filterKeys, this);
35512 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35513 this.el.on("click", this.autoSize, this);
35517 processValue : function(value){
35518 if(this.stripCharsRe){
35519 var newValue = value.replace(this.stripCharsRe, '');
35520 if(newValue !== value){
35521 this.setRawValue(newValue);
35528 filterValidation : function(e){
35529 if(!e.isNavKeyPress()){
35530 this.validationTask.delay(this.validationDelay);
35535 onKeyUp : function(e){
35536 if(!e.isNavKeyPress()){
35542 * Resets the current field value to the originally-loaded value and clears any validation messages.
35543 * Also adds emptyText and emptyClass if the original value was blank.
35545 reset : function(){
35546 Roo.form.TextField.superclass.reset.call(this);
35547 this.applyEmptyText();
35550 applyEmptyText : function(){
35551 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35552 this.setRawValue(this.emptyText);
35553 this.el.addClass(this.emptyClass);
35558 preFocus : function(){
35559 if(this.emptyText){
35560 if(this.el.dom.value == this.emptyText){
35561 this.setRawValue('');
35563 this.el.removeClass(this.emptyClass);
35565 if(this.selectOnFocus){
35566 this.el.dom.select();
35571 postBlur : function(){
35572 this.applyEmptyText();
35576 filterKeys : function(e){
35577 var k = e.getKey();
35578 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35581 var c = e.getCharCode(), cc = String.fromCharCode(c);
35582 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35585 if(!this.maskRe.test(cc)){
35590 setValue : function(v){
35591 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35592 this.el.removeClass(this.emptyClass);
35594 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35595 this.applyEmptyText();
35600 * Validates a value according to the field's validation rules and marks the field as invalid
35601 * if the validation fails
35602 * @param {Mixed} value The value to validate
35603 * @return {Boolean} True if the value is valid, else false
35605 validateValue : function(value){
35606 if(value.length < 1 || value === this.emptyText){ // if it's blank
35607 if(this.allowBlank){
35608 this.clearInvalid();
35611 this.markInvalid(this.blankText);
35615 if(value.length < this.minLength){
35616 this.markInvalid(String.format(this.minLengthText, this.minLength));
35619 if(value.length > this.maxLength){
35620 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35624 var vt = Roo.form.VTypes;
35625 if(!vt[this.vtype](value, this)){
35626 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35630 if(typeof this.validator == "function"){
35631 var msg = this.validator(value);
35633 this.markInvalid(msg);
35637 if(this.regex && !this.regex.test(value)){
35638 this.markInvalid(this.regexText);
35645 * Selects text in this field
35646 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
35647 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
35649 selectText : function(start, end){
35650 var v = this.getRawValue();
35652 start = start === undefined ? 0 : start;
35653 end = end === undefined ? v.length : end;
35654 var d = this.el.dom;
35655 if(d.setSelectionRange){
35656 d.setSelectionRange(start, end);
35657 }else if(d.createTextRange){
35658 var range = d.createTextRange();
35659 range.moveStart("character", start);
35660 range.moveEnd("character", v.length-end);
35667 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
35668 * This only takes effect if grow = true, and fires the autosize event.
35670 autoSize : function(){
35671 if(!this.grow || !this.rendered){
35675 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
35678 var v = el.dom.value;
35679 var d = document.createElement('div');
35680 d.appendChild(document.createTextNode(v));
35684 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
35685 this.el.setWidth(w);
35686 this.fireEvent("autosize", this, w);
35690 * Ext JS Library 1.1.1
35691 * Copyright(c) 2006-2007, Ext JS, LLC.
35693 * Originally Released Under LGPL - original licence link has changed is not relivant.
35696 * <script type="text/javascript">
35700 * @class Roo.form.Hidden
35701 * @extends Roo.form.TextField
35702 * Simple Hidden element used on forms
35704 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
35707 * Creates a new Hidden form element.
35708 * @param {Object} config Configuration options
35713 // easy hidden field...
35714 Roo.form.Hidden = function(config){
35715 Roo.form.Hidden.superclass.constructor.call(this, config);
35718 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
35720 inputType: 'hidden',
35723 labelSeparator: '',
35725 itemCls : 'x-form-item-display-none'
35733 * Ext JS Library 1.1.1
35734 * Copyright(c) 2006-2007, Ext JS, LLC.
35736 * Originally Released Under LGPL - original licence link has changed is not relivant.
35739 * <script type="text/javascript">
35743 * @class Roo.form.TriggerField
35744 * @extends Roo.form.TextField
35745 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
35746 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
35747 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
35748 * for which you can provide a custom implementation. For example:
35750 var trigger = new Roo.form.TriggerField();
35751 trigger.onTriggerClick = myTriggerFn;
35752 trigger.applyTo('my-field');
35755 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
35756 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
35757 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
35758 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
35760 * Create a new TriggerField.
35761 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
35762 * to the base TextField)
35764 Roo.form.TriggerField = function(config){
35765 this.mimicing = false;
35766 Roo.form.TriggerField.superclass.constructor.call(this, config);
35769 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
35771 * @cfg {String} triggerClass A CSS class to apply to the trigger
35774 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35775 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
35777 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
35779 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
35783 /** @cfg {Boolean} grow @hide */
35784 /** @cfg {Number} growMin @hide */
35785 /** @cfg {Number} growMax @hide */
35791 autoSize: Roo.emptyFn,
35795 deferHeight : true,
35798 actionMode : 'wrap',
35800 onResize : function(w, h){
35801 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
35802 if(typeof w == 'number'){
35803 this.el.setWidth(this.adjustWidth('input', w - this.trigger.getWidth()));
35808 adjustSize : Roo.BoxComponent.prototype.adjustSize,
35811 getResizeEl : function(){
35816 getPositionEl : function(){
35821 alignErrorIcon : function(){
35822 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
35826 onRender : function(ct, position){
35827 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
35828 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
35829 this.trigger = this.wrap.createChild(this.triggerConfig ||
35830 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
35831 if(this.hideTrigger){
35832 this.trigger.setDisplayed(false);
35834 this.initTrigger();
35836 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
35841 initTrigger : function(){
35842 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
35843 this.trigger.addClassOnOver('x-form-trigger-over');
35844 this.trigger.addClassOnClick('x-form-trigger-click');
35848 onDestroy : function(){
35850 this.trigger.removeAllListeners();
35851 this.trigger.remove();
35854 this.wrap.remove();
35856 Roo.form.TriggerField.superclass.onDestroy.call(this);
35860 onFocus : function(){
35861 Roo.form.TriggerField.superclass.onFocus.call(this);
35862 if(!this.mimicing){
35863 this.wrap.addClass('x-trigger-wrap-focus');
35864 this.mimicing = true;
35865 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
35866 if(this.monitorTab){
35867 this.el.on("keydown", this.checkTab, this);
35873 checkTab : function(e){
35874 if(e.getKey() == e.TAB){
35875 this.triggerBlur();
35880 onBlur : function(){
35885 mimicBlur : function(e, t){
35886 if(!this.wrap.contains(t) && this.validateBlur()){
35887 this.triggerBlur();
35892 triggerBlur : function(){
35893 this.mimicing = false;
35894 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
35895 if(this.monitorTab){
35896 this.el.un("keydown", this.checkTab, this);
35898 this.wrap.removeClass('x-trigger-wrap-focus');
35899 Roo.form.TriggerField.superclass.onBlur.call(this);
35903 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
35904 validateBlur : function(e, t){
35909 onDisable : function(){
35910 Roo.form.TriggerField.superclass.onDisable.call(this);
35912 this.wrap.addClass('x-item-disabled');
35917 onEnable : function(){
35918 Roo.form.TriggerField.superclass.onEnable.call(this);
35920 this.wrap.removeClass('x-item-disabled');
35925 onShow : function(){
35926 var ae = this.getActionEl();
35929 ae.dom.style.display = '';
35930 ae.dom.style.visibility = 'visible';
35936 onHide : function(){
35937 var ae = this.getActionEl();
35938 ae.dom.style.display = 'none';
35942 * The function that should handle the trigger's click event. This method does nothing by default until overridden
35943 * by an implementing function.
35945 * @param {EventObject} e
35947 onTriggerClick : Roo.emptyFn
35950 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
35951 // to be extended by an implementing class. For an example of implementing this class, see the custom
35952 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
35953 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
35954 initComponent : function(){
35955 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
35957 this.triggerConfig = {
35958 tag:'span', cls:'x-form-twin-triggers', cn:[
35959 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
35960 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
35964 getTrigger : function(index){
35965 return this.triggers[index];
35968 initTrigger : function(){
35969 var ts = this.trigger.select('.x-form-trigger', true);
35970 this.wrap.setStyle('overflow', 'hidden');
35971 var triggerField = this;
35972 ts.each(function(t, all, index){
35973 t.hide = function(){
35974 var w = triggerField.wrap.getWidth();
35975 this.dom.style.display = 'none';
35976 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
35978 t.show = function(){
35979 var w = triggerField.wrap.getWidth();
35980 this.dom.style.display = '';
35981 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
35983 var triggerIndex = 'Trigger'+(index+1);
35985 if(this['hide'+triggerIndex]){
35986 t.dom.style.display = 'none';
35988 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
35989 t.addClassOnOver('x-form-trigger-over');
35990 t.addClassOnClick('x-form-trigger-click');
35992 this.triggers = ts.elements;
35995 onTrigger1Click : Roo.emptyFn,
35996 onTrigger2Click : Roo.emptyFn
35999 * Ext JS Library 1.1.1
36000 * Copyright(c) 2006-2007, Ext JS, LLC.
36002 * Originally Released Under LGPL - original licence link has changed is not relivant.
36005 * <script type="text/javascript">
36009 * @class Roo.form.TextArea
36010 * @extends Roo.form.TextField
36011 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36012 * support for auto-sizing.
36014 * Creates a new TextArea
36015 * @param {Object} config Configuration options
36017 Roo.form.TextArea = function(config){
36018 Roo.form.TextArea.superclass.constructor.call(this, config);
36019 // these are provided exchanges for backwards compat
36020 // minHeight/maxHeight were replaced by growMin/growMax to be
36021 // compatible with TextField growing config values
36022 if(this.minHeight !== undefined){
36023 this.growMin = this.minHeight;
36025 if(this.maxHeight !== undefined){
36026 this.growMax = this.maxHeight;
36030 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36032 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36036 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36040 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36041 * in the field (equivalent to setting overflow: hidden, defaults to false)
36043 preventScrollbars: false,
36045 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36046 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36050 onRender : function(ct, position){
36052 this.defaultAutoCreate = {
36054 style:"width:300px;height:60px;",
36055 autocomplete: "off"
36058 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36060 this.textSizeEl = Roo.DomHelper.append(document.body, {
36061 tag: "pre", cls: "x-form-grow-sizer"
36063 if(this.preventScrollbars){
36064 this.el.setStyle("overflow", "hidden");
36066 this.el.setHeight(this.growMin);
36070 onDestroy : function(){
36071 if(this.textSizeEl){
36072 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36074 Roo.form.TextArea.superclass.onDestroy.call(this);
36078 onKeyUp : function(e){
36079 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36085 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36086 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36088 autoSize : function(){
36089 if(!this.grow || !this.textSizeEl){
36093 var v = el.dom.value;
36094 var ts = this.textSizeEl;
36097 ts.appendChild(document.createTextNode(v));
36100 Roo.fly(ts).setWidth(this.el.getWidth());
36102 v = "  ";
36105 v = v.replace(/\n/g, '<p> </p>');
36107 v += " \n ";
36110 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36111 if(h != this.lastHeight){
36112 this.lastHeight = h;
36113 this.el.setHeight(h);
36114 this.fireEvent("autosize", this, h);
36119 * Ext JS Library 1.1.1
36120 * Copyright(c) 2006-2007, Ext JS, LLC.
36122 * Originally Released Under LGPL - original licence link has changed is not relivant.
36125 * <script type="text/javascript">
36130 * @class Roo.form.NumberField
36131 * @extends Roo.form.TextField
36132 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36134 * Creates a new NumberField
36135 * @param {Object} config Configuration options
36137 Roo.form.NumberField = function(config){
36138 Roo.form.NumberField.superclass.constructor.call(this, config);
36141 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36143 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36145 fieldClass: "x-form-field x-form-num-field",
36147 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36149 allowDecimals : true,
36151 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36153 decimalSeparator : ".",
36155 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36157 decimalPrecision : 2,
36159 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36161 allowNegative : true,
36163 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36165 minValue : Number.NEGATIVE_INFINITY,
36167 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36169 maxValue : Number.MAX_VALUE,
36171 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36173 minText : "The minimum value for this field is {0}",
36175 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36177 maxText : "The maximum value for this field is {0}",
36179 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36180 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36182 nanText : "{0} is not a valid number",
36185 initEvents : function(){
36186 Roo.form.NumberField.superclass.initEvents.call(this);
36187 var allowed = "0123456789";
36188 if(this.allowDecimals){
36189 allowed += this.decimalSeparator;
36191 if(this.allowNegative){
36194 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36195 var keyPress = function(e){
36196 var k = e.getKey();
36197 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36200 var c = e.getCharCode();
36201 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36205 this.el.on("keypress", keyPress, this);
36209 validateValue : function(value){
36210 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36213 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36216 var num = this.parseValue(value);
36218 this.markInvalid(String.format(this.nanText, value));
36221 if(num < this.minValue){
36222 this.markInvalid(String.format(this.minText, this.minValue));
36225 if(num > this.maxValue){
36226 this.markInvalid(String.format(this.maxText, this.maxValue));
36232 getValue : function(){
36233 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36237 parseValue : function(value){
36238 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36239 return isNaN(value) ? '' : value;
36243 fixPrecision : function(value){
36244 var nan = isNaN(value);
36245 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36246 return nan ? '' : value;
36248 return parseFloat(value).toFixed(this.decimalPrecision);
36251 setValue : function(v){
36252 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36256 decimalPrecisionFcn : function(v){
36257 return Math.floor(v);
36260 beforeBlur : function(){
36261 var v = this.parseValue(this.getRawValue());
36263 this.setValue(this.fixPrecision(v));
36268 * Ext JS Library 1.1.1
36269 * Copyright(c) 2006-2007, Ext JS, LLC.
36271 * Originally Released Under LGPL - original licence link has changed is not relivant.
36274 * <script type="text/javascript">
36278 * @class Roo.form.DateField
36279 * @extends Roo.form.TriggerField
36280 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36282 * Create a new DateField
36283 * @param {Object} config
36285 Roo.form.DateField = function(config){
36286 Roo.form.DateField.superclass.constructor.call(this, config);
36292 * Fires when a date is selected
36293 * @param {Roo.form.DateField} combo This combo box
36294 * @param {Date} date The date selected
36301 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36302 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36303 this.ddMatch = null;
36304 if(this.disabledDates){
36305 var dd = this.disabledDates;
36307 for(var i = 0; i < dd.length; i++){
36309 if(i != dd.length-1) re += "|";
36311 this.ddMatch = new RegExp(re + ")");
36315 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36317 * @cfg {String} format
36318 * The default date format string which can be overriden for localization support. The format must be
36319 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36323 * @cfg {String} altFormats
36324 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36325 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36327 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36329 * @cfg {Array} disabledDays
36330 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36332 disabledDays : null,
36334 * @cfg {String} disabledDaysText
36335 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36337 disabledDaysText : "Disabled",
36339 * @cfg {Array} disabledDates
36340 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36341 * expression so they are very powerful. Some examples:
36343 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36344 * <li>["03/08", "09/16"] would disable those days for every year</li>
36345 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36346 * <li>["03/../2006"] would disable every day in March 2006</li>
36347 * <li>["^03"] would disable every day in every March</li>
36349 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36350 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36352 disabledDates : null,
36354 * @cfg {String} disabledDatesText
36355 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36357 disabledDatesText : "Disabled",
36359 * @cfg {Date/String} minValue
36360 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36361 * valid format (defaults to null).
36365 * @cfg {Date/String} maxValue
36366 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36367 * valid format (defaults to null).
36371 * @cfg {String} minText
36372 * The error text to display when the date in the cell is before minValue (defaults to
36373 * 'The date in this field must be after {minValue}').
36375 minText : "The date in this field must be equal to or after {0}",
36377 * @cfg {String} maxText
36378 * The error text to display when the date in the cell is after maxValue (defaults to
36379 * 'The date in this field must be before {maxValue}').
36381 maxText : "The date in this field must be equal to or before {0}",
36383 * @cfg {String} invalidText
36384 * The error text to display when the date in the field is invalid (defaults to
36385 * '{value} is not a valid date - it must be in the format {format}').
36387 invalidText : "{0} is not a valid date - it must be in the format {1}",
36389 * @cfg {String} triggerClass
36390 * An additional CSS class used to style the trigger button. The trigger will always get the
36391 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36392 * which displays a calendar icon).
36394 triggerClass : 'x-form-date-trigger',
36398 * @cfg {bool} useIso
36399 * if enabled, then the date field will use a hidden field to store the
36400 * real value as iso formated date. default (false)
36404 * @cfg {String/Object} autoCreate
36405 * A DomHelper element spec, or true for a default element spec (defaults to
36406 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36409 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36412 hiddenField: false,
36414 onRender : function(ct, position)
36416 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36418 this.el.dom.removeAttribute('name');
36419 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36421 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36422 // prevent input submission
36423 this.hiddenName = this.name;
36430 validateValue : function(value)
36432 value = this.formatDate(value);
36433 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36436 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36439 var svalue = value;
36440 value = this.parseDate(value);
36442 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36445 var time = value.getTime();
36446 if(this.minValue && time < this.minValue.getTime()){
36447 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36450 if(this.maxValue && time > this.maxValue.getTime()){
36451 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36454 if(this.disabledDays){
36455 var day = value.getDay();
36456 for(var i = 0; i < this.disabledDays.length; i++) {
36457 if(day === this.disabledDays[i]){
36458 this.markInvalid(this.disabledDaysText);
36463 var fvalue = this.formatDate(value);
36464 if(this.ddMatch && this.ddMatch.test(fvalue)){
36465 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36472 // Provides logic to override the default TriggerField.validateBlur which just returns true
36473 validateBlur : function(){
36474 return !this.menu || !this.menu.isVisible();
36478 * Returns the current date value of the date field.
36479 * @return {Date} The date value
36481 getValue : function(){
36483 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36487 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36488 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36489 * (the default format used is "m/d/y").
36492 //All of these calls set the same date value (May 4, 2006)
36494 //Pass a date object:
36495 var dt = new Date('5/4/06');
36496 dateField.setValue(dt);
36498 //Pass a date string (default format):
36499 dateField.setValue('5/4/06');
36501 //Pass a date string (custom format):
36502 dateField.format = 'Y-m-d';
36503 dateField.setValue('2006-5-4');
36505 * @param {String/Date} date The date or valid date string
36507 setValue : function(date){
36508 if (this.hiddenField) {
36509 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36511 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36515 parseDate : function(value){
36516 if(!value || value instanceof Date){
36519 var v = Date.parseDate(value, this.format);
36520 if(!v && this.altFormats){
36521 if(!this.altFormatsArray){
36522 this.altFormatsArray = this.altFormats.split("|");
36524 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36525 v = Date.parseDate(value, this.altFormatsArray[i]);
36532 formatDate : function(date, fmt){
36533 return (!date || !(date instanceof Date)) ?
36534 date : date.dateFormat(fmt || this.format);
36539 select: function(m, d){
36541 this.fireEvent('select', this, d);
36543 show : function(){ // retain focus styling
36547 this.focus.defer(10, this);
36548 var ml = this.menuListeners;
36549 this.menu.un("select", ml.select, this);
36550 this.menu.un("show", ml.show, this);
36551 this.menu.un("hide", ml.hide, this);
36556 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36557 onTriggerClick : function(){
36561 if(this.menu == null){
36562 this.menu = new Roo.menu.DateMenu();
36564 Roo.apply(this.menu.picker, {
36565 showClear: this.allowBlank,
36566 minDate : this.minValue,
36567 maxDate : this.maxValue,
36568 disabledDatesRE : this.ddMatch,
36569 disabledDatesText : this.disabledDatesText,
36570 disabledDays : this.disabledDays,
36571 disabledDaysText : this.disabledDaysText,
36572 format : this.format,
36573 minText : String.format(this.minText, this.formatDate(this.minValue)),
36574 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36576 this.menu.on(Roo.apply({}, this.menuListeners, {
36579 this.menu.picker.setValue(this.getValue() || new Date());
36580 this.menu.show(this.el, "tl-bl?");
36583 beforeBlur : function(){
36584 var v = this.parseDate(this.getRawValue());
36590 /** @cfg {Boolean} grow @hide */
36591 /** @cfg {Number} growMin @hide */
36592 /** @cfg {Number} growMax @hide */
36599 * Ext JS Library 1.1.1
36600 * Copyright(c) 2006-2007, Ext JS, LLC.
36602 * Originally Released Under LGPL - original licence link has changed is not relivant.
36605 * <script type="text/javascript">
36610 * @class Roo.form.ComboBox
36611 * @extends Roo.form.TriggerField
36612 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36614 * Create a new ComboBox.
36615 * @param {Object} config Configuration options
36617 Roo.form.ComboBox = function(config){
36618 Roo.form.ComboBox.superclass.constructor.call(this, config);
36622 * Fires when the dropdown list is expanded
36623 * @param {Roo.form.ComboBox} combo This combo box
36628 * Fires when the dropdown list is collapsed
36629 * @param {Roo.form.ComboBox} combo This combo box
36633 * @event beforeselect
36634 * Fires before a list item is selected. Return false to cancel the selection.
36635 * @param {Roo.form.ComboBox} combo This combo box
36636 * @param {Roo.data.Record} record The data record returned from the underlying store
36637 * @param {Number} index The index of the selected item in the dropdown list
36639 'beforeselect' : true,
36642 * Fires when a list item is selected
36643 * @param {Roo.form.ComboBox} combo This combo box
36644 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
36645 * @param {Number} index The index of the selected item in the dropdown list
36649 * @event beforequery
36650 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
36651 * The event object passed has these properties:
36652 * @param {Roo.form.ComboBox} combo This combo box
36653 * @param {String} query The query
36654 * @param {Boolean} forceAll true to force "all" query
36655 * @param {Boolean} cancel true to cancel the query
36656 * @param {Object} e The query event object
36658 'beforequery': true
36660 if(this.transform){
36661 this.allowDomMove = false;
36662 var s = Roo.getDom(this.transform);
36663 if(!this.hiddenName){
36664 this.hiddenName = s.name;
36667 this.mode = 'local';
36668 var d = [], opts = s.options;
36669 for(var i = 0, len = opts.length;i < len; i++){
36671 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
36673 this.value = value;
36675 d.push([value, o.text]);
36677 this.store = new Roo.data.SimpleStore({
36679 fields: ['value', 'text'],
36682 this.valueField = 'value';
36683 this.displayField = 'text';
36685 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
36686 if(!this.lazyRender){
36687 this.target = true;
36688 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
36689 s.parentNode.removeChild(s); // remove it
36690 this.render(this.el.parentNode);
36692 s.parentNode.removeChild(s); // remove it
36697 this.store = Roo.factory(this.store, Roo.data);
36700 this.selectedIndex = -1;
36701 if(this.mode == 'local'){
36702 if(config.queryDelay === undefined){
36703 this.queryDelay = 10;
36705 if(config.minChars === undefined){
36711 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
36713 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
36716 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
36717 * rendering into an Roo.Editor, defaults to false)
36720 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
36721 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
36724 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
36727 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
36728 * the dropdown list (defaults to undefined, with no header element)
36732 * @cfg {String/Roo.Template} tpl The template to use to render the output
36736 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
36738 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
36740 listWidth: undefined,
36742 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
36743 * mode = 'remote' or 'text' if mode = 'local')
36745 displayField: undefined,
36747 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
36748 * mode = 'remote' or 'value' if mode = 'local').
36749 * Note: use of a valueField requires the user make a selection
36750 * in order for a value to be mapped.
36752 valueField: undefined,
36754 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
36755 * field's data value (defaults to the underlying DOM element's name)
36757 hiddenName: undefined,
36759 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
36763 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
36765 selectedClass: 'x-combo-selected',
36767 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36768 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
36769 * which displays a downward arrow icon).
36771 triggerClass : 'x-form-arrow-trigger',
36773 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
36777 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
36778 * anchor positions (defaults to 'tl-bl')
36780 listAlign: 'tl-bl?',
36782 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
36786 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
36787 * query specified by the allQuery config option (defaults to 'query')
36789 triggerAction: 'query',
36791 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
36792 * (defaults to 4, does not apply if editable = false)
36796 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
36797 * delay (typeAheadDelay) if it matches a known value (defaults to false)
36801 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
36802 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
36806 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
36807 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
36811 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
36812 * when editable = true (defaults to false)
36814 selectOnFocus:false,
36816 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
36818 queryParam: 'query',
36820 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
36821 * when mode = 'remote' (defaults to 'Loading...')
36823 loadingText: 'Loading...',
36825 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
36829 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
36833 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
36834 * traditional select (defaults to true)
36838 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
36842 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
36846 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
36847 * listWidth has a higher value)
36851 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
36852 * allow the user to set arbitrary text into the field (defaults to false)
36854 forceSelection:false,
36856 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
36857 * if typeAhead = true (defaults to 250)
36859 typeAheadDelay : 250,
36861 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
36862 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
36864 valueNotFoundText : undefined,
36866 * @cfg {bool} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
36868 blockFocus : false,
36871 * @cfg {bool} disableClear Disable showing of clear button.
36873 disableClear : false,
36876 onRender : function(ct, position){
36877 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
36878 if(this.hiddenName){
36879 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
36881 this.hiddenField.value =
36882 this.hiddenValue !== undefined ? this.hiddenValue :
36883 this.value !== undefined ? this.value : '';
36885 // prevent input submission
36886 this.el.dom.removeAttribute('name');
36889 this.el.dom.setAttribute('autocomplete', 'off');
36892 var cls = 'x-combo-list';
36894 this.list = new Roo.Layer({
36895 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
36898 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
36899 this.list.setWidth(lw);
36900 this.list.swallowEvent('mousewheel');
36901 this.assetHeight = 0;
36904 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
36905 this.assetHeight += this.header.getHeight();
36908 this.innerList = this.list.createChild({cls:cls+'-inner'});
36909 this.innerList.on('mouseover', this.onViewOver, this);
36910 this.innerList.on('mousemove', this.onViewMove, this);
36911 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
36913 if(this.allowBlank && !this.pageSize && !this.disableClear){
36914 this.footer = this.list.createChild({cls:cls+'-ft'});
36915 this.pageTb = new Roo.Toolbar(this.footer);
36919 this.footer = this.list.createChild({cls:cls+'-ft'});
36920 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
36921 {pageSize: this.pageSize});
36925 if (this.pageTb && this.allowBlank && !this.disableClear) {
36927 this.pageTb.add(new Roo.Toolbar.Fill(), {
36928 cls: 'x-btn-icon x-btn-clear',
36930 handler: function()
36933 _this.clearValue();
36934 _this.onSelect(false, -1);
36939 this.assetHeight += this.footer.getHeight();
36944 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
36947 this.view = new Roo.View(this.innerList, this.tpl, {
36948 singleSelect:true, store: this.store, selectedClass: this.selectedClass
36951 this.view.on('click', this.onViewClick, this);
36953 this.store.on('beforeload', this.onBeforeLoad, this);
36954 this.store.on('load', this.onLoad, this);
36955 this.store.on('loadexception', this.collapse, this);
36957 if(this.resizable){
36958 this.resizer = new Roo.Resizable(this.list, {
36959 pinned:true, handles:'se'
36961 this.resizer.on('resize', function(r, w, h){
36962 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
36963 this.listWidth = w;
36964 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
36965 this.restrictHeight();
36967 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
36969 if(!this.editable){
36970 this.editable = true;
36971 this.setEditable(false);
36976 initEvents : function(){
36977 Roo.form.ComboBox.superclass.initEvents.call(this);
36979 this.keyNav = new Roo.KeyNav(this.el, {
36980 "up" : function(e){
36981 this.inKeyMode = true;
36985 "down" : function(e){
36986 if(!this.isExpanded()){
36987 this.onTriggerClick();
36989 this.inKeyMode = true;
36994 "enter" : function(e){
36995 this.onViewClick();
36999 "esc" : function(e){
37003 "tab" : function(e){
37004 this.onViewClick(false);
37010 doRelay : function(foo, bar, hname){
37011 if(hname == 'down' || this.scope.isExpanded()){
37012 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37019 this.queryDelay = Math.max(this.queryDelay || 10,
37020 this.mode == 'local' ? 10 : 250);
37021 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37022 if(this.typeAhead){
37023 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37025 if(this.editable !== false){
37026 this.el.on("keyup", this.onKeyUp, this);
37028 if(this.forceSelection){
37029 this.on('blur', this.doForce, this);
37033 onDestroy : function(){
37035 this.view.setStore(null);
37036 this.view.el.removeAllListeners();
37037 this.view.el.remove();
37038 this.view.purgeListeners();
37041 this.list.destroy();
37044 this.store.un('beforeload', this.onBeforeLoad, this);
37045 this.store.un('load', this.onLoad, this);
37046 this.store.un('loadexception', this.collapse, this);
37048 Roo.form.ComboBox.superclass.onDestroy.call(this);
37052 fireKey : function(e){
37053 if(e.isNavKeyPress() && !this.list.isVisible()){
37054 this.fireEvent("specialkey", this, e);
37059 onResize: function(w, h){
37060 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37061 if(this.list && this.listWidth === undefined){
37062 var lw = Math.max(w, this.minListWidth);
37063 this.list.setWidth(lw);
37064 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37069 * Allow or prevent the user from directly editing the field text. If false is passed,
37070 * the user will only be able to select from the items defined in the dropdown list. This method
37071 * is the runtime equivalent of setting the 'editable' config option at config time.
37072 * @param {Boolean} value True to allow the user to directly edit the field text
37074 setEditable : function(value){
37075 if(value == this.editable){
37078 this.editable = value;
37080 this.el.dom.setAttribute('readOnly', true);
37081 this.el.on('mousedown', this.onTriggerClick, this);
37082 this.el.addClass('x-combo-noedit');
37084 this.el.dom.setAttribute('readOnly', false);
37085 this.el.un('mousedown', this.onTriggerClick, this);
37086 this.el.removeClass('x-combo-noedit');
37091 onBeforeLoad : function(){
37092 if(!this.hasFocus){
37095 this.innerList.update(this.loadingText ?
37096 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37097 this.restrictHeight();
37098 this.selectedIndex = -1;
37102 onLoad : function(){
37103 if(!this.hasFocus){
37106 if(this.store.getCount() > 0){
37108 this.restrictHeight();
37109 if(this.lastQuery == this.allQuery){
37111 this.el.dom.select();
37113 if(!this.selectByValue(this.value, true)){
37114 this.select(0, true);
37118 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37119 this.taTask.delay(this.typeAheadDelay);
37123 this.onEmptyResults();
37129 onTypeAhead : function(){
37130 if(this.store.getCount() > 0){
37131 var r = this.store.getAt(0);
37132 var newValue = r.data[this.displayField];
37133 var len = newValue.length;
37134 var selStart = this.getRawValue().length;
37135 if(selStart != len){
37136 this.setRawValue(newValue);
37137 this.selectText(selStart, newValue.length);
37143 onSelect : function(record, index){
37144 if(this.fireEvent('beforeselect', this, record, index) !== false){
37145 this.setFromData(index > -1 ? record.data : false);
37147 this.fireEvent('select', this, record, index);
37152 * Returns the currently selected field value or empty string if no value is set.
37153 * @return {String} value The selected value
37155 getValue : function(){
37156 if(this.valueField){
37157 return typeof this.value != 'undefined' ? this.value : '';
37159 return Roo.form.ComboBox.superclass.getValue.call(this);
37164 * Clears any text/value currently set in the field
37166 clearValue : function(){
37167 if(this.hiddenField){
37168 this.hiddenField.value = '';
37171 this.setRawValue('');
37172 this.lastSelectionText = '';
37173 this.applyEmptyText();
37177 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37178 * will be displayed in the field. If the value does not match the data value of an existing item,
37179 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37180 * Otherwise the field will be blank (although the value will still be set).
37181 * @param {String} value The value to match
37183 setValue : function(v){
37185 if(this.valueField){
37186 var r = this.findRecord(this.valueField, v);
37188 text = r.data[this.displayField];
37189 }else if(this.valueNotFoundText !== undefined){
37190 text = this.valueNotFoundText;
37193 this.lastSelectionText = text;
37194 if(this.hiddenField){
37195 this.hiddenField.value = v;
37197 Roo.form.ComboBox.superclass.setValue.call(this, text);
37201 * @property {Object} the last set data for the element
37206 * Sets the value of the field based on a object which is related to the record format for the store.
37207 * @param {Object} value the value to set as. or false on reset?
37209 setFromData : function(o){
37210 var dv = ''; // display value
37211 var vv = ''; // value value..
37213 if (this.displayField) {
37214 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37216 // this is an error condition!!!
37217 console.log('no value field set for '+ this.name);
37220 if(this.valueField){
37221 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37223 if(this.hiddenField){
37224 this.hiddenField.value = vv;
37226 this.lastSelectionText = dv;
37227 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37231 // no hidden field.. - we store the value in 'value', but still display
37232 // display field!!!!
37233 this.lastSelectionText = dv;
37234 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37240 reset : function(){
37241 // overridden so that last data is reset..
37242 this.setValue(this.originalValue);
37243 this.clearInvalid();
37244 this.lastData = false;
37247 findRecord : function(prop, value){
37249 if(this.store.getCount() > 0){
37250 this.store.each(function(r){
37251 if(r.data[prop] == value){
37261 onViewMove : function(e, t){
37262 this.inKeyMode = false;
37266 onViewOver : function(e, t){
37267 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37270 var item = this.view.findItemFromChild(t);
37272 var index = this.view.indexOf(item);
37273 this.select(index, false);
37278 onViewClick : function(doFocus){
37279 var index = this.view.getSelectedIndexes()[0];
37280 var r = this.store.getAt(index);
37282 this.onSelect(r, index);
37284 if(doFocus !== false && !this.blockFocus){
37290 restrictHeight : function(){
37291 this.innerList.dom.style.height = '';
37292 var inner = this.innerList.dom;
37293 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37294 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37295 this.list.beginUpdate();
37296 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37297 this.list.alignTo(this.el, this.listAlign);
37298 this.list.endUpdate();
37302 onEmptyResults : function(){
37307 * Returns true if the dropdown list is expanded, else false.
37309 isExpanded : function(){
37310 return this.list.isVisible();
37314 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37315 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37316 * @param {String} value The data value of the item to select
37317 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37318 * selected item if it is not currently in view (defaults to true)
37319 * @return {Boolean} True if the value matched an item in the list, else false
37321 selectByValue : function(v, scrollIntoView){
37322 if(v !== undefined && v !== null){
37323 var r = this.findRecord(this.valueField || this.displayField, v);
37325 this.select(this.store.indexOf(r), scrollIntoView);
37333 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37334 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37335 * @param {Number} index The zero-based index of the list item to select
37336 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37337 * selected item if it is not currently in view (defaults to true)
37339 select : function(index, scrollIntoView){
37340 this.selectedIndex = index;
37341 this.view.select(index);
37342 if(scrollIntoView !== false){
37343 var el = this.view.getNode(index);
37345 this.innerList.scrollChildIntoView(el, false);
37351 selectNext : function(){
37352 var ct = this.store.getCount();
37354 if(this.selectedIndex == -1){
37356 }else if(this.selectedIndex < ct-1){
37357 this.select(this.selectedIndex+1);
37363 selectPrev : function(){
37364 var ct = this.store.getCount();
37366 if(this.selectedIndex == -1){
37368 }else if(this.selectedIndex != 0){
37369 this.select(this.selectedIndex-1);
37375 onKeyUp : function(e){
37376 if(this.editable !== false && !e.isSpecialKey()){
37377 this.lastKey = e.getKey();
37378 this.dqTask.delay(this.queryDelay);
37383 validateBlur : function(){
37384 return !this.list || !this.list.isVisible();
37388 initQuery : function(){
37389 this.doQuery(this.getRawValue());
37393 doForce : function(){
37394 if(this.el.dom.value.length > 0){
37395 this.el.dom.value =
37396 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37397 this.applyEmptyText();
37402 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37403 * query allowing the query action to be canceled if needed.
37404 * @param {String} query The SQL query to execute
37405 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37406 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37407 * saved in the current store (defaults to false)
37409 doQuery : function(q, forceAll){
37410 if(q === undefined || q === null){
37415 forceAll: forceAll,
37419 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37423 forceAll = qe.forceAll;
37424 if(forceAll === true || (q.length >= this.minChars)){
37425 if(this.lastQuery != q){
37426 this.lastQuery = q;
37427 if(this.mode == 'local'){
37428 this.selectedIndex = -1;
37430 this.store.clearFilter();
37432 this.store.filter(this.displayField, q);
37436 this.store.baseParams[this.queryParam] = q;
37438 params: this.getParams(q)
37443 this.selectedIndex = -1;
37450 getParams : function(q){
37452 //p[this.queryParam] = q;
37455 p.limit = this.pageSize;
37461 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37463 collapse : function(){
37464 if(!this.isExpanded()){
37468 Roo.get(document).un('mousedown', this.collapseIf, this);
37469 Roo.get(document).un('mousewheel', this.collapseIf, this);
37470 this.fireEvent('collapse', this);
37474 collapseIf : function(e){
37475 if(!e.within(this.wrap) && !e.within(this.list)){
37481 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37483 expand : function(){
37484 if(this.isExpanded() || !this.hasFocus){
37487 this.list.alignTo(this.el, this.listAlign);
37489 Roo.get(document).on('mousedown', this.collapseIf, this);
37490 Roo.get(document).on('mousewheel', this.collapseIf, this);
37491 this.fireEvent('expand', this);
37495 // Implements the default empty TriggerField.onTriggerClick function
37496 onTriggerClick : function(){
37500 if(this.isExpanded()){
37502 if (!this.blockFocus) {
37507 this.hasFocus = true;
37508 if(this.triggerAction == 'all') {
37509 this.doQuery(this.allQuery, true);
37511 this.doQuery(this.getRawValue());
37513 if (!this.blockFocus) {
37520 * @cfg {Boolean} grow
37524 * @cfg {Number} growMin
37528 * @cfg {Number} growMax
37537 * Ext JS Library 1.1.1
37538 * Copyright(c) 2006-2007, Ext JS, LLC.
37540 * Originally Released Under LGPL - original licence link has changed is not relivant.
37543 * <script type="text/javascript">
37546 * @class Roo.form.Checkbox
37547 * @extends Roo.form.Field
37548 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
37550 * Creates a new Checkbox
37551 * @param {Object} config Configuration options
37553 Roo.form.Checkbox = function(config){
37554 Roo.form.Checkbox.superclass.constructor.call(this, config);
37558 * Fires when the checkbox is checked or unchecked.
37559 * @param {Roo.form.Checkbox} this This checkbox
37560 * @param {Boolean} checked The new checked value
37566 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
37568 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
37570 focusClass : undefined,
37572 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
37574 fieldClass: "x-form-field",
37576 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
37580 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37581 * {tag: "input", type: "checkbox", autocomplete: "off"})
37583 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
37585 * @cfg {String} boxLabel The text that appears beside the checkbox
37589 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
37593 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
37595 valueOff: '0', // value when not checked..
37597 actionMode : 'viewEl',
37600 itemCls : 'x-menu-check-item x-form-item',
37601 groupClass : 'x-menu-group-item',
37602 inputType : 'hidden',
37605 inSetChecked: false, // check that we are not calling self...
37607 inputElement: false, // real input element?
37608 basedOn: false, // ????
37610 isFormField: true, // not sure where this is needed!!!!
37612 onResize : function(){
37613 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
37614 if(!this.boxLabel){
37615 this.el.alignTo(this.wrap, 'c-c');
37619 initEvents : function(){
37620 Roo.form.Checkbox.superclass.initEvents.call(this);
37621 this.el.on("click", this.onClick, this);
37622 this.el.on("change", this.onClick, this);
37626 getResizeEl : function(){
37630 getPositionEl : function(){
37635 onRender : function(ct, position){
37636 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
37638 if(this.inputValue !== undefined){
37639 this.el.dom.value = this.inputValue;
37642 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
37643 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
37644 var viewEl = this.wrap.createChild({
37645 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
37646 this.viewEl = viewEl;
37647 this.wrap.on('click', this.onClick, this);
37649 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
37650 this.el.on('propertychange', this.setFromHidden, this); //ie
37655 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
37656 // viewEl.on('click', this.onClick, this);
37658 //if(this.checked){
37659 this.setChecked(this.checked);
37661 //this.checked = this.el.dom;
37667 initValue : Roo.emptyFn,
37670 * Returns the checked state of the checkbox.
37671 * @return {Boolean} True if checked, else false
37673 getValue : function(){
37675 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
37677 return this.valueOff;
37682 onClick : function(){
37683 this.setChecked(!this.checked);
37685 //if(this.el.dom.checked != this.checked){
37686 // this.setValue(this.el.dom.checked);
37691 * Sets the checked state of the checkbox.
37692 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
37694 setValue : function(v,suppressEvent){
37695 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
37696 //if(this.el && this.el.dom){
37697 // this.el.dom.checked = this.checked;
37698 // this.el.dom.defaultChecked = this.checked;
37700 this.setChecked(v === this.inputValue);
37701 //this.fireEvent("check", this, this.checked);
37704 setChecked : function(state,suppressEvent)
37706 if (this.inSetChecked) {
37707 this.checked = state;
37713 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
37715 this.checked = state;
37716 if(suppressEvent !== true){
37717 this.fireEvent('checkchange', this, state);
37719 this.inSetChecked = true;
37720 this.el.dom.value = state ? this.inputValue : this.valueOff;
37721 this.inSetChecked = false;
37724 // handle setting of hidden value by some other method!!?!?
37725 setFromHidden: function()
37730 //console.log("SET FROM HIDDEN");
37731 //alert('setFrom hidden');
37732 this.setValue(this.el.dom.value);
37735 onDestroy : function()
37738 Roo.get(this.viewEl).remove();
37741 Roo.form.Checkbox.superclass.onDestroy.call(this);
37746 * Ext JS Library 1.1.1
37747 * Copyright(c) 2006-2007, Ext JS, LLC.
37749 * Originally Released Under LGPL - original licence link has changed is not relivant.
37752 * <script type="text/javascript">
37756 * @class Roo.form.Radio
37757 * @extends Roo.form.Checkbox
37758 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
37759 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
37761 * Creates a new Radio
37762 * @param {Object} config Configuration options
37764 Roo.form.Radio = function(){
37765 Roo.form.Radio.superclass.constructor.apply(this, arguments);
37767 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
37768 inputType: 'radio',
37771 * If this radio is part of a group, it will return the selected value
37774 getGroupValue : function(){
37775 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
37777 });//<script type="text/javascript">
37780 * Ext JS Library 1.1.1
37781 * Copyright(c) 2006-2007, Ext JS, LLC.
37782 * licensing@extjs.com
37784 * http://www.extjs.com/license
37790 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
37791 * - IE ? - no idea how much works there.
37799 * @class Ext.form.HtmlEditor
37800 * @extends Ext.form.Field
37801 * Provides a lightweight HTML Editor component.
37802 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
37804 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
37805 * supported by this editor.</b><br/><br/>
37806 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
37807 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
37809 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
37811 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
37815 * @cfg {String} createLinkText The default text for the create link prompt
37817 createLinkText : 'Please enter the URL for the link:',
37819 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
37821 defaultLinkValue : 'http:/'+'/',
37827 // private properties
37828 validationEvent : false,
37830 initialized : false,
37832 sourceEditMode : false,
37833 onFocus : Roo.emptyFn,
37835 hideMode:'offsets',
37836 defaultAutoCreate : {
37838 style:"width:500px;height:300px;",
37839 autocomplete: "off"
37843 initComponent : function(){
37846 * @event initialize
37847 * Fires when the editor is fully initialized (including the iframe)
37848 * @param {HtmlEditor} this
37853 * Fires when the editor is first receives the focus. Any insertion must wait
37854 * until after this event.
37855 * @param {HtmlEditor} this
37859 * @event beforesync
37860 * Fires before the textarea is updated with content from the editor iframe. Return false
37861 * to cancel the sync.
37862 * @param {HtmlEditor} this
37863 * @param {String} html
37867 * @event beforepush
37868 * Fires before the iframe editor is updated with content from the textarea. Return false
37869 * to cancel the push.
37870 * @param {HtmlEditor} this
37871 * @param {String} html
37876 * Fires when the textarea is updated with content from the editor iframe.
37877 * @param {HtmlEditor} this
37878 * @param {String} html
37883 * Fires when the iframe editor is updated with content from the textarea.
37884 * @param {HtmlEditor} this
37885 * @param {String} html
37889 * @event editmodechange
37890 * Fires when the editor switches edit modes
37891 * @param {HtmlEditor} this
37892 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
37894 editmodechange: true,
37896 * @event editorevent
37897 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
37898 * @param {HtmlEditor} this
37905 * Protected method that will not generally be called directly. It
37906 * is called when the editor creates its toolbar. Override this method if you need to
37907 * add custom toolbar buttons.
37908 * @param {HtmlEditor} editor
37910 createToolbar : function(editor){
37911 if (!editor.toolbars || !editor.toolbars.length) {
37912 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
37915 for (var i =0 ; i < editor.toolbars.length;i++) {
37916 editor.toolbars[i].init(editor);
37923 * Protected method that will not generally be called directly. It
37924 * is called when the editor initializes the iframe with HTML contents. Override this method if you
37925 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
37927 getDocMarkup : function(){
37928 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
37932 onRender : function(ct, position){
37933 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
37934 this.el.dom.style.border = '0 none';
37935 this.el.dom.setAttribute('tabIndex', -1);
37936 this.el.addClass('x-hidden');
37937 if(Roo.isIE){ // fix IE 1px bogus margin
37938 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
37940 this.wrap = this.el.wrap({
37941 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
37944 this.frameId = Roo.id();
37945 this.createToolbar(this);
37952 var iframe = this.wrap.createChild({
37955 name: this.frameId,
37956 frameBorder : 'no',
37957 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
37960 // console.log(iframe);
37961 //this.wrap.dom.appendChild(iframe);
37963 this.iframe = iframe.dom;
37965 this.assignDocWin();
37967 this.doc.designMode = 'on';
37970 this.doc.write(this.getDocMarkup());
37974 var task = { // must defer to wait for browser to be ready
37976 //console.log("run task?" + this.doc.readyState);
37977 this.assignDocWin();
37978 if(this.doc.body || this.doc.readyState == 'complete'){
37982 this.doc.designMode="on";
37986 Roo.TaskMgr.stop(task);
37987 this.initEditor.defer(10, this);
37994 Roo.TaskMgr.start(task);
37997 this.setSize(this.el.getSize());
38002 onResize : function(w, h){
38003 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38004 if(this.el && this.iframe){
38005 if(typeof w == 'number'){
38006 var aw = w - this.wrap.getFrameWidth('lr');
38007 this.el.setWidth(this.adjustWidth('textarea', aw));
38008 this.iframe.style.width = aw + 'px';
38010 if(typeof h == 'number'){
38012 for (var i =0; i < this.toolbars.length;i++) {
38013 // fixme - ask toolbars for heights?
38014 tbh += this.toolbars[i].tb.el.getHeight();
38020 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38021 this.el.setHeight(this.adjustWidth('textarea', ah));
38022 this.iframe.style.height = ah + 'px';
38024 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38031 * Toggles the editor between standard and source edit mode.
38032 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38034 toggleSourceEdit : function(sourceEditMode){
38036 this.sourceEditMode = sourceEditMode === true;
38038 if(this.sourceEditMode){
38041 this.iframe.className = 'x-hidden';
38042 this.el.removeClass('x-hidden');
38043 this.el.dom.removeAttribute('tabIndex');
38048 this.iframe.className = '';
38049 this.el.addClass('x-hidden');
38050 this.el.dom.setAttribute('tabIndex', -1);
38053 this.setSize(this.wrap.getSize());
38054 this.fireEvent('editmodechange', this, this.sourceEditMode);
38057 // private used internally
38058 createLink : function(){
38059 var url = prompt(this.createLinkText, this.defaultLinkValue);
38060 if(url && url != 'http:/'+'/'){
38061 this.relayCmd('createlink', url);
38065 // private (for BoxComponent)
38066 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38068 // private (for BoxComponent)
38069 getResizeEl : function(){
38073 // private (for BoxComponent)
38074 getPositionEl : function(){
38079 initEvents : function(){
38080 this.originalValue = this.getValue();
38084 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38087 markInvalid : Roo.emptyFn,
38089 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
38092 clearInvalid : Roo.emptyFn,
38094 setValue : function(v){
38095 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
38100 * Protected method that will not generally be called directly. If you need/want
38101 * custom HTML cleanup, this is the method you should override.
38102 * @param {String} html The HTML to be cleaned
38103 * return {String} The cleaned HTML
38105 cleanHtml : function(html){
38106 html = String(html);
38107 if(html.length > 5){
38108 if(Roo.isSafari){ // strip safari nonsense
38109 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
38112 if(html == ' '){
38119 * Protected method that will not generally be called directly. Syncs the contents
38120 * of the editor iframe with the textarea.
38122 syncValue : function(){
38123 if(this.initialized){
38124 var bd = (this.doc.body || this.doc.documentElement);
38125 var html = bd.innerHTML;
38127 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38128 var m = bs.match(/text-align:(.*?);/i);
38130 html = '<div style="'+m[0]+'">' + html + '</div>';
38133 html = this.cleanHtml(html);
38134 if(this.fireEvent('beforesync', this, html) !== false){
38135 this.el.dom.value = html;
38136 this.fireEvent('sync', this, html);
38142 * Protected method that will not generally be called directly. Pushes the value of the textarea
38143 * into the iframe editor.
38145 pushValue : function(){
38146 if(this.initialized){
38147 var v = this.el.dom.value;
38151 if(this.fireEvent('beforepush', this, v) !== false){
38152 (this.doc.body || this.doc.documentElement).innerHTML = v;
38153 this.fireEvent('push', this, v);
38159 deferFocus : function(){
38160 this.focus.defer(10, this);
38164 focus : function(){
38165 if(this.win && !this.sourceEditMode){
38172 assignDocWin: function()
38174 var iframe = this.iframe;
38177 this.doc = iframe.contentWindow.document;
38178 this.win = iframe.contentWindow;
38180 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38181 this.win = Roo.get(this.frameId).dom.contentWindow;
38186 initEditor : function(){
38187 //console.log("INIT EDITOR");
38188 this.assignDocWin();
38192 this.doc.designMode="on";
38194 this.doc.write(this.getDocMarkup());
38197 var dbody = (this.doc.body || this.doc.documentElement);
38198 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38199 // this copies styles from the containing element into thsi one..
38200 // not sure why we need all of this..
38201 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38202 ss['background-attachment'] = 'fixed'; // w3c
38203 dbody.bgProperties = 'fixed'; // ie
38204 Roo.DomHelper.applyStyles(dbody, ss);
38205 Roo.EventManager.on(this.doc, {
38206 'mousedown': this.onEditorEvent,
38207 'dblclick': this.onEditorEvent,
38208 'click': this.onEditorEvent,
38209 'keyup': this.onEditorEvent,
38214 Roo.EventManager.on(this.doc, 'keypress', this.applyCommand, this);
38216 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38217 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38219 this.initialized = true;
38221 this.fireEvent('initialize', this);
38226 onDestroy : function(){
38232 for (var i =0; i < this.toolbars.length;i++) {
38233 // fixme - ask toolbars for heights?
38234 this.toolbars[i].onDestroy();
38237 this.wrap.dom.innerHTML = '';
38238 this.wrap.remove();
38243 onFirstFocus : function(){
38245 this.assignDocWin();
38248 this.activated = true;
38249 for (var i =0; i < this.toolbars.length;i++) {
38250 this.toolbars[i].onFirstFocus();
38253 if(Roo.isGecko){ // prevent silly gecko errors
38255 var s = this.win.getSelection();
38256 if(!s.focusNode || s.focusNode.nodeType != 3){
38257 var r = s.getRangeAt(0);
38258 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38263 this.execCmd('useCSS', true);
38264 this.execCmd('styleWithCSS', false);
38267 this.fireEvent('activate', this);
38271 adjustFont: function(btn){
38272 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38273 //if(Roo.isSafari){ // safari
38276 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38277 if(Roo.isSafari){ // safari
38278 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38279 v = (v < 10) ? 10 : v;
38280 v = (v > 48) ? 48 : v;
38281 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38286 v = Math.max(1, v+adjust);
38288 this.execCmd('FontSize', v );
38291 onEditorEvent : function(e){
38292 this.fireEvent('editorevent', this, e);
38293 // this.updateToolbar();
38297 insertTag : function(tg)
38299 // could be a bit smarter... -> wrap the current selected tRoo..
38301 this.execCmd("formatblock", tg);
38305 insertText : function(txt)
38309 range = this.createRange();
38310 range.deleteContents();
38311 //alert(Sender.getAttribute('label'));
38313 range.insertNode(this.doc.createTextNode(txt));
38317 relayBtnCmd : function(btn){
38318 this.relayCmd(btn.cmd);
38322 * Executes a Midas editor command on the editor document and performs necessary focus and
38323 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38324 * @param {String} cmd The Midas command
38325 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38327 relayCmd : function(cmd, value){
38329 this.execCmd(cmd, value);
38330 this.fireEvent('editorevent', this);
38331 //this.updateToolbar();
38336 * Executes a Midas editor command directly on the editor document.
38337 * For visual commands, you should use {@link #relayCmd} instead.
38338 * <b>This should only be called after the editor is initialized.</b>
38339 * @param {String} cmd The Midas command
38340 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38342 execCmd : function(cmd, value){
38343 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38348 applyCommand : function(e){
38350 var c = e.getCharCode(), cmd;
38352 c = String.fromCharCode(c);
38368 e.preventDefault();
38375 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38377 * @param {String} text
38379 insertAtCursor : function(text){
38380 if(!this.activated){
38385 var r = this.doc.selection.createRange();
38392 }else if(Roo.isGecko || Roo.isOpera){
38394 this.execCmd('InsertHTML', text);
38396 }else if(Roo.isSafari){
38397 this.execCmd('InsertText', text);
38403 fixKeys : function(){ // load time branching for fastest keydown performance
38405 return function(e){
38406 var k = e.getKey(), r;
38409 r = this.doc.selection.createRange();
38412 r.pasteHTML('    ');
38415 }else if(k == e.ENTER){
38416 r = this.doc.selection.createRange();
38418 var target = r.parentElement();
38419 if(!target || target.tagName.toLowerCase() != 'li'){
38421 r.pasteHTML('<br />');
38428 }else if(Roo.isOpera){
38429 return function(e){
38430 var k = e.getKey();
38434 this.execCmd('InsertHTML','    ');
38438 }else if(Roo.isSafari){
38439 return function(e){
38440 var k = e.getKey();
38443 this.execCmd('InsertText','\t');
38450 getAllAncestors: function()
38452 var p = this.getSelectedNode();
38455 a.push(p); // push blank onto stack..
38456 p = this.getParentElement();
38460 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38464 a.push(this.doc.body);
38468 lastSelNode : false,
38471 getSelection : function()
38473 this.assignDocWin();
38474 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38477 getSelectedNode: function()
38479 // this may only work on Gecko!!!
38481 // should we cache this!!!!
38486 var range = this.createRange(this.getSelection());
38489 var parent = range.parentElement();
38491 var testRange = range.duplicate();
38492 testRange.moveToElementText(parent);
38493 if (testRange.inRange(range)) {
38496 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
38499 parent = parent.parentElement;
38505 var ar = range.endContainer.childNodes;
38507 ar = range.commonAncestorContainer.childNodes;
38508 //alert(ar.length);
38511 var other_nodes = [];
38512 var has_other_nodes = false;
38513 for (var i=0;i<ar.length;i++) {
38514 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
38517 // fullly contained node.
38519 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
38524 // probably selected..
38525 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
38526 other_nodes.push(ar[i]);
38529 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
38534 has_other_nodes = true;
38536 if (!nodes.length && other_nodes.length) {
38537 nodes= other_nodes;
38539 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
38545 createRange: function(sel)
38547 // this has strange effects when using with
38548 // top toolbar - not sure if it's a great idea.
38549 //this.editor.contentWindow.focus();
38550 if (typeof sel != "undefined") {
38552 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
38554 return this.doc.createRange();
38557 return this.doc.createRange();
38560 getParentElement: function()
38563 this.assignDocWin();
38564 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
38566 var range = this.createRange(sel);
38569 var p = range.commonAncestorContainer;
38570 while (p.nodeType == 3) { // text node
38582 // BC Hacks - cause I cant work out what i was trying to do..
38583 rangeIntersectsNode : function(range, node)
38585 var nodeRange = node.ownerDocument.createRange();
38587 nodeRange.selectNode(node);
38590 nodeRange.selectNodeContents(node);
38593 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
38594 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
38596 rangeCompareNode : function(range, node) {
38597 var nodeRange = node.ownerDocument.createRange();
38599 nodeRange.selectNode(node);
38601 nodeRange.selectNodeContents(node);
38603 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
38604 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
38606 if (nodeIsBefore && !nodeIsAfter)
38608 if (!nodeIsBefore && nodeIsAfter)
38610 if (nodeIsBefore && nodeIsAfter)
38618 // hide stuff that is not compatible
38632 * @event specialkey
38636 * @cfg {String} fieldClass @hide
38639 * @cfg {String} focusClass @hide
38642 * @cfg {String} autoCreate @hide
38645 * @cfg {String} inputType @hide
38648 * @cfg {String} invalidClass @hide
38651 * @cfg {String} invalidText @hide
38654 * @cfg {String} msgFx @hide
38657 * @cfg {String} validateOnBlur @hide
38659 });// <script type="text/javascript">
38662 * Ext JS Library 1.1.1
38663 * Copyright(c) 2006-2007, Ext JS, LLC.
38669 * @class Roo.form.HtmlEditorToolbar1
38674 new Roo.form.HtmlEditor({
38677 new Roo.form.HtmlEditorToolbar1({
38678 disable : { fonts: 1 , format: 1, ..., ... , ...],
38684 * @cfg {Object} disable List of elements to disable..
38685 * @cfg {Array} btns List of additional buttons.
38689 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
38692 Roo.form.HtmlEditor.ToolbarStandard = function(config)
38695 Roo.apply(this, config);
38696 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
38697 // dont call parent... till later.
38700 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
38708 * @cfg {Object} disable List of toolbar elements to disable
38713 * @cfg {Array} fontFamilies An array of available font families
38731 // "á" , ?? a acute?
38736 "°" // , // degrees
38738 // "é" , // e ecute
38739 // "ú" , // u ecute?
38742 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
38743 "input:submit", "input:button", "select", "textarea", "label" ],
38746 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
38748 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
38751 * @cfg {String} defaultFont default font to use.
38753 defaultFont: 'tahoma',
38755 fontSelect : false,
38758 formatCombo : false,
38760 init : function(editor)
38762 this.editor = editor;
38765 var fid = editor.frameId;
38767 function btn(id, toggle, handler){
38768 var xid = fid + '-'+ id ;
38772 cls : 'x-btn-icon x-edit-'+id,
38773 enableToggle:toggle !== false,
38774 scope: editor, // was editor...
38775 handler:handler||editor.relayBtnCmd,
38776 clickEvent:'mousedown',
38777 tooltip: etb.buttonTips[id] || undefined, ///tips ???
38784 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
38786 // stop form submits
38787 tb.el.on('click', function(e){
38788 e.preventDefault(); // what does this do?
38791 if(!this.disable.font && !Roo.isSafari){
38792 /* why no safari for fonts
38793 editor.fontSelect = tb.el.createChild({
38796 cls:'x-font-select',
38797 html: editor.createFontOptions()
38799 editor.fontSelect.on('change', function(){
38800 var font = editor.fontSelect.dom.value;
38801 editor.relayCmd('fontname', font);
38802 editor.deferFocus();
38805 editor.fontSelect.dom,
38810 if(!this.disable.formats){
38811 this.formatCombo = new Roo.form.ComboBox({
38812 store: new Roo.data.SimpleStore({
38815 data : this.formats // from states.js
38818 //autoCreate : {tag: "div", size: "20"},
38819 displayField:'tag',
38823 triggerAction: 'all',
38824 emptyText:'Add tag',
38825 selectOnFocus:true,
38828 'select': function(c, r, i) {
38829 editor.insertTag(r.get('tag'));
38835 tb.addField(this.formatCombo);
38839 if(!this.disable.format){
38846 if(!this.disable.fontSize){
38851 btn('increasefontsize', false, editor.adjustFont),
38852 btn('decreasefontsize', false, editor.adjustFont)
38857 if(this.disable.colors){
38860 id:editor.frameId +'-forecolor',
38861 cls:'x-btn-icon x-edit-forecolor',
38862 clickEvent:'mousedown',
38863 tooltip: this.buttonTips['forecolor'] || undefined,
38865 menu : new Roo.menu.ColorMenu({
38866 allowReselect: true,
38867 focus: Roo.emptyFn,
38870 selectHandler: function(cp, color){
38871 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
38872 editor.deferFocus();
38875 clickEvent:'mousedown'
38878 id:editor.frameId +'backcolor',
38879 cls:'x-btn-icon x-edit-backcolor',
38880 clickEvent:'mousedown',
38881 tooltip: this.buttonTips['backcolor'] || undefined,
38883 menu : new Roo.menu.ColorMenu({
38884 focus: Roo.emptyFn,
38887 allowReselect: true,
38888 selectHandler: function(cp, color){
38890 editor.execCmd('useCSS', false);
38891 editor.execCmd('hilitecolor', color);
38892 editor.execCmd('useCSS', true);
38893 editor.deferFocus();
38895 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
38896 Roo.isSafari || Roo.isIE ? '#'+color : color);
38897 editor.deferFocus();
38901 clickEvent:'mousedown'
38906 // now add all the items...
38909 if(!this.disable.alignments){
38912 btn('justifyleft'),
38913 btn('justifycenter'),
38914 btn('justifyright')
38918 //if(!Roo.isSafari){
38919 if(!this.disable.links){
38922 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
38926 if(!this.disable.lists){
38929 btn('insertorderedlist'),
38930 btn('insertunorderedlist')
38933 if(!this.disable.sourceEdit){
38936 btn('sourceedit', true, function(btn){
38937 this.toggleSourceEdit(btn.pressed);
38944 // special menu.. - needs to be tidied up..
38945 if (!this.disable.special) {
38948 cls: 'x-edit-none',
38953 for (var i =0; i < this.specialChars.length; i++) {
38954 smenu.menu.items.push({
38956 text: this.specialChars[i],
38957 handler: function(a,b) {
38958 editor.insertAtCursor(String.fromCharCode(a.text.replace('&#','').replace(';', '')));
38970 for(var i =0; i< this.btns.length;i++) {
38971 var b = this.btns[i];
38972 b.cls = 'x-edit-none';
38981 // disable everything...
38983 this.tb.items.each(function(item){
38984 if(item.id != editor.frameId+ '-sourceedit'){
38988 this.rendered = true;
38990 // the all the btns;
38991 editor.on('editorevent', this.updateToolbar, this);
38992 // other toolbars need to implement this..
38993 //editor.on('editmodechange', this.updateToolbar, this);
38999 * Protected method that will not generally be called directly. It triggers
39000 * a toolbar update by reading the markup state of the current selection in the editor.
39002 updateToolbar: function(){
39004 if(!this.editor.activated){
39005 this.editor.onFirstFocus();
39009 var btns = this.tb.items.map,
39010 doc = this.editor.doc,
39011 frameId = this.editor.frameId;
39013 if(!this.disable.font && !Roo.isSafari){
39015 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
39016 if(name != this.fontSelect.dom.value){
39017 this.fontSelect.dom.value = name;
39021 if(!this.disable.format){
39022 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
39023 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
39024 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
39026 if(!this.disable.alignments){
39027 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
39028 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
39029 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
39031 if(!Roo.isSafari && !this.disable.lists){
39032 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
39033 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
39036 var ans = this.editor.getAllAncestors();
39037 if (this.formatCombo) {
39040 var store = this.formatCombo.store;
39041 this.formatCombo.setValue("");
39042 for (var i =0; i < ans.length;i++) {
39043 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), true).length) {
39045 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
39053 // hides menus... - so this cant be on a menu...
39054 Roo.menu.MenuMgr.hideAll();
39056 //this.editorsyncValue();
39060 createFontOptions : function(){
39061 var buf = [], fs = this.fontFamilies, ff, lc;
39062 for(var i = 0, len = fs.length; i< len; i++){
39064 lc = ff.toLowerCase();
39066 '<option value="',lc,'" style="font-family:',ff,';"',
39067 (this.defaultFont == lc ? ' selected="true">' : '>'),
39072 return buf.join('');
39075 toggleSourceEdit : function(sourceEditMode){
39076 if(sourceEditMode === undefined){
39077 sourceEditMode = !this.sourceEditMode;
39079 this.sourceEditMode = sourceEditMode === true;
39080 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
39081 // just toggle the button?
39082 if(btn.pressed !== this.editor.sourceEditMode){
39083 btn.toggle(this.editor.sourceEditMode);
39087 if(this.sourceEditMode){
39088 this.tb.items.each(function(item){
39089 if(item.cmd != 'sourceedit'){
39095 if(this.initialized){
39096 this.tb.items.each(function(item){
39102 // tell the editor that it's been pressed..
39103 this.editor.toggleSourceEdit(sourceEditMode);
39107 * Object collection of toolbar tooltips for the buttons in the editor. The key
39108 * is the command id associated with that button and the value is a valid QuickTips object.
39113 title: 'Bold (Ctrl+B)',
39114 text: 'Make the selected text bold.',
39115 cls: 'x-html-editor-tip'
39118 title: 'Italic (Ctrl+I)',
39119 text: 'Make the selected text italic.',
39120 cls: 'x-html-editor-tip'
39128 title: 'Bold (Ctrl+B)',
39129 text: 'Make the selected text bold.',
39130 cls: 'x-html-editor-tip'
39133 title: 'Italic (Ctrl+I)',
39134 text: 'Make the selected text italic.',
39135 cls: 'x-html-editor-tip'
39138 title: 'Underline (Ctrl+U)',
39139 text: 'Underline the selected text.',
39140 cls: 'x-html-editor-tip'
39142 increasefontsize : {
39143 title: 'Grow Text',
39144 text: 'Increase the font size.',
39145 cls: 'x-html-editor-tip'
39147 decreasefontsize : {
39148 title: 'Shrink Text',
39149 text: 'Decrease the font size.',
39150 cls: 'x-html-editor-tip'
39153 title: 'Text Highlight Color',
39154 text: 'Change the background color of the selected text.',
39155 cls: 'x-html-editor-tip'
39158 title: 'Font Color',
39159 text: 'Change the color of the selected text.',
39160 cls: 'x-html-editor-tip'
39163 title: 'Align Text Left',
39164 text: 'Align text to the left.',
39165 cls: 'x-html-editor-tip'
39168 title: 'Center Text',
39169 text: 'Center text in the editor.',
39170 cls: 'x-html-editor-tip'
39173 title: 'Align Text Right',
39174 text: 'Align text to the right.',
39175 cls: 'x-html-editor-tip'
39177 insertunorderedlist : {
39178 title: 'Bullet List',
39179 text: 'Start a bulleted list.',
39180 cls: 'x-html-editor-tip'
39182 insertorderedlist : {
39183 title: 'Numbered List',
39184 text: 'Start a numbered list.',
39185 cls: 'x-html-editor-tip'
39188 title: 'Hyperlink',
39189 text: 'Make the selected text a hyperlink.',
39190 cls: 'x-html-editor-tip'
39193 title: 'Source Edit',
39194 text: 'Switch to source editing mode.',
39195 cls: 'x-html-editor-tip'
39199 onDestroy : function(){
39202 this.tb.items.each(function(item){
39204 item.menu.removeAll();
39206 item.menu.el.destroy();
39214 onFirstFocus: function() {
39215 this.tb.items.each(function(item){
39224 // <script type="text/javascript">
39227 * Ext JS Library 1.1.1
39228 * Copyright(c) 2006-2007, Ext JS, LLC.
39235 * @class Roo.form.HtmlEditor.ToolbarContext
39240 new Roo.form.HtmlEditor({
39243 new Roo.form.HtmlEditor.ToolbarStandard(),
39244 new Roo.form.HtmlEditor.ToolbarContext()
39249 * @config : {Object} disable List of elements to disable.. (not done yet.)
39254 Roo.form.HtmlEditor.ToolbarContext = function(config)
39257 Roo.apply(this, config);
39258 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39259 // dont call parent... till later.
39261 Roo.form.HtmlEditor.ToolbarContext.types = {
39273 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39335 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
39340 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
39404 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
39412 * @cfg {Object} disable List of toolbar elements to disable
39421 init : function(editor)
39423 this.editor = editor;
39426 var fid = editor.frameId;
39428 function btn(id, toggle, handler){
39429 var xid = fid + '-'+ id ;
39433 cls : 'x-btn-icon x-edit-'+id,
39434 enableToggle:toggle !== false,
39435 scope: editor, // was editor...
39436 handler:handler||editor.relayBtnCmd,
39437 clickEvent:'mousedown',
39438 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39442 // create a new element.
39443 var wdiv = editor.wrap.createChild({
39445 }, editor.wrap.dom.firstChild.nextSibling, true);
39447 // can we do this more than once??
39449 // stop form submits
39452 // disable everything...
39453 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39454 this.toolbars = {};
39456 for (var i in ty) {
39457 this.toolbars[i] = this.buildToolbar(ty[i],i);
39459 this.tb = this.toolbars.BODY;
39463 this.rendered = true;
39465 // the all the btns;
39466 editor.on('editorevent', this.updateToolbar, this);
39467 // other toolbars need to implement this..
39468 //editor.on('editmodechange', this.updateToolbar, this);
39474 * Protected method that will not generally be called directly. It triggers
39475 * a toolbar update by reading the markup state of the current selection in the editor.
39477 updateToolbar: function(){
39479 if(!this.editor.activated){
39480 this.editor.onFirstFocus();
39485 var ans = this.editor.getAllAncestors();
39488 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39489 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
39490 sel = sel ? sel : this.editor.doc.body;
39491 sel = sel.tagName.length ? sel : this.editor.doc.body;
39492 var tn = sel.tagName.toUpperCase();
39493 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
39494 tn = sel.tagName.toUpperCase();
39495 if (this.tb.name == tn) {
39496 return; // no change
39499 ///console.log("show: " + tn);
39500 this.tb = this.toolbars[tn];
39502 this.tb.fields.each(function(e) {
39503 e.setValue(sel.getAttribute(e.name));
39505 this.tb.selectedNode = sel;
39508 Roo.menu.MenuMgr.hideAll();
39510 //this.editorsyncValue();
39515 onDestroy : function(){
39518 this.tb.items.each(function(item){
39520 item.menu.removeAll();
39522 item.menu.el.destroy();
39530 onFirstFocus: function() {
39531 // need to do this for all the toolbars..
39532 this.tb.items.each(function(item){
39536 buildToolbar: function(tlist, nm)
39538 var editor = this.editor;
39539 // create a new element.
39540 var wdiv = editor.wrap.createChild({
39542 }, editor.wrap.dom.firstChild.nextSibling, true);
39545 var tb = new Roo.Toolbar(wdiv);
39546 tb.add(nm+ ": ");
39547 for (var i in tlist) {
39548 var item = tlist[i];
39549 tb.add(item.title + ": ");
39554 tb.addField( new Roo.form.ComboBox({
39555 store: new Roo.data.SimpleStore({
39558 data : item.opts // from states.js
39561 displayField:'val',
39565 triggerAction: 'all',
39566 emptyText:'Select',
39567 selectOnFocus:true,
39568 width: item.width ? item.width : 130,
39570 'select': function(c, r, i) {
39571 tb.selectedNode.setAttribute(c.name, r.get('val'));
39582 tb.addField( new Roo.form.TextField({
39585 //allowBlank:false,
39590 tb.addField( new Roo.form.TextField({
39596 'change' : function(f, nv, ov) {
39597 tb.selectedNode.setAttribute(f.name, nv);
39603 tb.el.on('click', function(e){
39604 e.preventDefault(); // what does this do?
39606 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
39609 // dont need to disable them... as they will get hidden
39626 * Ext JS Library 1.1.1
39627 * Copyright(c) 2006-2007, Ext JS, LLC.
39629 * Originally Released Under LGPL - original licence link has changed is not relivant.
39632 * <script type="text/javascript">
39636 * @class Roo.form.BasicForm
39637 * @extends Roo.util.Observable
39638 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
39640 * @param {String/HTMLElement/Roo.Element} el The form element or its id
39641 * @param {Object} config Configuration options
39643 Roo.form.BasicForm = function(el, config){
39644 this.allItems = [];
39645 this.childForms = [];
39646 Roo.apply(this, config);
39648 * The Roo.form.Field items in this form.
39649 * @type MixedCollection
39653 this.items = new Roo.util.MixedCollection(false, function(o){
39654 return o.id || (o.id = Roo.id());
39658 * @event beforeaction
39659 * Fires before any action is performed. Return false to cancel the action.
39660 * @param {Form} this
39661 * @param {Action} action The action to be performed
39663 beforeaction: true,
39665 * @event actionfailed
39666 * Fires when an action fails.
39667 * @param {Form} this
39668 * @param {Action} action The action that failed
39670 actionfailed : true,
39672 * @event actioncomplete
39673 * Fires when an action is completed.
39674 * @param {Form} this
39675 * @param {Action} action The action that completed
39677 actioncomplete : true
39682 Roo.form.BasicForm.superclass.constructor.call(this);
39685 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
39687 * @cfg {String} method
39688 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
39691 * @cfg {DataReader} reader
39692 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
39693 * This is optional as there is built-in support for processing JSON.
39696 * @cfg {DataReader} errorReader
39697 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
39698 * This is completely optional as there is built-in support for processing JSON.
39701 * @cfg {String} url
39702 * The URL to use for form actions if one isn't supplied in the action options.
39705 * @cfg {Boolean} fileUpload
39706 * Set to true if this form is a file upload.
39709 * @cfg {Object} baseParams
39710 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
39713 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
39718 activeAction : null,
39721 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
39722 * or setValues() data instead of when the form was first created.
39724 trackResetOnLoad : false,
39728 * childForms - used for multi-tab forms
39731 childForms : false,
39734 * allItems - full list of fields.
39740 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
39741 * element by passing it or its id or mask the form itself by passing in true.
39744 waitMsgTarget : undefined,
39747 initEl : function(el){
39748 this.el = Roo.get(el);
39749 this.id = this.el.id || Roo.id();
39750 this.el.on('submit', this.onSubmit, this);
39751 this.el.addClass('x-form');
39755 onSubmit : function(e){
39760 * Returns true if client-side validation on the form is successful.
39763 isValid : function(){
39765 this.items.each(function(f){
39774 * Returns true if any fields in this form have changed since their original load.
39777 isDirty : function(){
39779 this.items.each(function(f){
39789 * Performs a predefined action (submit or load) or custom actions you define on this form.
39790 * @param {String} actionName The name of the action type
39791 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
39792 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
39793 * accept other config options):
39795 Property Type Description
39796 ---------------- --------------- ----------------------------------------------------------------------------------
39797 url String The url for the action (defaults to the form's url)
39798 method String The form method to use (defaults to the form's method, or POST if not defined)
39799 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
39800 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
39801 validate the form on the client (defaults to false)
39803 * @return {BasicForm} this
39805 doAction : function(action, options){
39806 if(typeof action == 'string'){
39807 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
39809 if(this.fireEvent('beforeaction', this, action) !== false){
39810 this.beforeAction(action);
39811 action.run.defer(100, action);
39817 * Shortcut to do a submit action.
39818 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39819 * @return {BasicForm} this
39821 submit : function(options){
39822 this.doAction('submit', options);
39827 * Shortcut to do a load action.
39828 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39829 * @return {BasicForm} this
39831 load : function(options){
39832 this.doAction('load', options);
39837 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
39838 * @param {Record} record The record to edit
39839 * @return {BasicForm} this
39841 updateRecord : function(record){
39842 record.beginEdit();
39843 var fs = record.fields;
39844 fs.each(function(f){
39845 var field = this.findField(f.name);
39847 record.set(f.name, field.getValue());
39855 * Loads an Roo.data.Record into this form.
39856 * @param {Record} record The record to load
39857 * @return {BasicForm} this
39859 loadRecord : function(record){
39860 this.setValues(record.data);
39865 beforeAction : function(action){
39866 var o = action.options;
39868 if(this.waitMsgTarget === true){
39869 this.el.mask(o.waitMsg, 'x-mask-loading');
39870 }else if(this.waitMsgTarget){
39871 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
39872 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
39874 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
39880 afterAction : function(action, success){
39881 this.activeAction = null;
39882 var o = action.options;
39884 if(this.waitMsgTarget === true){
39886 }else if(this.waitMsgTarget){
39887 this.waitMsgTarget.unmask();
39889 Roo.MessageBox.updateProgress(1);
39890 Roo.MessageBox.hide();
39897 Roo.callback(o.success, o.scope, [this, action]);
39898 this.fireEvent('actioncomplete', this, action);
39900 Roo.callback(o.failure, o.scope, [this, action]);
39901 this.fireEvent('actionfailed', this, action);
39906 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
39907 * @param {String} id The value to search for
39910 findField : function(id){
39911 var field = this.items.get(id);
39913 this.items.each(function(f){
39914 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
39920 return field || null;
39924 * Add a secondary form to this one,
39925 * Used to provide tabbed forms. One form is primary, with hidden values
39926 * which mirror the elements from the other forms.
39928 * @param {Roo.form.Form} form to add.
39931 addForm : function(form){
39933 this.childForms.push(form);
39934 Roo.each(form.allItems, function (fe) {
39936 if (this.findField(fe.name)) { // already added..
39939 this.add( new Roo.form.Hidden({
39946 * Mark fields in this form invalid in bulk.
39947 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
39948 * @return {BasicForm} this
39950 markInvalid : function(errors){
39951 if(errors instanceof Array){
39952 for(var i = 0, len = errors.length; i < len; i++){
39953 var fieldError = errors[i];
39954 var f = this.findField(fieldError.id);
39956 f.markInvalid(fieldError.msg);
39962 if(typeof errors[id] != 'function' && (field = this.findField(id))){
39963 field.markInvalid(errors[id]);
39967 Roo.each(this.childForms || [], function (f) {
39968 f.markInvalid(errors);
39975 * Set values for fields in this form in bulk.
39976 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
39977 * @return {BasicForm} this
39979 setValues : function(values){
39980 if(values instanceof Array){ // array of objects
39981 for(var i = 0, len = values.length; i < len; i++){
39983 var f = this.findField(v.id);
39985 f.setValue(v.value);
39986 if(this.trackResetOnLoad){
39987 f.originalValue = f.getValue();
39991 }else{ // object hash
39994 if(typeof values[id] != 'function' && (field = this.findField(id))){
39996 if (field.setFromData &&
39997 field.valueField &&
39998 field.displayField &&
39999 // combos' with local stores can
40000 // be queried via setValue()
40001 // to set their value..
40002 (field.store && !field.store.isLocal)
40006 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
40007 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
40008 field.setFromData(sd);
40011 field.setValue(values[id]);
40015 if(this.trackResetOnLoad){
40016 field.originalValue = field.getValue();
40022 Roo.each(this.childForms || [], function (f) {
40023 f.setValues(values);
40030 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
40031 * they are returned as an array.
40032 * @param {Boolean} asString
40035 getValues : function(asString){
40036 if (this.childForms) {
40037 // copy values from the child forms
40038 Roo.each(this.childForms, function (f) {
40040 Roo.each(f.allFields, function (e) {
40041 if (e.name && e.getValue && this.findField(e.name)) {
40042 this.findField(e.name).setValue(e.getValue());
40051 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
40052 if(asString === true){
40055 return Roo.urlDecode(fs);
40059 * Clears all invalid messages in this form.
40060 * @return {BasicForm} this
40062 clearInvalid : function(){
40063 this.items.each(function(f){
40067 Roo.each(this.childForms || [], function (f) {
40076 * Resets this form.
40077 * @return {BasicForm} this
40079 reset : function(){
40080 this.items.each(function(f){
40084 Roo.each(this.childForms || [], function (f) {
40093 * Add Roo.form components to this form.
40094 * @param {Field} field1
40095 * @param {Field} field2 (optional)
40096 * @param {Field} etc (optional)
40097 * @return {BasicForm} this
40100 this.items.addAll(Array.prototype.slice.call(arguments, 0));
40106 * Removes a field from the items collection (does NOT remove its markup).
40107 * @param {Field} field
40108 * @return {BasicForm} this
40110 remove : function(field){
40111 this.items.remove(field);
40116 * Looks at the fields in this form, checks them for an id attribute,
40117 * and calls applyTo on the existing dom element with that id.
40118 * @return {BasicForm} this
40120 render : function(){
40121 this.items.each(function(f){
40122 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
40130 * Calls {@link Ext#apply} for all fields in this form with the passed object.
40131 * @param {Object} values
40132 * @return {BasicForm} this
40134 applyToFields : function(o){
40135 this.items.each(function(f){
40142 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
40143 * @param {Object} values
40144 * @return {BasicForm} this
40146 applyIfToFields : function(o){
40147 this.items.each(function(f){
40155 Roo.BasicForm = Roo.form.BasicForm;/*
40157 * Ext JS Library 1.1.1
40158 * Copyright(c) 2006-2007, Ext JS, LLC.
40160 * Originally Released Under LGPL - original licence link has changed is not relivant.
40163 * <script type="text/javascript">
40167 * @class Roo.form.Form
40168 * @extends Roo.form.BasicForm
40169 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
40171 * @param {Object} config Configuration options
40173 Roo.form.Form = function(config){
40175 if (config.items) {
40176 xitems = config.items;
40177 delete config.items;
40181 Roo.form.Form.superclass.constructor.call(this, null, config);
40182 this.url = this.url || this.action;
40184 this.root = new Roo.form.Layout(Roo.applyIf({
40188 this.active = this.root;
40190 * Array of all the buttons that have been added to this form via {@link addButton}
40194 this.allItems = [];
40197 * @event clientvalidation
40198 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40199 * @param {Form} this
40200 * @param {Boolean} valid true if the form has passed client-side validation
40202 clientvalidation: true,
40205 * Fires when the form is rendered
40206 * @param {Roo.form.Form} form
40211 Roo.each(xitems, this.addxtype, this);
40217 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40219 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40222 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40225 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40227 buttonAlign:'center',
40230 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40235 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40236 * This property cascades to child containers if not set.
40241 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40242 * fires a looping event with that state. This is required to bind buttons to the valid
40243 * state using the config value formBind:true on the button.
40245 monitorValid : false,
40248 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40254 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40255 * fields are added and the column is closed. If no fields are passed the column remains open
40256 * until end() is called.
40257 * @param {Object} config The config to pass to the column
40258 * @param {Field} field1 (optional)
40259 * @param {Field} field2 (optional)
40260 * @param {Field} etc (optional)
40261 * @return Column The column container object
40263 column : function(c){
40264 var col = new Roo.form.Column(c);
40266 if(arguments.length > 1){ // duplicate code required because of Opera
40267 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40274 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40275 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40276 * until end() is called.
40277 * @param {Object} config The config to pass to the fieldset
40278 * @param {Field} field1 (optional)
40279 * @param {Field} field2 (optional)
40280 * @param {Field} etc (optional)
40281 * @return FieldSet The fieldset container object
40283 fieldset : function(c){
40284 var fs = new Roo.form.FieldSet(c);
40286 if(arguments.length > 1){ // duplicate code required because of Opera
40287 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40294 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
40295 * fields are added and the container is closed. If no fields are passed the container remains open
40296 * until end() is called.
40297 * @param {Object} config The config to pass to the Layout
40298 * @param {Field} field1 (optional)
40299 * @param {Field} field2 (optional)
40300 * @param {Field} etc (optional)
40301 * @return Layout The container object
40303 container : function(c){
40304 var l = new Roo.form.Layout(c);
40306 if(arguments.length > 1){ // duplicate code required because of Opera
40307 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40314 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
40315 * @param {Object} container A Roo.form.Layout or subclass of Layout
40316 * @return {Form} this
40318 start : function(c){
40319 // cascade label info
40320 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
40321 this.active.stack.push(c);
40322 c.ownerCt = this.active;
40328 * Closes the current open container
40329 * @return {Form} this
40332 if(this.active == this.root){
40335 this.active = this.active.ownerCt;
40340 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
40341 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
40342 * as the label of the field.
40343 * @param {Field} field1
40344 * @param {Field} field2 (optional)
40345 * @param {Field} etc. (optional)
40346 * @return {Form} this
40349 this.active.stack.push.apply(this.active.stack, arguments);
40350 this.allItems.push.apply(this.allItems,arguments);
40352 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
40353 if(a[i].isFormField){
40358 Roo.form.Form.superclass.add.apply(this, r);
40368 * Find any element that has been added to a form, using it's ID or name
40369 * This can include framesets, columns etc. along with regular fields..
40370 * @param {String} id - id or name to find.
40372 * @return {Element} e - or false if nothing found.
40374 findbyId : function(id)
40380 Ext.each(this.allItems, function(f){
40381 if (f.id == id || f.name == id ){
40392 * Render this form into the passed container. This should only be called once!
40393 * @param {String/HTMLElement/Element} container The element this component should be rendered into
40394 * @return {Form} this
40396 render : function(ct){
40398 var o = this.autoCreate || {
40400 method : this.method || 'POST',
40401 id : this.id || Roo.id()
40403 this.initEl(ct.createChild(o));
40405 this.root.render(this.el);
40407 this.items.each(function(f){
40408 f.render('x-form-el-'+f.id);
40411 if(this.buttons.length > 0){
40412 // tables are required to maintain order and for correct IE layout
40413 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
40414 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
40415 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
40417 var tr = tb.getElementsByTagName('tr')[0];
40418 for(var i = 0, len = this.buttons.length; i < len; i++) {
40419 var b = this.buttons[i];
40420 var td = document.createElement('td');
40421 td.className = 'x-form-btn-td';
40422 b.render(tr.appendChild(td));
40425 if(this.monitorValid){ // initialize after render
40426 this.startMonitoring();
40428 this.fireEvent('rendered', this);
40433 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
40434 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
40435 * object or a valid Roo.DomHelper element config
40436 * @param {Function} handler The function called when the button is clicked
40437 * @param {Object} scope (optional) The scope of the handler function
40438 * @return {Roo.Button}
40440 addButton : function(config, handler, scope){
40444 minWidth: this.minButtonWidth,
40447 if(typeof config == "string"){
40450 Roo.apply(bc, config);
40452 var btn = new Roo.Button(null, bc);
40453 this.buttons.push(btn);
40458 * Adds a series of form elements (using the xtype property as the factory method.
40459 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
40460 * @param {Object} config
40463 addxtype : function()
40465 var ar = Array.prototype.slice.call(arguments, 0);
40467 for(var i = 0; i < ar.length; i++) {
40469 continue; // skip -- if this happends something invalid got sent, we
40470 // should ignore it, as basically that interface element will not show up
40471 // and that should be pretty obvious!!
40474 if (Roo.form[ar[i].xtype]) {
40476 var fe = Roo.factory(ar[i], Roo.form);
40482 fe.store.form = this;
40487 this.allItems.push(fe);
40488 if (fe.items && fe.addxtype) {
40489 fe.addxtype.apply(fe, fe.items);
40499 // console.log('adding ' + ar[i].xtype);
40501 if (ar[i].xtype == 'Button') {
40502 //console.log('adding button');
40503 //console.log(ar[i]);
40504 this.addButton(ar[i]);
40505 this.allItems.push(fe);
40509 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
40510 alert('end is not supported on xtype any more, use items');
40512 // //console.log('adding end');
40520 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
40521 * option "monitorValid"
40523 startMonitoring : function(){
40526 Roo.TaskMgr.start({
40527 run : this.bindHandler,
40528 interval : this.monitorPoll || 200,
40535 * Stops monitoring of the valid state of this form
40537 stopMonitoring : function(){
40538 this.bound = false;
40542 bindHandler : function(){
40544 return false; // stops binding
40547 this.items.each(function(f){
40548 if(!f.isValid(true)){
40553 for(var i = 0, len = this.buttons.length; i < len; i++){
40554 var btn = this.buttons[i];
40555 if(btn.formBind === true && btn.disabled === valid){
40556 btn.setDisabled(!valid);
40559 this.fireEvent('clientvalidation', this, valid);
40573 Roo.Form = Roo.form.Form;
40576 * Ext JS Library 1.1.1
40577 * Copyright(c) 2006-2007, Ext JS, LLC.
40579 * Originally Released Under LGPL - original licence link has changed is not relivant.
40582 * <script type="text/javascript">
40586 * @class Roo.form.Action
40587 * Internal Class used to handle form actions
40589 * @param {Roo.form.BasicForm} el The form element or its id
40590 * @param {Object} config Configuration options
40594 // define the action interface
40595 Roo.form.Action = function(form, options){
40597 this.options = options || {};
40600 * Client Validation Failed
40603 Roo.form.Action.CLIENT_INVALID = 'client';
40605 * Server Validation Failed
40608 Roo.form.Action.SERVER_INVALID = 'server';
40610 * Connect to Server Failed
40613 Roo.form.Action.CONNECT_FAILURE = 'connect';
40615 * Reading Data from Server Failed
40618 Roo.form.Action.LOAD_FAILURE = 'load';
40620 Roo.form.Action.prototype = {
40622 failureType : undefined,
40623 response : undefined,
40624 result : undefined,
40626 // interface method
40627 run : function(options){
40631 // interface method
40632 success : function(response){
40636 // interface method
40637 handleResponse : function(response){
40641 // default connection failure
40642 failure : function(response){
40643 this.response = response;
40644 this.failureType = Roo.form.Action.CONNECT_FAILURE;
40645 this.form.afterAction(this, false);
40648 processResponse : function(response){
40649 this.response = response;
40650 if(!response.responseText){
40653 this.result = this.handleResponse(response);
40654 return this.result;
40657 // utility functions used internally
40658 getUrl : function(appendParams){
40659 var url = this.options.url || this.form.url || this.form.el.dom.action;
40661 var p = this.getParams();
40663 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
40669 getMethod : function(){
40670 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
40673 getParams : function(){
40674 var bp = this.form.baseParams;
40675 var p = this.options.params;
40677 if(typeof p == "object"){
40678 p = Roo.urlEncode(Roo.applyIf(p, bp));
40679 }else if(typeof p == 'string' && bp){
40680 p += '&' + Roo.urlEncode(bp);
40683 p = Roo.urlEncode(bp);
40688 createCallback : function(){
40690 success: this.success,
40691 failure: this.failure,
40693 timeout: (this.form.timeout*1000),
40694 upload: this.form.fileUpload ? this.success : undefined
40699 Roo.form.Action.Submit = function(form, options){
40700 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
40703 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
40707 var o = this.options;
40708 var method = this.getMethod();
40709 var isPost = method == 'POST';
40710 if(o.clientValidation === false || this.form.isValid()){
40711 Roo.Ajax.request(Roo.apply(this.createCallback(), {
40712 form:this.form.el.dom,
40713 url:this.getUrl(!isPost),
40715 params:isPost ? this.getParams() : null,
40716 isUpload: this.form.fileUpload
40719 }else if (o.clientValidation !== false){ // client validation failed
40720 this.failureType = Roo.form.Action.CLIENT_INVALID;
40721 this.form.afterAction(this, false);
40725 success : function(response){
40726 var result = this.processResponse(response);
40727 if(result === true || result.success){
40728 this.form.afterAction(this, true);
40732 this.form.markInvalid(result.errors);
40733 this.failureType = Roo.form.Action.SERVER_INVALID;
40735 this.form.afterAction(this, false);
40738 handleResponse : function(response){
40739 if(this.form.errorReader){
40740 var rs = this.form.errorReader.read(response);
40743 for(var i = 0, len = rs.records.length; i < len; i++) {
40744 var r = rs.records[i];
40745 errors[i] = r.data;
40748 if(errors.length < 1){
40752 success : rs.success,
40758 ret = Roo.decode(response.responseText);
40762 errorMsg: "Failed to read server message: " + response.responseText,
40772 Roo.form.Action.Load = function(form, options){
40773 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
40774 this.reader = this.form.reader;
40777 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
40781 Roo.Ajax.request(Roo.apply(
40782 this.createCallback(), {
40783 method:this.getMethod(),
40784 url:this.getUrl(false),
40785 params:this.getParams()
40789 success : function(response){
40790 var result = this.processResponse(response);
40791 if(result === true || !result.success || !result.data){
40792 this.failureType = Roo.form.Action.LOAD_FAILURE;
40793 this.form.afterAction(this, false);
40796 this.form.clearInvalid();
40797 this.form.setValues(result.data);
40798 this.form.afterAction(this, true);
40801 handleResponse : function(response){
40802 if(this.form.reader){
40803 var rs = this.form.reader.read(response);
40804 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
40806 success : rs.success,
40810 return Roo.decode(response.responseText);
40814 Roo.form.Action.ACTION_TYPES = {
40815 'load' : Roo.form.Action.Load,
40816 'submit' : Roo.form.Action.Submit
40819 * Ext JS Library 1.1.1
40820 * Copyright(c) 2006-2007, Ext JS, LLC.
40822 * Originally Released Under LGPL - original licence link has changed is not relivant.
40825 * <script type="text/javascript">
40829 * @class Roo.form.Layout
40830 * @extends Roo.Component
40831 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
40833 * @param {Object} config Configuration options
40835 Roo.form.Layout = function(config){
40837 if (config.items) {
40838 xitems = config.items;
40839 delete config.items;
40841 Roo.form.Layout.superclass.constructor.call(this, config);
40843 Roo.each(xitems, this.addxtype, this);
40847 Roo.extend(Roo.form.Layout, Roo.Component, {
40849 * @cfg {String/Object} autoCreate
40850 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
40853 * @cfg {String/Object/Function} style
40854 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
40855 * a function which returns such a specification.
40858 * @cfg {String} labelAlign
40859 * Valid values are "left," "top" and "right" (defaults to "left")
40862 * @cfg {Number} labelWidth
40863 * Fixed width in pixels of all field labels (defaults to undefined)
40866 * @cfg {Boolean} clear
40867 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
40871 * @cfg {String} labelSeparator
40872 * The separator to use after field labels (defaults to ':')
40874 labelSeparator : ':',
40876 * @cfg {Boolean} hideLabels
40877 * True to suppress the display of field labels in this layout (defaults to false)
40879 hideLabels : false,
40882 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
40887 onRender : function(ct, position){
40888 if(this.el){ // from markup
40889 this.el = Roo.get(this.el);
40890 }else { // generate
40891 var cfg = this.getAutoCreate();
40892 this.el = ct.createChild(cfg, position);
40895 this.el.applyStyles(this.style);
40897 if(this.labelAlign){
40898 this.el.addClass('x-form-label-'+this.labelAlign);
40900 if(this.hideLabels){
40901 this.labelStyle = "display:none";
40902 this.elementStyle = "padding-left:0;";
40904 if(typeof this.labelWidth == 'number'){
40905 this.labelStyle = "width:"+this.labelWidth+"px;";
40906 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
40908 if(this.labelAlign == 'top'){
40909 this.labelStyle = "width:auto;";
40910 this.elementStyle = "padding-left:0;";
40913 var stack = this.stack;
40914 var slen = stack.length;
40916 if(!this.fieldTpl){
40917 var t = new Roo.Template(
40918 '<div class="x-form-item {5}">',
40919 '<label for="{0}" style="{2}">{1}{4}</label>',
40920 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
40922 '</div><div class="x-form-clear-left"></div>'
40924 t.disableFormats = true;
40926 Roo.form.Layout.prototype.fieldTpl = t;
40928 for(var i = 0; i < slen; i++) {
40929 if(stack[i].isFormField){
40930 this.renderField(stack[i]);
40932 this.renderComponent(stack[i]);
40937 this.el.createChild({cls:'x-form-clear'});
40942 renderField : function(f){
40943 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
40946 f.labelStyle||this.labelStyle||'', //2
40947 this.elementStyle||'', //3
40948 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
40949 f.itemCls||this.itemCls||'' //5
40950 ], true).getPrevSibling());
40954 renderComponent : function(c){
40955 c.render(c.isLayout ? this.el : this.el.createChild());
40958 * Adds a object form elements (using the xtype property as the factory method.)
40959 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
40960 * @param {Object} config
40962 addxtype : function(o)
40964 // create the lement.
40965 o.form = this.form;
40966 var fe = Roo.factory(o, Roo.form);
40967 this.form.allItems.push(fe);
40968 this.stack.push(fe);
40970 if (fe.isFormField) {
40971 this.form.items.add(fe);
40979 * @class Roo.form.Column
40980 * @extends Roo.form.Layout
40981 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
40983 * @param {Object} config Configuration options
40985 Roo.form.Column = function(config){
40986 Roo.form.Column.superclass.constructor.call(this, config);
40989 Roo.extend(Roo.form.Column, Roo.form.Layout, {
40991 * @cfg {Number/String} width
40992 * The fixed width of the column in pixels or CSS value (defaults to "auto")
40995 * @cfg {String/Object} autoCreate
40996 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
41000 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
41003 onRender : function(ct, position){
41004 Roo.form.Column.superclass.onRender.call(this, ct, position);
41006 this.el.setWidth(this.width);
41013 * @class Roo.form.Row
41014 * @extends Roo.form.Layout
41015 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
41017 * @param {Object} config Configuration options
41021 Roo.form.Row = function(config){
41022 Roo.form.Row.superclass.constructor.call(this, config);
41025 Roo.extend(Roo.form.Row, Roo.form.Layout, {
41027 * @cfg {Number/String} width
41028 * The fixed width of the column in pixels or CSS value (defaults to "auto")
41031 * @cfg {Number/String} height
41032 * The fixed height of the column in pixels or CSS value (defaults to "auto")
41034 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
41038 onRender : function(ct, position){
41039 //console.log('row render');
41041 var t = new Roo.Template(
41042 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
41043 '<label for="{0}" style="{2}">{1}{4}</label>',
41044 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
41048 t.disableFormats = true;
41050 Roo.form.Layout.prototype.rowTpl = t;
41052 this.fieldTpl = this.rowTpl;
41054 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
41055 var labelWidth = 100;
41057 if ((this.labelAlign != 'top')) {
41058 if (typeof this.labelWidth == 'number') {
41059 labelWidth = this.labelWidth
41061 this.padWidth = 20 + labelWidth;
41065 Roo.form.Column.superclass.onRender.call(this, ct, position);
41067 this.el.setWidth(this.width);
41070 this.el.setHeight(this.height);
41075 renderField : function(f){
41076 f.fieldEl = this.fieldTpl.append(this.el, [
41077 f.id, f.fieldLabel,
41078 f.labelStyle||this.labelStyle||'',
41079 this.elementStyle||'',
41080 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
41081 f.itemCls||this.itemCls||'',
41082 f.width ? f.width + this.padWidth : 160 + this.padWidth
41089 * @class Roo.form.FieldSet
41090 * @extends Roo.form.Layout
41091 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
41093 * @param {Object} config Configuration options
41095 Roo.form.FieldSet = function(config){
41096 Roo.form.FieldSet.superclass.constructor.call(this, config);
41099 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
41101 * @cfg {String} legend
41102 * The text to display as the legend for the FieldSet (defaults to '')
41105 * @cfg {String/Object} autoCreate
41106 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
41110 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
41113 onRender : function(ct, position){
41114 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
41116 this.setLegend(this.legend);
41121 setLegend : function(text){
41123 this.el.child('legend').update(text);
41128 * Ext JS Library 1.1.1
41129 * Copyright(c) 2006-2007, Ext JS, LLC.
41131 * Originally Released Under LGPL - original licence link has changed is not relivant.
41134 * <script type="text/javascript">
41137 * @class Roo.form.VTypes
41138 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
41141 Roo.form.VTypes = function(){
41142 // closure these in so they are only created once.
41143 var alpha = /^[a-zA-Z_]+$/;
41144 var alphanum = /^[a-zA-Z0-9_]+$/;
41145 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
41146 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
41148 // All these messages and functions are configurable
41151 * The function used to validate email addresses
41152 * @param {String} value The email address
41154 'email' : function(v){
41155 return email.test(v);
41158 * The error text to display when the email validation function returns false
41161 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
41163 * The keystroke filter mask to be applied on email input
41166 'emailMask' : /[a-z0-9_\.\-@]/i,
41169 * The function used to validate URLs
41170 * @param {String} value The URL
41172 'url' : function(v){
41173 return url.test(v);
41176 * The error text to display when the url validation function returns false
41179 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
41182 * The function used to validate alpha values
41183 * @param {String} value The value
41185 'alpha' : function(v){
41186 return alpha.test(v);
41189 * The error text to display when the alpha validation function returns false
41192 'alphaText' : 'This field should only contain letters and _',
41194 * The keystroke filter mask to be applied on alpha input
41197 'alphaMask' : /[a-z_]/i,
41200 * The function used to validate alphanumeric values
41201 * @param {String} value The value
41203 'alphanum' : function(v){
41204 return alphanum.test(v);
41207 * The error text to display when the alphanumeric validation function returns false
41210 'alphanumText' : 'This field should only contain letters, numbers and _',
41212 * The keystroke filter mask to be applied on alphanumeric input
41215 'alphanumMask' : /[a-z0-9_]/i
41217 }();//<script type="text/javascript">
41220 * @class Roo.form.FCKeditor
41221 * @extends Roo.form.TextArea
41222 * Wrapper around the FCKEditor http://www.fckeditor.net
41224 * Creates a new FCKeditor
41225 * @param {Object} config Configuration options
41227 Roo.form.FCKeditor = function(config){
41228 Roo.form.FCKeditor.superclass.constructor.call(this, config);
41231 * @event editorinit
41232 * Fired when the editor is initialized - you can add extra handlers here..
41233 * @param {FCKeditor} this
41234 * @param {Object} the FCK object.
41241 Roo.form.FCKeditor.editors = { };
41242 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
41244 //defaultAutoCreate : {
41245 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
41249 * @cfg {Object} fck options - see fck manual for details.
41254 * @cfg {Object} fck toolbar set (Basic or Default)
41256 toolbarSet : 'Basic',
41258 * @cfg {Object} fck BasePath
41260 basePath : '/fckeditor/',
41268 onRender : function(ct, position)
41271 this.defaultAutoCreate = {
41273 style:"width:300px;height:60px;",
41274 autocomplete: "off"
41277 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
41280 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
41281 if(this.preventScrollbars){
41282 this.el.setStyle("overflow", "hidden");
41284 this.el.setHeight(this.growMin);
41287 //console.log('onrender' + this.getId() );
41288 Roo.form.FCKeditor.editors[this.getId()] = this;
41291 this.replaceTextarea() ;
41295 getEditor : function() {
41296 return this.fckEditor;
41299 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
41300 * @param {Mixed} value The value to set
41304 setValue : function(value)
41306 //console.log('setValue: ' + value);
41308 if(typeof(value) == 'undefined') { // not sure why this is happending...
41311 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41313 //if(!this.el || !this.getEditor()) {
41314 // this.value = value;
41315 //this.setValue.defer(100,this,[value]);
41319 if(!this.getEditor()) {
41323 this.getEditor().SetData(value);
41330 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
41331 * @return {Mixed} value The field value
41333 getValue : function()
41336 if (this.frame && this.frame.dom.style.display == 'none') {
41337 return Roo.form.FCKeditor.superclass.getValue.call(this);
41340 if(!this.el || !this.getEditor()) {
41342 // this.getValue.defer(100,this);
41347 var value=this.getEditor().GetData();
41348 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41349 return Roo.form.FCKeditor.superclass.getValue.call(this);
41355 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
41356 * @return {Mixed} value The field value
41358 getRawValue : function()
41360 if (this.frame && this.frame.dom.style.display == 'none') {
41361 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41364 if(!this.el || !this.getEditor()) {
41365 //this.getRawValue.defer(100,this);
41372 var value=this.getEditor().GetData();
41373 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
41374 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41378 setSize : function(w,h) {
41382 //if (this.frame && this.frame.dom.style.display == 'none') {
41383 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41386 //if(!this.el || !this.getEditor()) {
41387 // this.setSize.defer(100,this, [w,h]);
41393 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41395 this.frame.dom.setAttribute('width', w);
41396 this.frame.dom.setAttribute('height', h);
41397 this.frame.setSize(w,h);
41401 toggleSourceEdit : function(value) {
41405 this.el.dom.style.display = value ? '' : 'none';
41406 this.frame.dom.style.display = value ? 'none' : '';
41411 focus: function(tag)
41413 if (this.frame.dom.style.display == 'none') {
41414 return Roo.form.FCKeditor.superclass.focus.call(this);
41416 if(!this.el || !this.getEditor()) {
41417 this.focus.defer(100,this, [tag]);
41424 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
41425 this.getEditor().Focus();
41427 if (!this.getEditor().Selection.GetSelection()) {
41428 this.focus.defer(100,this, [tag]);
41433 var r = this.getEditor().EditorDocument.createRange();
41434 r.setStart(tgs[0],0);
41435 r.setEnd(tgs[0],0);
41436 this.getEditor().Selection.GetSelection().removeAllRanges();
41437 this.getEditor().Selection.GetSelection().addRange(r);
41438 this.getEditor().Focus();
41445 replaceTextarea : function()
41447 if ( document.getElementById( this.getId() + '___Frame' ) )
41449 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
41451 // We must check the elements firstly using the Id and then the name.
41452 var oTextarea = document.getElementById( this.getId() );
41454 var colElementsByName = document.getElementsByName( this.getId() ) ;
41456 oTextarea.style.display = 'none' ;
41458 if ( oTextarea.tabIndex ) {
41459 this.TabIndex = oTextarea.tabIndex ;
41462 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
41463 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
41464 this.frame = Roo.get(this.getId() + '___Frame')
41467 _getConfigHtml : function()
41471 for ( var o in this.fckconfig ) {
41472 sConfig += sConfig.length > 0 ? '&' : '';
41473 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
41476 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
41480 _getIFrameHtml : function()
41482 var sFile = 'fckeditor.html' ;
41483 /* no idea what this is about..
41486 if ( (/fcksource=true/i).test( window.top.location.search ) )
41487 sFile = 'fckeditor.original.html' ;
41492 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
41493 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
41496 var html = '<iframe id="' + this.getId() +
41497 '___Frame" src="' + sLink +
41498 '" width="' + this.width +
41499 '" height="' + this.height + '"' +
41500 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
41501 ' frameborder="0" scrolling="no"></iframe>' ;
41506 _insertHtmlBefore : function( html, element )
41508 if ( element.insertAdjacentHTML ) {
41510 element.insertAdjacentHTML( 'beforeBegin', html ) ;
41512 var oRange = document.createRange() ;
41513 oRange.setStartBefore( element ) ;
41514 var oFragment = oRange.createContextualFragment( html );
41515 element.parentNode.insertBefore( oFragment, element ) ;
41528 //Roo.reg('fckeditor', Roo.form.FCKeditor);
41530 function FCKeditor_OnComplete(editorInstance){
41531 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
41532 f.fckEditor = editorInstance;
41533 //console.log("loaded");
41534 f.fireEvent('editorinit', f, editorInstance);
41554 //<script type="text/javascript">
41556 * @class Roo.form.GridField
41557 * @extends Roo.form.Field
41558 * Embed a grid (or editable grid into a form)
41561 * Creates a new GridField
41562 * @param {Object} config Configuration options
41564 Roo.form.GridField = function(config){
41565 Roo.form.GridField.superclass.constructor.call(this, config);
41569 Roo.extend(Roo.form.GridField, Roo.form.Field, {
41571 * @cfg {Number} width - used to restrict width of grid..
41575 * @cfg {Number} height - used to restrict height of grid..
41579 * @cfg {Object} xgrid (xtype'd description of grid) Grid or EditorGrid
41583 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41584 * {tag: "input", type: "checkbox", autocomplete: "off"})
41586 // defaultAutoCreate : { tag: 'div' },
41587 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
41589 * @cfg {String} addTitle Text to include for adding a title.
41593 onResize : function(){
41594 Roo.form.Field.superclass.onResize.apply(this, arguments);
41597 initEvents : function(){
41598 // Roo.form.Checkbox.superclass.initEvents.call(this);
41599 // has no events...
41604 getResizeEl : function(){
41608 getPositionEl : function(){
41613 onRender : function(ct, position){
41615 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
41616 var style = this.style;
41619 Roo.form.DisplayImage.superclass.onRender.call(this, ct, position);
41620 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
41621 this.viewEl = this.wrap.createChild({ tag: 'div' });
41623 this.viewEl.applyStyles(style);
41626 this.viewEl.setWidth(this.width);
41629 this.viewEl.setHeight(this.height);
41631 //if(this.inputValue !== undefined){
41632 //this.setValue(this.value);
41635 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
41638 this.grid.render();
41639 this.grid.getDataSource().on('remove', this.refreshValue, this);
41640 this.grid.getDataSource().on('update', this.refreshValue, this);
41641 this.grid.on('afteredit', this.refreshValue, this);
41647 * Sets the value of the item.
41648 * @param {String} either an object or a string..
41650 setValue : function(v){
41652 v = v || []; // empty set..
41653 // this does not seem smart - it really only affects memoryproxy grids..
41654 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
41655 var ds = this.grid.getDataSource();
41656 // assumes a json reader..
41658 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
41659 ds.loadData( data);
41661 Roo.form.GridField.superclass.setValue.call(this, v);
41662 this.refreshValue();
41663 // should load data in the grid really....
41667 refreshValue: function() {
41669 this.grid.getDataSource().each(function(r) {
41672 this.el.dom.value = Roo.encode(val);
41678 });//<script type="text/javasscript">
41682 * @class Roo.DDView
41683 * A DnD enabled version of Roo.View.
41684 * @param {Element/String} container The Element in which to create the View.
41685 * @param {String} tpl The template string used to create the markup for each element of the View
41686 * @param {Object} config The configuration properties. These include all the config options of
41687 * {@link Roo.View} plus some specific to this class.<br>
41689 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
41690 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
41692 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
41693 .x-view-drag-insert-above {
41694 border-top:1px dotted #3366cc;
41696 .x-view-drag-insert-below {
41697 border-bottom:1px dotted #3366cc;
41703 Roo.DDView = function(container, tpl, config) {
41704 Roo.DDView.superclass.constructor.apply(this, arguments);
41705 this.getEl().setStyle("outline", "0px none");
41706 this.getEl().unselectable();
41707 if (this.dragGroup) {
41708 this.setDraggable(this.dragGroup.split(","));
41710 if (this.dropGroup) {
41711 this.setDroppable(this.dropGroup.split(","));
41713 if (this.deletable) {
41714 this.setDeletable();
41716 this.isDirtyFlag = false;
41722 Roo.extend(Roo.DDView, Roo.View, {
41723 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
41724 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
41725 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
41726 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
41730 reset: Roo.emptyFn,
41732 clearInvalid: Roo.form.Field.prototype.clearInvalid,
41734 validate: function() {
41738 destroy: function() {
41739 this.purgeListeners();
41740 this.getEl.removeAllListeners();
41741 this.getEl().remove();
41742 if (this.dragZone) {
41743 if (this.dragZone.destroy) {
41744 this.dragZone.destroy();
41747 if (this.dropZone) {
41748 if (this.dropZone.destroy) {
41749 this.dropZone.destroy();
41754 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
41755 getName: function() {
41759 /** Loads the View from a JSON string representing the Records to put into the Store. */
41760 setValue: function(v) {
41762 throw "DDView.setValue(). DDView must be constructed with a valid Store";
41765 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
41766 this.store.proxy = new Roo.data.MemoryProxy(data);
41770 /** @return {String} a parenthesised list of the ids of the Records in the View. */
41771 getValue: function() {
41773 this.store.each(function(rec) {
41774 result += rec.id + ',';
41776 return result.substr(0, result.length - 1) + ')';
41779 getIds: function() {
41780 var i = 0, result = new Array(this.store.getCount());
41781 this.store.each(function(rec) {
41782 result[i++] = rec.id;
41787 isDirty: function() {
41788 return this.isDirtyFlag;
41792 * Part of the Roo.dd.DropZone interface. If no target node is found, the
41793 * whole Element becomes the target, and this causes the drop gesture to append.
41795 getTargetFromEvent : function(e) {
41796 var target = e.getTarget();
41797 while ((target !== null) && (target.parentNode != this.el.dom)) {
41798 target = target.parentNode;
41801 target = this.el.dom.lastChild || this.el.dom;
41807 * Create the drag data which consists of an object which has the property "ddel" as
41808 * the drag proxy element.
41810 getDragData : function(e) {
41811 var target = this.findItemFromChild(e.getTarget());
41813 this.handleSelection(e);
41814 var selNodes = this.getSelectedNodes();
41817 copy: this.copy || (this.allowCopy && e.ctrlKey),
41821 var selectedIndices = this.getSelectedIndexes();
41822 for (var i = 0; i < selectedIndices.length; i++) {
41823 dragData.records.push(this.store.getAt(selectedIndices[i]));
41825 if (selNodes.length == 1) {
41826 dragData.ddel = target.cloneNode(true); // the div element
41828 var div = document.createElement('div'); // create the multi element drag "ghost"
41829 div.className = 'multi-proxy';
41830 for (var i = 0, len = selNodes.length; i < len; i++) {
41831 div.appendChild(selNodes[i].cloneNode(true));
41833 dragData.ddel = div;
41835 //console.log(dragData)
41836 //console.log(dragData.ddel.innerHTML)
41839 //console.log('nodragData')
41843 /** Specify to which ddGroup items in this DDView may be dragged. */
41844 setDraggable: function(ddGroup) {
41845 if (ddGroup instanceof Array) {
41846 Roo.each(ddGroup, this.setDraggable, this);
41849 if (this.dragZone) {
41850 this.dragZone.addToGroup(ddGroup);
41852 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
41853 containerScroll: true,
41857 // Draggability implies selection. DragZone's mousedown selects the element.
41858 if (!this.multiSelect) { this.singleSelect = true; }
41860 // Wire the DragZone's handlers up to methods in *this*
41861 this.dragZone.getDragData = this.getDragData.createDelegate(this);
41865 /** Specify from which ddGroup this DDView accepts drops. */
41866 setDroppable: function(ddGroup) {
41867 if (ddGroup instanceof Array) {
41868 Roo.each(ddGroup, this.setDroppable, this);
41871 if (this.dropZone) {
41872 this.dropZone.addToGroup(ddGroup);
41874 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
41875 containerScroll: true,
41879 // Wire the DropZone's handlers up to methods in *this*
41880 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
41881 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
41882 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
41883 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
41884 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
41888 /** Decide whether to drop above or below a View node. */
41889 getDropPoint : function(e, n, dd){
41890 if (n == this.el.dom) { return "above"; }
41891 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
41892 var c = t + (b - t) / 2;
41893 var y = Roo.lib.Event.getPageY(e);
41901 onNodeEnter : function(n, dd, e, data){
41905 onNodeOver : function(n, dd, e, data){
41906 var pt = this.getDropPoint(e, n, dd);
41907 // set the insert point style on the target node
41908 var dragElClass = this.dropNotAllowed;
41911 if (pt == "above"){
41912 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
41913 targetElClass = "x-view-drag-insert-above";
41915 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
41916 targetElClass = "x-view-drag-insert-below";
41918 if (this.lastInsertClass != targetElClass){
41919 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
41920 this.lastInsertClass = targetElClass;
41923 return dragElClass;
41926 onNodeOut : function(n, dd, e, data){
41927 this.removeDropIndicators(n);
41930 onNodeDrop : function(n, dd, e, data){
41931 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
41934 var pt = this.getDropPoint(e, n, dd);
41935 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
41936 if (pt == "below") { insertAt++; }
41937 for (var i = 0; i < data.records.length; i++) {
41938 var r = data.records[i];
41939 var dup = this.store.getById(r.id);
41940 if (dup && (dd != this.dragZone)) {
41941 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
41944 this.store.insert(insertAt++, r.copy());
41946 data.source.isDirtyFlag = true;
41948 this.store.insert(insertAt++, r);
41950 this.isDirtyFlag = true;
41953 this.dragZone.cachedTarget = null;
41957 removeDropIndicators : function(n){
41959 Roo.fly(n).removeClass([
41960 "x-view-drag-insert-above",
41961 "x-view-drag-insert-below"]);
41962 this.lastInsertClass = "_noclass";
41967 * Utility method. Add a delete option to the DDView's context menu.
41968 * @param {String} imageUrl The URL of the "delete" icon image.
41970 setDeletable: function(imageUrl) {
41971 if (!this.singleSelect && !this.multiSelect) {
41972 this.singleSelect = true;
41974 var c = this.getContextMenu();
41975 this.contextMenu.on("itemclick", function(item) {
41978 this.remove(this.getSelectedIndexes());
41982 this.contextMenu.add({
41989 /** Return the context menu for this DDView. */
41990 getContextMenu: function() {
41991 if (!this.contextMenu) {
41992 // Create the View's context menu
41993 this.contextMenu = new Roo.menu.Menu({
41994 id: this.id + "-contextmenu"
41996 this.el.on("contextmenu", this.showContextMenu, this);
41998 return this.contextMenu;
42001 disableContextMenu: function() {
42002 if (this.contextMenu) {
42003 this.el.un("contextmenu", this.showContextMenu, this);
42007 showContextMenu: function(e, item) {
42008 item = this.findItemFromChild(e.getTarget());
42011 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
42012 this.contextMenu.showAt(e.getXY());
42017 * Remove {@link Roo.data.Record}s at the specified indices.
42018 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
42020 remove: function(selectedIndices) {
42021 selectedIndices = [].concat(selectedIndices);
42022 for (var i = 0; i < selectedIndices.length; i++) {
42023 var rec = this.store.getAt(selectedIndices[i]);
42024 this.store.remove(rec);
42029 * Double click fires the event, but also, if this is draggable, and there is only one other
42030 * related DropZone, it transfers the selected node.
42032 onDblClick : function(e){
42033 var item = this.findItemFromChild(e.getTarget());
42035 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
42038 if (this.dragGroup) {
42039 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
42040 while (targets.indexOf(this.dropZone) > -1) {
42041 targets.remove(this.dropZone);
42043 if (targets.length == 1) {
42044 this.dragZone.cachedTarget = null;
42045 var el = Roo.get(targets[0].getEl());
42046 var box = el.getBox(true);
42047 targets[0].onNodeDrop(el.dom, {
42049 xy: [box.x, box.y + box.height - 1]
42050 }, null, this.getDragData(e));
42056 handleSelection: function(e) {
42057 this.dragZone.cachedTarget = null;
42058 var item = this.findItemFromChild(e.getTarget());
42060 this.clearSelections(true);
42063 if (item && (this.multiSelect || this.singleSelect)){
42064 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
42065 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
42066 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
42067 this.unselect(item);
42069 this.select(item, this.multiSelect && e.ctrlKey);
42070 this.lastSelection = item;
42075 onItemClick : function(item, index, e){
42076 if(this.fireEvent("beforeclick", this, index, item, e) === false){
42082 unselect : function(nodeInfo, suppressEvent){
42083 var node = this.getNode(nodeInfo);
42084 if(node && this.isSelected(node)){
42085 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
42086 Roo.fly(node).removeClass(this.selectedClass);
42087 this.selections.remove(node);
42088 if(!suppressEvent){
42089 this.fireEvent("selectionchange", this, this.selections);
42097 * Ext JS Library 1.1.1
42098 * Copyright(c) 2006-2007, Ext JS, LLC.
42100 * Originally Released Under LGPL - original licence link has changed is not relivant.
42103 * <script type="text/javascript">
42107 * @class Roo.LayoutManager
42108 * @extends Roo.util.Observable
42109 * Base class for layout managers.
42111 Roo.LayoutManager = function(container, config){
42112 Roo.LayoutManager.superclass.constructor.call(this);
42113 this.el = Roo.get(container);
42114 // ie scrollbar fix
42115 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
42116 document.body.scroll = "no";
42117 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
42118 this.el.position('relative');
42120 this.id = this.el.id;
42121 this.el.addClass("x-layout-container");
42122 /** false to disable window resize monitoring @type Boolean */
42123 this.monitorWindowResize = true;
42128 * Fires when a layout is performed.
42129 * @param {Roo.LayoutManager} this
42133 * @event regionresized
42134 * Fires when the user resizes a region.
42135 * @param {Roo.LayoutRegion} region The resized region
42136 * @param {Number} newSize The new size (width for east/west, height for north/south)
42138 "regionresized" : true,
42140 * @event regioncollapsed
42141 * Fires when a region is collapsed.
42142 * @param {Roo.LayoutRegion} region The collapsed region
42144 "regioncollapsed" : true,
42146 * @event regionexpanded
42147 * Fires when a region is expanded.
42148 * @param {Roo.LayoutRegion} region The expanded region
42150 "regionexpanded" : true
42152 this.updating = false;
42153 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
42156 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
42158 * Returns true if this layout is currently being updated
42159 * @return {Boolean}
42161 isUpdating : function(){
42162 return this.updating;
42166 * Suspend the LayoutManager from doing auto-layouts while
42167 * making multiple add or remove calls
42169 beginUpdate : function(){
42170 this.updating = true;
42174 * Restore auto-layouts and optionally disable the manager from performing a layout
42175 * @param {Boolean} noLayout true to disable a layout update
42177 endUpdate : function(noLayout){
42178 this.updating = false;
42184 layout: function(){
42188 onRegionResized : function(region, newSize){
42189 this.fireEvent("regionresized", region, newSize);
42193 onRegionCollapsed : function(region){
42194 this.fireEvent("regioncollapsed", region);
42197 onRegionExpanded : function(region){
42198 this.fireEvent("regionexpanded", region);
42202 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
42203 * performs box-model adjustments.
42204 * @return {Object} The size as an object {width: (the width), height: (the height)}
42206 getViewSize : function(){
42208 if(this.el.dom != document.body){
42209 size = this.el.getSize();
42211 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
42213 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
42214 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
42219 * Returns the Element this layout is bound to.
42220 * @return {Roo.Element}
42222 getEl : function(){
42227 * Returns the specified region.
42228 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
42229 * @return {Roo.LayoutRegion}
42231 getRegion : function(target){
42232 return this.regions[target.toLowerCase()];
42235 onWindowResize : function(){
42236 if(this.monitorWindowResize){
42242 * Ext JS Library 1.1.1
42243 * Copyright(c) 2006-2007, Ext JS, LLC.
42245 * Originally Released Under LGPL - original licence link has changed is not relivant.
42248 * <script type="text/javascript">
42251 * @class Roo.BorderLayout
42252 * @extends Roo.LayoutManager
42253 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
42254 * please see: <br><br>
42255 * <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>
42256 * <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>
42259 var layout = new Roo.BorderLayout(document.body, {
42293 preferredTabWidth: 150
42298 var CP = Roo.ContentPanel;
42300 layout.beginUpdate();
42301 layout.add("north", new CP("north", "North"));
42302 layout.add("south", new CP("south", {title: "South", closable: true}));
42303 layout.add("west", new CP("west", {title: "West"}));
42304 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
42305 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
42306 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
42307 layout.getRegion("center").showPanel("center1");
42308 layout.endUpdate();
42311 <b>The container the layout is rendered into can be either the body element or any other element.
42312 If it is not the body element, the container needs to either be an absolute positioned element,
42313 or you will need to add "position:relative" to the css of the container. You will also need to specify
42314 the container size if it is not the body element.</b>
42317 * Create a new BorderLayout
42318 * @param {String/HTMLElement/Element} container The container this layout is bound to
42319 * @param {Object} config Configuration options
42321 Roo.BorderLayout = function(container, config){
42322 config = config || {};
42323 Roo.BorderLayout.superclass.constructor.call(this, container, config);
42324 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
42325 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
42326 var target = this.factory.validRegions[i];
42327 if(config[target]){
42328 this.addRegion(target, config[target]);
42333 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
42335 * Creates and adds a new region if it doesn't already exist.
42336 * @param {String} target The target region key (north, south, east, west or center).
42337 * @param {Object} config The regions config object
42338 * @return {BorderLayoutRegion} The new region
42340 addRegion : function(target, config){
42341 if(!this.regions[target]){
42342 var r = this.factory.create(target, this, config);
42343 this.bindRegion(target, r);
42345 return this.regions[target];
42349 bindRegion : function(name, r){
42350 this.regions[name] = r;
42351 r.on("visibilitychange", this.layout, this);
42352 r.on("paneladded", this.layout, this);
42353 r.on("panelremoved", this.layout, this);
42354 r.on("invalidated", this.layout, this);
42355 r.on("resized", this.onRegionResized, this);
42356 r.on("collapsed", this.onRegionCollapsed, this);
42357 r.on("expanded", this.onRegionExpanded, this);
42361 * Performs a layout update.
42363 layout : function(){
42364 if(this.updating) return;
42365 var size = this.getViewSize();
42366 var w = size.width;
42367 var h = size.height;
42372 //var x = 0, y = 0;
42374 var rs = this.regions;
42375 var north = rs["north"];
42376 var south = rs["south"];
42377 var west = rs["west"];
42378 var east = rs["east"];
42379 var center = rs["center"];
42380 //if(this.hideOnLayout){ // not supported anymore
42381 //c.el.setStyle("display", "none");
42383 if(north && north.isVisible()){
42384 var b = north.getBox();
42385 var m = north.getMargins();
42386 b.width = w - (m.left+m.right);
42389 centerY = b.height + b.y + m.bottom;
42390 centerH -= centerY;
42391 north.updateBox(this.safeBox(b));
42393 if(south && south.isVisible()){
42394 var b = south.getBox();
42395 var m = south.getMargins();
42396 b.width = w - (m.left+m.right);
42398 var totalHeight = (b.height + m.top + m.bottom);
42399 b.y = h - totalHeight + m.top;
42400 centerH -= totalHeight;
42401 south.updateBox(this.safeBox(b));
42403 if(west && west.isVisible()){
42404 var b = west.getBox();
42405 var m = west.getMargins();
42406 b.height = centerH - (m.top+m.bottom);
42408 b.y = centerY + m.top;
42409 var totalWidth = (b.width + m.left + m.right);
42410 centerX += totalWidth;
42411 centerW -= totalWidth;
42412 west.updateBox(this.safeBox(b));
42414 if(east && east.isVisible()){
42415 var b = east.getBox();
42416 var m = east.getMargins();
42417 b.height = centerH - (m.top+m.bottom);
42418 var totalWidth = (b.width + m.left + m.right);
42419 b.x = w - totalWidth + m.left;
42420 b.y = centerY + m.top;
42421 centerW -= totalWidth;
42422 east.updateBox(this.safeBox(b));
42425 var m = center.getMargins();
42427 x: centerX + m.left,
42428 y: centerY + m.top,
42429 width: centerW - (m.left+m.right),
42430 height: centerH - (m.top+m.bottom)
42432 //if(this.hideOnLayout){
42433 //center.el.setStyle("display", "block");
42435 center.updateBox(this.safeBox(centerBox));
42438 this.fireEvent("layout", this);
42442 safeBox : function(box){
42443 box.width = Math.max(0, box.width);
42444 box.height = Math.max(0, box.height);
42449 * Adds a ContentPanel (or subclass) to this layout.
42450 * @param {String} target The target region key (north, south, east, west or center).
42451 * @param {Roo.ContentPanel} panel The panel to add
42452 * @return {Roo.ContentPanel} The added panel
42454 add : function(target, panel){
42456 target = target.toLowerCase();
42457 return this.regions[target].add(panel);
42461 * Remove a ContentPanel (or subclass) to this layout.
42462 * @param {String} target The target region key (north, south, east, west or center).
42463 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
42464 * @return {Roo.ContentPanel} The removed panel
42466 remove : function(target, panel){
42467 target = target.toLowerCase();
42468 return this.regions[target].remove(panel);
42472 * Searches all regions for a panel with the specified id
42473 * @param {String} panelId
42474 * @return {Roo.ContentPanel} The panel or null if it wasn't found
42476 findPanel : function(panelId){
42477 var rs = this.regions;
42478 for(var target in rs){
42479 if(typeof rs[target] != "function"){
42480 var p = rs[target].getPanel(panelId);
42490 * Searches all regions for a panel with the specified id and activates (shows) it.
42491 * @param {String/ContentPanel} panelId The panels id or the panel itself
42492 * @return {Roo.ContentPanel} The shown panel or null
42494 showPanel : function(panelId) {
42495 var rs = this.regions;
42496 for(var target in rs){
42497 var r = rs[target];
42498 if(typeof r != "function"){
42499 if(r.hasPanel(panelId)){
42500 return r.showPanel(panelId);
42508 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
42509 * @param {Roo.state.Provider} provider (optional) An alternate state provider
42511 restoreState : function(provider){
42513 provider = Roo.state.Manager;
42515 var sm = new Roo.LayoutStateManager();
42516 sm.init(this, provider);
42520 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
42521 * object should contain properties for each region to add ContentPanels to, and each property's value should be
42522 * a valid ContentPanel config object. Example:
42524 // Create the main layout
42525 var layout = new Roo.BorderLayout('main-ct', {
42536 // Create and add multiple ContentPanels at once via configs
42539 id: 'source-files',
42541 title:'Ext Source Files',
42554 * @param {Object} regions An object containing ContentPanel configs by region name
42556 batchAdd : function(regions){
42557 this.beginUpdate();
42558 for(var rname in regions){
42559 var lr = this.regions[rname];
42561 this.addTypedPanels(lr, regions[rname]);
42568 addTypedPanels : function(lr, ps){
42569 if(typeof ps == 'string'){
42570 lr.add(new Roo.ContentPanel(ps));
42572 else if(ps instanceof Array){
42573 for(var i =0, len = ps.length; i < len; i++){
42574 this.addTypedPanels(lr, ps[i]);
42577 else if(!ps.events){ // raw config?
42579 delete ps.el; // prevent conflict
42580 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
42582 else { // panel object assumed!
42587 * Adds a xtype elements to the layout.
42591 xtype : 'ContentPanel',
42598 xtype : 'NestedLayoutPanel',
42604 items : [ ... list of content panels or nested layout panels.. ]
42608 * @param {Object} cfg Xtype definition of item to add.
42610 addxtype : function(cfg)
42612 // basically accepts a pannel...
42613 // can accept a layout region..!?!?
42614 // console.log('BorderLayout add ' + cfg.xtype)
42616 if (!cfg.xtype.match(/Panel$/)) {
42620 var region = cfg.region;
42626 xitems = cfg.items;
42633 case 'ContentPanel': // ContentPanel (el, cfg)
42634 if(cfg.autoCreate) {
42635 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42637 var el = this.el.createChild();
42638 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
42641 this.add(region, ret);
42645 case 'TreePanel': // our new panel!
42646 cfg.el = this.el.createChild();
42647 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42648 this.add(region, ret);
42651 case 'NestedLayoutPanel':
42652 // create a new Layout (which is a Border Layout...
42653 var el = this.el.createChild();
42654 var clayout = cfg.layout;
42656 clayout.items = clayout.items || [];
42657 // replace this exitems with the clayout ones..
42658 xitems = clayout.items;
42661 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
42662 cfg.background = false;
42664 var layout = new Roo.BorderLayout(el, clayout);
42666 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
42667 //console.log('adding nested layout panel ' + cfg.toSource());
42668 this.add(region, ret);
42674 // needs grid and region
42676 //var el = this.getRegion(region).el.createChild();
42677 var el = this.el.createChild();
42678 // create the grid first...
42680 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
42682 if (region == 'center' && this.active ) {
42683 cfg.background = false;
42685 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
42687 this.add(region, ret);
42688 if (cfg.background) {
42689 ret.on('activate', function(gp) {
42690 if (!gp.grid.rendered) {
42703 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
42705 // GridPanel (grid, cfg)
42708 this.beginUpdate();
42710 Roo.each(xitems, function(i) {
42720 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
42721 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
42722 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
42723 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
42726 var CP = Roo.ContentPanel;
42728 var layout = Roo.BorderLayout.create({
42732 panels: [new CP("north", "North")]
42741 panels: [new CP("west", {title: "West"})]
42750 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
42759 panels: [new CP("south", {title: "South", closable: true})]
42766 preferredTabWidth: 150,
42768 new CP("center1", {title: "Close Me", closable: true}),
42769 new CP("center2", {title: "Center Panel", closable: false})
42774 layout.getRegion("center").showPanel("center1");
42779 Roo.BorderLayout.create = function(config, targetEl){
42780 var layout = new Roo.BorderLayout(targetEl || document.body, config);
42781 layout.beginUpdate();
42782 var regions = Roo.BorderLayout.RegionFactory.validRegions;
42783 for(var j = 0, jlen = regions.length; j < jlen; j++){
42784 var lr = regions[j];
42785 if(layout.regions[lr] && config[lr].panels){
42786 var r = layout.regions[lr];
42787 var ps = config[lr].panels;
42788 layout.addTypedPanels(r, ps);
42791 layout.endUpdate();
42796 Roo.BorderLayout.RegionFactory = {
42798 validRegions : ["north","south","east","west","center"],
42801 create : function(target, mgr, config){
42802 target = target.toLowerCase();
42803 if(config.lightweight || config.basic){
42804 return new Roo.BasicLayoutRegion(mgr, config, target);
42808 return new Roo.NorthLayoutRegion(mgr, config);
42810 return new Roo.SouthLayoutRegion(mgr, config);
42812 return new Roo.EastLayoutRegion(mgr, config);
42814 return new Roo.WestLayoutRegion(mgr, config);
42816 return new Roo.CenterLayoutRegion(mgr, config);
42818 throw 'Layout region "'+target+'" not supported.';
42822 * Ext JS Library 1.1.1
42823 * Copyright(c) 2006-2007, Ext JS, LLC.
42825 * Originally Released Under LGPL - original licence link has changed is not relivant.
42828 * <script type="text/javascript">
42832 * @class Roo.BasicLayoutRegion
42833 * @extends Roo.util.Observable
42834 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
42835 * and does not have a titlebar, tabs or any other features. All it does is size and position
42836 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
42838 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
42840 this.position = pos;
42843 * @scope Roo.BasicLayoutRegion
42847 * @event beforeremove
42848 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
42849 * @param {Roo.LayoutRegion} this
42850 * @param {Roo.ContentPanel} panel The panel
42851 * @param {Object} e The cancel event object
42853 "beforeremove" : true,
42855 * @event invalidated
42856 * Fires when the layout for this region is changed.
42857 * @param {Roo.LayoutRegion} this
42859 "invalidated" : true,
42861 * @event visibilitychange
42862 * Fires when this region is shown or hidden
42863 * @param {Roo.LayoutRegion} this
42864 * @param {Boolean} visibility true or false
42866 "visibilitychange" : true,
42868 * @event paneladded
42869 * Fires when a panel is added.
42870 * @param {Roo.LayoutRegion} this
42871 * @param {Roo.ContentPanel} panel The panel
42873 "paneladded" : true,
42875 * @event panelremoved
42876 * Fires when a panel is removed.
42877 * @param {Roo.LayoutRegion} this
42878 * @param {Roo.ContentPanel} panel The panel
42880 "panelremoved" : true,
42883 * Fires when this region is collapsed.
42884 * @param {Roo.LayoutRegion} this
42886 "collapsed" : true,
42889 * Fires when this region is expanded.
42890 * @param {Roo.LayoutRegion} this
42895 * Fires when this region is slid into view.
42896 * @param {Roo.LayoutRegion} this
42898 "slideshow" : true,
42901 * Fires when this region slides out of view.
42902 * @param {Roo.LayoutRegion} this
42904 "slidehide" : true,
42906 * @event panelactivated
42907 * Fires when a panel is activated.
42908 * @param {Roo.LayoutRegion} this
42909 * @param {Roo.ContentPanel} panel The activated panel
42911 "panelactivated" : true,
42914 * Fires when the user resizes this region.
42915 * @param {Roo.LayoutRegion} this
42916 * @param {Number} newSize The new size (width for east/west, height for north/south)
42920 /** A collection of panels in this region. @type Roo.util.MixedCollection */
42921 this.panels = new Roo.util.MixedCollection();
42922 this.panels.getKey = this.getPanelId.createDelegate(this);
42924 this.activePanel = null;
42925 // ensure listeners are added...
42927 if (config.listeners || config.events) {
42928 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
42929 listeners : config.listeners || {},
42930 events : config.events || {}
42934 if(skipConfig !== true){
42935 this.applyConfig(config);
42939 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
42940 getPanelId : function(p){
42944 applyConfig : function(config){
42945 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
42946 this.config = config;
42951 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
42952 * the width, for horizontal (north, south) the height.
42953 * @param {Number} newSize The new width or height
42955 resizeTo : function(newSize){
42956 var el = this.el ? this.el :
42957 (this.activePanel ? this.activePanel.getEl() : null);
42959 switch(this.position){
42962 el.setWidth(newSize);
42963 this.fireEvent("resized", this, newSize);
42967 el.setHeight(newSize);
42968 this.fireEvent("resized", this, newSize);
42974 getBox : function(){
42975 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
42978 getMargins : function(){
42979 return this.margins;
42982 updateBox : function(box){
42984 var el = this.activePanel.getEl();
42985 el.dom.style.left = box.x + "px";
42986 el.dom.style.top = box.y + "px";
42987 this.activePanel.setSize(box.width, box.height);
42991 * Returns the container element for this region.
42992 * @return {Roo.Element}
42994 getEl : function(){
42995 return this.activePanel;
42999 * Returns true if this region is currently visible.
43000 * @return {Boolean}
43002 isVisible : function(){
43003 return this.activePanel ? true : false;
43006 setActivePanel : function(panel){
43007 panel = this.getPanel(panel);
43008 if(this.activePanel && this.activePanel != panel){
43009 this.activePanel.setActiveState(false);
43010 this.activePanel.getEl().setLeftTop(-10000,-10000);
43012 this.activePanel = panel;
43013 panel.setActiveState(true);
43015 panel.setSize(this.box.width, this.box.height);
43017 this.fireEvent("panelactivated", this, panel);
43018 this.fireEvent("invalidated");
43022 * Show the specified panel.
43023 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
43024 * @return {Roo.ContentPanel} The shown panel or null
43026 showPanel : function(panel){
43027 if(panel = this.getPanel(panel)){
43028 this.setActivePanel(panel);
43034 * Get the active panel for this region.
43035 * @return {Roo.ContentPanel} The active panel or null
43037 getActivePanel : function(){
43038 return this.activePanel;
43042 * Add the passed ContentPanel(s)
43043 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43044 * @return {Roo.ContentPanel} The panel added (if only one was added)
43046 add : function(panel){
43047 if(arguments.length > 1){
43048 for(var i = 0, len = arguments.length; i < len; i++) {
43049 this.add(arguments[i]);
43053 if(this.hasPanel(panel)){
43054 this.showPanel(panel);
43057 var el = panel.getEl();
43058 if(el.dom.parentNode != this.mgr.el.dom){
43059 this.mgr.el.dom.appendChild(el.dom);
43061 if(panel.setRegion){
43062 panel.setRegion(this);
43064 this.panels.add(panel);
43065 el.setStyle("position", "absolute");
43066 if(!panel.background){
43067 this.setActivePanel(panel);
43068 if(this.config.initialSize && this.panels.getCount()==1){
43069 this.resizeTo(this.config.initialSize);
43072 this.fireEvent("paneladded", this, panel);
43077 * Returns true if the panel is in this region.
43078 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43079 * @return {Boolean}
43081 hasPanel : function(panel){
43082 if(typeof panel == "object"){ // must be panel obj
43083 panel = panel.getId();
43085 return this.getPanel(panel) ? true : false;
43089 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
43090 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43091 * @param {Boolean} preservePanel Overrides the config preservePanel option
43092 * @return {Roo.ContentPanel} The panel that was removed
43094 remove : function(panel, preservePanel){
43095 panel = this.getPanel(panel);
43100 this.fireEvent("beforeremove", this, panel, e);
43101 if(e.cancel === true){
43104 var panelId = panel.getId();
43105 this.panels.removeKey(panelId);
43110 * Returns the panel specified or null if it's not in this region.
43111 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
43112 * @return {Roo.ContentPanel}
43114 getPanel : function(id){
43115 if(typeof id == "object"){ // must be panel obj
43118 return this.panels.get(id);
43122 * Returns this regions position (north/south/east/west/center).
43125 getPosition: function(){
43126 return this.position;
43130 * Ext JS Library 1.1.1
43131 * Copyright(c) 2006-2007, Ext JS, LLC.
43133 * Originally Released Under LGPL - original licence link has changed is not relivant.
43136 * <script type="text/javascript">
43140 * @class Roo.LayoutRegion
43141 * @extends Roo.BasicLayoutRegion
43142 * This class represents a region in a layout manager.
43143 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
43144 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
43145 * @cfg {Boolean} floatable False to disable floating (defaults to true)
43146 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
43147 * @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})
43148 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
43149 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
43150 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
43151 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
43152 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
43153 * @cfg {String} title The title for the region (overrides panel titles)
43154 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
43155 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
43156 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
43157 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
43158 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
43159 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
43160 * the space available, similar to FireFox 1.5 tabs (defaults to false)
43161 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
43162 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
43163 * @cfg {Boolean} showPin True to show a pin button
43164 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
43165 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
43166 * @cfg {Boolean} disableTabTips True to disable tab tooltips
43167 * @cfg {Number} width For East/West panels
43168 * @cfg {Number} height For North/South panels
43169 * @cfg {Boolean} split To show the splitter
43171 Roo.LayoutRegion = function(mgr, config, pos){
43172 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
43173 var dh = Roo.DomHelper;
43174 /** This region's container element
43175 * @type Roo.Element */
43176 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
43177 /** This region's title element
43178 * @type Roo.Element */
43180 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
43181 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
43182 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
43184 this.titleEl.enableDisplayMode();
43185 /** This region's title text element
43186 * @type HTMLElement */
43187 this.titleTextEl = this.titleEl.dom.firstChild;
43188 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
43189 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
43190 this.closeBtn.enableDisplayMode();
43191 this.closeBtn.on("click", this.closeClicked, this);
43192 this.closeBtn.hide();
43194 this.createBody(config);
43195 this.visible = true;
43196 this.collapsed = false;
43198 if(config.hideWhenEmpty){
43200 this.on("paneladded", this.validateVisibility, this);
43201 this.on("panelremoved", this.validateVisibility, this);
43203 this.applyConfig(config);
43206 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
43208 createBody : function(){
43209 /** This region's body element
43210 * @type Roo.Element */
43211 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
43214 applyConfig : function(c){
43215 if(c.collapsible && this.position != "center" && !this.collapsedEl){
43216 var dh = Roo.DomHelper;
43217 if(c.titlebar !== false){
43218 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
43219 this.collapseBtn.on("click", this.collapse, this);
43220 this.collapseBtn.enableDisplayMode();
43222 if(c.showPin === true || this.showPin){
43223 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
43224 this.stickBtn.enableDisplayMode();
43225 this.stickBtn.on("click", this.expand, this);
43226 this.stickBtn.hide();
43229 /** This region's collapsed element
43230 * @type Roo.Element */
43231 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
43232 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
43234 if(c.floatable !== false){
43235 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
43236 this.collapsedEl.on("click", this.collapseClick, this);
43239 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
43240 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
43241 id: "message", unselectable: "on", style:{"float":"left"}});
43242 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
43244 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
43245 this.expandBtn.on("click", this.expand, this);
43247 if(this.collapseBtn){
43248 this.collapseBtn.setVisible(c.collapsible == true);
43250 this.cmargins = c.cmargins || this.cmargins ||
43251 (this.position == "west" || this.position == "east" ?
43252 {top: 0, left: 2, right:2, bottom: 0} :
43253 {top: 2, left: 0, right:0, bottom: 2});
43254 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43255 this.bottomTabs = c.tabPosition != "top";
43256 this.autoScroll = c.autoScroll || false;
43257 if(this.autoScroll){
43258 this.bodyEl.setStyle("overflow", "auto");
43260 this.bodyEl.setStyle("overflow", "hidden");
43262 //if(c.titlebar !== false){
43263 if((!c.titlebar && !c.title) || c.titlebar === false){
43264 this.titleEl.hide();
43266 this.titleEl.show();
43268 this.titleTextEl.innerHTML = c.title;
43272 this.duration = c.duration || .30;
43273 this.slideDuration = c.slideDuration || .45;
43276 this.collapse(true);
43283 * Returns true if this region is currently visible.
43284 * @return {Boolean}
43286 isVisible : function(){
43287 return this.visible;
43291 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
43292 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
43294 setCollapsedTitle : function(title){
43295 title = title || " ";
43296 if(this.collapsedTitleTextEl){
43297 this.collapsedTitleTextEl.innerHTML = title;
43301 getBox : function(){
43303 if(!this.collapsed){
43304 b = this.el.getBox(false, true);
43306 b = this.collapsedEl.getBox(false, true);
43311 getMargins : function(){
43312 return this.collapsed ? this.cmargins : this.margins;
43315 highlight : function(){
43316 this.el.addClass("x-layout-panel-dragover");
43319 unhighlight : function(){
43320 this.el.removeClass("x-layout-panel-dragover");
43323 updateBox : function(box){
43325 if(!this.collapsed){
43326 this.el.dom.style.left = box.x + "px";
43327 this.el.dom.style.top = box.y + "px";
43328 this.updateBody(box.width, box.height);
43330 this.collapsedEl.dom.style.left = box.x + "px";
43331 this.collapsedEl.dom.style.top = box.y + "px";
43332 this.collapsedEl.setSize(box.width, box.height);
43335 this.tabs.autoSizeTabs();
43339 updateBody : function(w, h){
43341 this.el.setWidth(w);
43342 w -= this.el.getBorderWidth("rl");
43343 if(this.config.adjustments){
43344 w += this.config.adjustments[0];
43348 this.el.setHeight(h);
43349 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
43350 h -= this.el.getBorderWidth("tb");
43351 if(this.config.adjustments){
43352 h += this.config.adjustments[1];
43354 this.bodyEl.setHeight(h);
43356 h = this.tabs.syncHeight(h);
43359 if(this.panelSize){
43360 w = w !== null ? w : this.panelSize.width;
43361 h = h !== null ? h : this.panelSize.height;
43363 if(this.activePanel){
43364 var el = this.activePanel.getEl();
43365 w = w !== null ? w : el.getWidth();
43366 h = h !== null ? h : el.getHeight();
43367 this.panelSize = {width: w, height: h};
43368 this.activePanel.setSize(w, h);
43370 if(Roo.isIE && this.tabs){
43371 this.tabs.el.repaint();
43376 * Returns the container element for this region.
43377 * @return {Roo.Element}
43379 getEl : function(){
43384 * Hides this region.
43387 if(!this.collapsed){
43388 this.el.dom.style.left = "-2000px";
43391 this.collapsedEl.dom.style.left = "-2000px";
43392 this.collapsedEl.hide();
43394 this.visible = false;
43395 this.fireEvent("visibilitychange", this, false);
43399 * Shows this region if it was previously hidden.
43402 if(!this.collapsed){
43405 this.collapsedEl.show();
43407 this.visible = true;
43408 this.fireEvent("visibilitychange", this, true);
43411 closeClicked : function(){
43412 if(this.activePanel){
43413 this.remove(this.activePanel);
43417 collapseClick : function(e){
43419 e.stopPropagation();
43422 e.stopPropagation();
43428 * Collapses this region.
43429 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
43431 collapse : function(skipAnim){
43432 if(this.collapsed) return;
43433 this.collapsed = true;
43435 this.split.el.hide();
43437 if(this.config.animate && skipAnim !== true){
43438 this.fireEvent("invalidated", this);
43439 this.animateCollapse();
43441 this.el.setLocation(-20000,-20000);
43443 this.collapsedEl.show();
43444 this.fireEvent("collapsed", this);
43445 this.fireEvent("invalidated", this);
43449 animateCollapse : function(){
43454 * Expands this region if it was previously collapsed.
43455 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
43456 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
43458 expand : function(e, skipAnim){
43459 if(e) e.stopPropagation();
43460 if(!this.collapsed || this.el.hasActiveFx()) return;
43462 this.afterSlideIn();
43465 this.collapsed = false;
43466 if(this.config.animate && skipAnim !== true){
43467 this.animateExpand();
43471 this.split.el.show();
43473 this.collapsedEl.setLocation(-2000,-2000);
43474 this.collapsedEl.hide();
43475 this.fireEvent("invalidated", this);
43476 this.fireEvent("expanded", this);
43480 animateExpand : function(){
43484 initTabs : function(){
43485 this.bodyEl.setStyle("overflow", "hidden");
43486 var ts = new Roo.TabPanel(this.bodyEl.dom, {
43487 tabPosition: this.bottomTabs ? 'bottom' : 'top',
43488 disableTooltips: this.config.disableTabTips
43490 if(this.config.hideTabs){
43491 ts.stripWrap.setDisplayed(false);
43494 ts.resizeTabs = this.config.resizeTabs === true;
43495 ts.minTabWidth = this.config.minTabWidth || 40;
43496 ts.maxTabWidth = this.config.maxTabWidth || 250;
43497 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
43498 ts.monitorResize = false;
43499 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43500 ts.bodyEl.addClass('x-layout-tabs-body');
43501 this.panels.each(this.initPanelAsTab, this);
43504 initPanelAsTab : function(panel){
43505 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
43506 this.config.closeOnTab && panel.isClosable());
43507 if(panel.tabTip !== undefined){
43508 ti.setTooltip(panel.tabTip);
43510 ti.on("activate", function(){
43511 this.setActivePanel(panel);
43513 if(this.config.closeOnTab){
43514 ti.on("beforeclose", function(t, e){
43516 this.remove(panel);
43522 updatePanelTitle : function(panel, title){
43523 if(this.activePanel == panel){
43524 this.updateTitle(title);
43527 var ti = this.tabs.getTab(panel.getEl().id);
43529 if(panel.tabTip !== undefined){
43530 ti.setTooltip(panel.tabTip);
43535 updateTitle : function(title){
43536 if(this.titleTextEl && !this.config.title){
43537 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
43541 setActivePanel : function(panel){
43542 panel = this.getPanel(panel);
43543 if(this.activePanel && this.activePanel != panel){
43544 this.activePanel.setActiveState(false);
43546 this.activePanel = panel;
43547 panel.setActiveState(true);
43548 if(this.panelSize){
43549 panel.setSize(this.panelSize.width, this.panelSize.height);
43552 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
43554 this.updateTitle(panel.getTitle());
43556 this.fireEvent("invalidated", this);
43558 this.fireEvent("panelactivated", this, panel);
43562 * Shows the specified panel.
43563 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
43564 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
43566 showPanel : function(panel){
43567 if(panel = this.getPanel(panel)){
43569 var tab = this.tabs.getTab(panel.getEl().id);
43570 if(tab.isHidden()){
43571 this.tabs.unhideTab(tab.id);
43575 this.setActivePanel(panel);
43582 * Get the active panel for this region.
43583 * @return {Roo.ContentPanel} The active panel or null
43585 getActivePanel : function(){
43586 return this.activePanel;
43589 validateVisibility : function(){
43590 if(this.panels.getCount() < 1){
43591 this.updateTitle(" ");
43592 this.closeBtn.hide();
43595 if(!this.isVisible()){
43602 * Adds the passed ContentPanel(s) to this region.
43603 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43604 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
43606 add : function(panel){
43607 if(arguments.length > 1){
43608 for(var i = 0, len = arguments.length; i < len; i++) {
43609 this.add(arguments[i]);
43613 if(this.hasPanel(panel)){
43614 this.showPanel(panel);
43617 panel.setRegion(this);
43618 this.panels.add(panel);
43619 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
43620 this.bodyEl.dom.appendChild(panel.getEl().dom);
43621 if(panel.background !== true){
43622 this.setActivePanel(panel);
43624 this.fireEvent("paneladded", this, panel);
43630 this.initPanelAsTab(panel);
43632 if(panel.background !== true){
43633 this.tabs.activate(panel.getEl().id);
43635 this.fireEvent("paneladded", this, panel);
43640 * Hides the tab for the specified panel.
43641 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43643 hidePanel : function(panel){
43644 if(this.tabs && (panel = this.getPanel(panel))){
43645 this.tabs.hideTab(panel.getEl().id);
43650 * Unhides the tab for a previously hidden panel.
43651 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43653 unhidePanel : function(panel){
43654 if(this.tabs && (panel = this.getPanel(panel))){
43655 this.tabs.unhideTab(panel.getEl().id);
43659 clearPanels : function(){
43660 while(this.panels.getCount() > 0){
43661 this.remove(this.panels.first());
43666 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
43667 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43668 * @param {Boolean} preservePanel Overrides the config preservePanel option
43669 * @return {Roo.ContentPanel} The panel that was removed
43671 remove : function(panel, preservePanel){
43672 panel = this.getPanel(panel);
43677 this.fireEvent("beforeremove", this, panel, e);
43678 if(e.cancel === true){
43681 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
43682 var panelId = panel.getId();
43683 this.panels.removeKey(panelId);
43685 document.body.appendChild(panel.getEl().dom);
43688 this.tabs.removeTab(panel.getEl().id);
43689 }else if (!preservePanel){
43690 this.bodyEl.dom.removeChild(panel.getEl().dom);
43692 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
43693 var p = this.panels.first();
43694 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
43695 tempEl.appendChild(p.getEl().dom);
43696 this.bodyEl.update("");
43697 this.bodyEl.dom.appendChild(p.getEl().dom);
43699 this.updateTitle(p.getTitle());
43701 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43702 this.setActivePanel(p);
43704 panel.setRegion(null);
43705 if(this.activePanel == panel){
43706 this.activePanel = null;
43708 if(this.config.autoDestroy !== false && preservePanel !== true){
43709 try{panel.destroy();}catch(e){}
43711 this.fireEvent("panelremoved", this, panel);
43716 * Returns the TabPanel component used by this region
43717 * @return {Roo.TabPanel}
43719 getTabs : function(){
43723 createTool : function(parentEl, className){
43724 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
43725 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
43726 btn.addClassOnOver("x-layout-tools-button-over");
43731 * Ext JS Library 1.1.1
43732 * Copyright(c) 2006-2007, Ext JS, LLC.
43734 * Originally Released Under LGPL - original licence link has changed is not relivant.
43737 * <script type="text/javascript">
43743 * @class Roo.SplitLayoutRegion
43744 * @extends Roo.LayoutRegion
43745 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
43747 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
43748 this.cursor = cursor;
43749 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
43752 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
43753 splitTip : "Drag to resize.",
43754 collapsibleSplitTip : "Drag to resize. Double click to hide.",
43755 useSplitTips : false,
43757 applyConfig : function(config){
43758 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
43761 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
43762 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
43763 /** The SplitBar for this region
43764 * @type Roo.SplitBar */
43765 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
43766 this.split.on("moved", this.onSplitMove, this);
43767 this.split.useShim = config.useShim === true;
43768 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
43769 if(this.useSplitTips){
43770 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
43772 if(config.collapsible){
43773 this.split.el.on("dblclick", this.collapse, this);
43776 if(typeof config.minSize != "undefined"){
43777 this.split.minSize = config.minSize;
43779 if(typeof config.maxSize != "undefined"){
43780 this.split.maxSize = config.maxSize;
43782 if(config.hideWhenEmpty || config.hidden || config.collapsed){
43783 this.hideSplitter();
43788 getHMaxSize : function(){
43789 var cmax = this.config.maxSize || 10000;
43790 var center = this.mgr.getRegion("center");
43791 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
43794 getVMaxSize : function(){
43795 var cmax = this.config.maxSize || 10000;
43796 var center = this.mgr.getRegion("center");
43797 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
43800 onSplitMove : function(split, newSize){
43801 this.fireEvent("resized", this, newSize);
43805 * Returns the {@link Roo.SplitBar} for this region.
43806 * @return {Roo.SplitBar}
43808 getSplitBar : function(){
43813 this.hideSplitter();
43814 Roo.SplitLayoutRegion.superclass.hide.call(this);
43817 hideSplitter : function(){
43819 this.split.el.setLocation(-2000,-2000);
43820 this.split.el.hide();
43826 this.split.el.show();
43828 Roo.SplitLayoutRegion.superclass.show.call(this);
43831 beforeSlide: function(){
43832 if(Roo.isGecko){// firefox overflow auto bug workaround
43833 this.bodyEl.clip();
43834 if(this.tabs) this.tabs.bodyEl.clip();
43835 if(this.activePanel){
43836 this.activePanel.getEl().clip();
43838 if(this.activePanel.beforeSlide){
43839 this.activePanel.beforeSlide();
43845 afterSlide : function(){
43846 if(Roo.isGecko){// firefox overflow auto bug workaround
43847 this.bodyEl.unclip();
43848 if(this.tabs) this.tabs.bodyEl.unclip();
43849 if(this.activePanel){
43850 this.activePanel.getEl().unclip();
43851 if(this.activePanel.afterSlide){
43852 this.activePanel.afterSlide();
43858 initAutoHide : function(){
43859 if(this.autoHide !== false){
43860 if(!this.autoHideHd){
43861 var st = new Roo.util.DelayedTask(this.slideIn, this);
43862 this.autoHideHd = {
43863 "mouseout": function(e){
43864 if(!e.within(this.el, true)){
43868 "mouseover" : function(e){
43874 this.el.on(this.autoHideHd);
43878 clearAutoHide : function(){
43879 if(this.autoHide !== false){
43880 this.el.un("mouseout", this.autoHideHd.mouseout);
43881 this.el.un("mouseover", this.autoHideHd.mouseover);
43885 clearMonitor : function(){
43886 Roo.get(document).un("click", this.slideInIf, this);
43889 // these names are backwards but not changed for compat
43890 slideOut : function(){
43891 if(this.isSlid || this.el.hasActiveFx()){
43894 this.isSlid = true;
43895 if(this.collapseBtn){
43896 this.collapseBtn.hide();
43898 this.closeBtnState = this.closeBtn.getStyle('display');
43899 this.closeBtn.hide();
43901 this.stickBtn.show();
43904 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
43905 this.beforeSlide();
43906 this.el.setStyle("z-index", 10001);
43907 this.el.slideIn(this.getSlideAnchor(), {
43908 callback: function(){
43910 this.initAutoHide();
43911 Roo.get(document).on("click", this.slideInIf, this);
43912 this.fireEvent("slideshow", this);
43919 afterSlideIn : function(){
43920 this.clearAutoHide();
43921 this.isSlid = false;
43922 this.clearMonitor();
43923 this.el.setStyle("z-index", "");
43924 if(this.collapseBtn){
43925 this.collapseBtn.show();
43927 this.closeBtn.setStyle('display', this.closeBtnState);
43929 this.stickBtn.hide();
43931 this.fireEvent("slidehide", this);
43934 slideIn : function(cb){
43935 if(!this.isSlid || this.el.hasActiveFx()){
43939 this.isSlid = false;
43940 this.beforeSlide();
43941 this.el.slideOut(this.getSlideAnchor(), {
43942 callback: function(){
43943 this.el.setLeftTop(-10000, -10000);
43945 this.afterSlideIn();
43953 slideInIf : function(e){
43954 if(!e.within(this.el)){
43959 animateCollapse : function(){
43960 this.beforeSlide();
43961 this.el.setStyle("z-index", 20000);
43962 var anchor = this.getSlideAnchor();
43963 this.el.slideOut(anchor, {
43964 callback : function(){
43965 this.el.setStyle("z-index", "");
43966 this.collapsedEl.slideIn(anchor, {duration:.3});
43968 this.el.setLocation(-10000,-10000);
43970 this.fireEvent("collapsed", this);
43977 animateExpand : function(){
43978 this.beforeSlide();
43979 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
43980 this.el.setStyle("z-index", 20000);
43981 this.collapsedEl.hide({
43984 this.el.slideIn(this.getSlideAnchor(), {
43985 callback : function(){
43986 this.el.setStyle("z-index", "");
43989 this.split.el.show();
43991 this.fireEvent("invalidated", this);
43992 this.fireEvent("expanded", this);
44020 getAnchor : function(){
44021 return this.anchors[this.position];
44024 getCollapseAnchor : function(){
44025 return this.canchors[this.position];
44028 getSlideAnchor : function(){
44029 return this.sanchors[this.position];
44032 getAlignAdj : function(){
44033 var cm = this.cmargins;
44034 switch(this.position){
44050 getExpandAdj : function(){
44051 var c = this.collapsedEl, cm = this.cmargins;
44052 switch(this.position){
44054 return [-(cm.right+c.getWidth()+cm.left), 0];
44057 return [cm.right+c.getWidth()+cm.left, 0];
44060 return [0, -(cm.top+cm.bottom+c.getHeight())];
44063 return [0, cm.top+cm.bottom+c.getHeight()];
44069 * Ext JS Library 1.1.1
44070 * Copyright(c) 2006-2007, Ext JS, LLC.
44072 * Originally Released Under LGPL - original licence link has changed is not relivant.
44075 * <script type="text/javascript">
44078 * These classes are private internal classes
44080 Roo.CenterLayoutRegion = function(mgr, config){
44081 Roo.LayoutRegion.call(this, mgr, config, "center");
44082 this.visible = true;
44083 this.minWidth = config.minWidth || 20;
44084 this.minHeight = config.minHeight || 20;
44087 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
44089 // center panel can't be hidden
44093 // center panel can't be hidden
44096 getMinWidth: function(){
44097 return this.minWidth;
44100 getMinHeight: function(){
44101 return this.minHeight;
44106 Roo.NorthLayoutRegion = function(mgr, config){
44107 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
44109 this.split.placement = Roo.SplitBar.TOP;
44110 this.split.orientation = Roo.SplitBar.VERTICAL;
44111 this.split.el.addClass("x-layout-split-v");
44113 var size = config.initialSize || config.height;
44114 if(typeof size != "undefined"){
44115 this.el.setHeight(size);
44118 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
44119 orientation: Roo.SplitBar.VERTICAL,
44120 getBox : function(){
44121 if(this.collapsed){
44122 return this.collapsedEl.getBox();
44124 var box = this.el.getBox();
44126 box.height += this.split.el.getHeight();
44131 updateBox : function(box){
44132 if(this.split && !this.collapsed){
44133 box.height -= this.split.el.getHeight();
44134 this.split.el.setLeft(box.x);
44135 this.split.el.setTop(box.y+box.height);
44136 this.split.el.setWidth(box.width);
44138 if(this.collapsed){
44139 this.updateBody(box.width, null);
44141 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44145 Roo.SouthLayoutRegion = function(mgr, config){
44146 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
44148 this.split.placement = Roo.SplitBar.BOTTOM;
44149 this.split.orientation = Roo.SplitBar.VERTICAL;
44150 this.split.el.addClass("x-layout-split-v");
44152 var size = config.initialSize || config.height;
44153 if(typeof size != "undefined"){
44154 this.el.setHeight(size);
44157 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
44158 orientation: Roo.SplitBar.VERTICAL,
44159 getBox : function(){
44160 if(this.collapsed){
44161 return this.collapsedEl.getBox();
44163 var box = this.el.getBox();
44165 var sh = this.split.el.getHeight();
44172 updateBox : function(box){
44173 if(this.split && !this.collapsed){
44174 var sh = this.split.el.getHeight();
44177 this.split.el.setLeft(box.x);
44178 this.split.el.setTop(box.y-sh);
44179 this.split.el.setWidth(box.width);
44181 if(this.collapsed){
44182 this.updateBody(box.width, null);
44184 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44188 Roo.EastLayoutRegion = function(mgr, config){
44189 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
44191 this.split.placement = Roo.SplitBar.RIGHT;
44192 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44193 this.split.el.addClass("x-layout-split-h");
44195 var size = config.initialSize || config.width;
44196 if(typeof size != "undefined"){
44197 this.el.setWidth(size);
44200 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
44201 orientation: Roo.SplitBar.HORIZONTAL,
44202 getBox : function(){
44203 if(this.collapsed){
44204 return this.collapsedEl.getBox();
44206 var box = this.el.getBox();
44208 var sw = this.split.el.getWidth();
44215 updateBox : function(box){
44216 if(this.split && !this.collapsed){
44217 var sw = this.split.el.getWidth();
44219 this.split.el.setLeft(box.x);
44220 this.split.el.setTop(box.y);
44221 this.split.el.setHeight(box.height);
44224 if(this.collapsed){
44225 this.updateBody(null, box.height);
44227 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44231 Roo.WestLayoutRegion = function(mgr, config){
44232 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
44234 this.split.placement = Roo.SplitBar.LEFT;
44235 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44236 this.split.el.addClass("x-layout-split-h");
44238 var size = config.initialSize || config.width;
44239 if(typeof size != "undefined"){
44240 this.el.setWidth(size);
44243 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
44244 orientation: Roo.SplitBar.HORIZONTAL,
44245 getBox : function(){
44246 if(this.collapsed){
44247 return this.collapsedEl.getBox();
44249 var box = this.el.getBox();
44251 box.width += this.split.el.getWidth();
44256 updateBox : function(box){
44257 if(this.split && !this.collapsed){
44258 var sw = this.split.el.getWidth();
44260 this.split.el.setLeft(box.x+box.width);
44261 this.split.el.setTop(box.y);
44262 this.split.el.setHeight(box.height);
44264 if(this.collapsed){
44265 this.updateBody(null, box.height);
44267 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44272 * Ext JS Library 1.1.1
44273 * Copyright(c) 2006-2007, Ext JS, LLC.
44275 * Originally Released Under LGPL - original licence link has changed is not relivant.
44278 * <script type="text/javascript">
44283 * Private internal class for reading and applying state
44285 Roo.LayoutStateManager = function(layout){
44286 // default empty state
44295 Roo.LayoutStateManager.prototype = {
44296 init : function(layout, provider){
44297 this.provider = provider;
44298 var state = provider.get(layout.id+"-layout-state");
44300 var wasUpdating = layout.isUpdating();
44302 layout.beginUpdate();
44304 for(var key in state){
44305 if(typeof state[key] != "function"){
44306 var rstate = state[key];
44307 var r = layout.getRegion(key);
44310 r.resizeTo(rstate.size);
44312 if(rstate.collapsed == true){
44315 r.expand(null, true);
44321 layout.endUpdate();
44323 this.state = state;
44325 this.layout = layout;
44326 layout.on("regionresized", this.onRegionResized, this);
44327 layout.on("regioncollapsed", this.onRegionCollapsed, this);
44328 layout.on("regionexpanded", this.onRegionExpanded, this);
44331 storeState : function(){
44332 this.provider.set(this.layout.id+"-layout-state", this.state);
44335 onRegionResized : function(region, newSize){
44336 this.state[region.getPosition()].size = newSize;
44340 onRegionCollapsed : function(region){
44341 this.state[region.getPosition()].collapsed = true;
44345 onRegionExpanded : function(region){
44346 this.state[region.getPosition()].collapsed = false;
44351 * Ext JS Library 1.1.1
44352 * Copyright(c) 2006-2007, Ext JS, LLC.
44354 * Originally Released Under LGPL - original licence link has changed is not relivant.
44357 * <script type="text/javascript">
44360 * @class Roo.ContentPanel
44361 * @extends Roo.util.Observable
44362 * A basic ContentPanel element.
44363 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
44364 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
44365 * @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
44366 * @cfg {Boolean} closable True if the panel can be closed/removed
44367 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
44368 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
44369 * @cfg {Toolbar} toolbar A toolbar for this panel
44370 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
44371 * @cfg {String} title The title for this panel
44372 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
44373 * @cfg {String} url Calls {@link #setUrl} with this value
44374 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
44375 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
44377 * Create a new ContentPanel.
44378 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
44379 * @param {String/Object} config A string to set only the title or a config object
44380 * @param {String} content (optional) Set the HTML content for this panel
44381 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
44383 Roo.ContentPanel = function(el, config, content){
44387 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
44391 if (config && config.parentLayout) {
44392 el = config.parentLayout.el.createChild();
44395 if(el.autoCreate){ // xtype is available if this is called from factory
44399 this.el = Roo.get(el);
44400 if(!this.el && config && config.autoCreate){
44401 if(typeof config.autoCreate == "object"){
44402 if(!config.autoCreate.id){
44403 config.autoCreate.id = config.id||el;
44405 this.el = Roo.DomHelper.append(document.body,
44406 config.autoCreate, true);
44408 this.el = Roo.DomHelper.append(document.body,
44409 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
44412 this.closable = false;
44413 this.loaded = false;
44414 this.active = false;
44415 if(typeof config == "string"){
44416 this.title = config;
44418 Roo.apply(this, config);
44421 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
44422 this.wrapEl = this.el.wrap();
44423 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
44430 this.resizeEl = Roo.get(this.resizeEl, true);
44432 this.resizeEl = this.el;
44437 * Fires when this panel is activated.
44438 * @param {Roo.ContentPanel} this
44442 * @event deactivate
44443 * Fires when this panel is activated.
44444 * @param {Roo.ContentPanel} this
44446 "deactivate" : true,
44450 * Fires when this panel is resized if fitToFrame is true.
44451 * @param {Roo.ContentPanel} this
44452 * @param {Number} width The width after any component adjustments
44453 * @param {Number} height The height after any component adjustments
44457 if(this.autoScroll){
44458 this.resizeEl.setStyle("overflow", "auto");
44460 content = content || this.content;
44462 this.setContent(content);
44464 if(config && config.url){
44465 this.setUrl(this.url, this.params, this.loadOnce);
44470 Roo.ContentPanel.superclass.constructor.call(this);
44473 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
44475 setRegion : function(region){
44476 this.region = region;
44478 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
44480 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
44485 * Returns the toolbar for this Panel if one was configured.
44486 * @return {Roo.Toolbar}
44488 getToolbar : function(){
44489 return this.toolbar;
44492 setActiveState : function(active){
44493 this.active = active;
44495 this.fireEvent("deactivate", this);
44497 this.fireEvent("activate", this);
44501 * Updates this panel's element
44502 * @param {String} content The new content
44503 * @param {Boolean} loadScripts (optional) true to look for and process scripts
44505 setContent : function(content, loadScripts){
44506 this.el.update(content, loadScripts);
44509 ignoreResize : function(w, h){
44510 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
44513 this.lastSize = {width: w, height: h};
44518 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
44519 * @return {Roo.UpdateManager} The UpdateManager
44521 getUpdateManager : function(){
44522 return this.el.getUpdateManager();
44525 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
44526 * @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:
44529 url: "your-url.php",
44530 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
44531 callback: yourFunction,
44532 scope: yourObject, //(optional scope)
44535 text: "Loading...",
44540 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
44541 * 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.
44542 * @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}
44543 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
44544 * @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.
44545 * @return {Roo.ContentPanel} this
44548 var um = this.el.getUpdateManager();
44549 um.update.apply(um, arguments);
44555 * 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.
44556 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
44557 * @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)
44558 * @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)
44559 * @return {Roo.UpdateManager} The UpdateManager
44561 setUrl : function(url, params, loadOnce){
44562 if(this.refreshDelegate){
44563 this.removeListener("activate", this.refreshDelegate);
44565 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
44566 this.on("activate", this.refreshDelegate);
44567 return this.el.getUpdateManager();
44570 _handleRefresh : function(url, params, loadOnce){
44571 if(!loadOnce || !this.loaded){
44572 var updater = this.el.getUpdateManager();
44573 updater.update(url, params, this._setLoaded.createDelegate(this));
44577 _setLoaded : function(){
44578 this.loaded = true;
44582 * Returns this panel's id
44585 getId : function(){
44590 * Returns this panel's element - used by regiosn to add.
44591 * @return {Roo.Element}
44593 getEl : function(){
44594 return this.wrapEl || this.el;
44597 adjustForComponents : function(width, height){
44598 if(this.resizeEl != this.el){
44599 width -= this.el.getFrameWidth('lr');
44600 height -= this.el.getFrameWidth('tb');
44603 var te = this.toolbar.getEl();
44604 height -= te.getHeight();
44605 te.setWidth(width);
44607 if(this.adjustments){
44608 width += this.adjustments[0];
44609 height += this.adjustments[1];
44611 return {"width": width, "height": height};
44614 setSize : function(width, height){
44615 if(this.fitToFrame && !this.ignoreResize(width, height)){
44616 if(this.fitContainer && this.resizeEl != this.el){
44617 this.el.setSize(width, height);
44619 var size = this.adjustForComponents(width, height);
44620 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
44621 this.fireEvent('resize', this, size.width, size.height);
44626 * Returns this panel's title
44629 getTitle : function(){
44634 * Set this panel's title
44635 * @param {String} title
44637 setTitle : function(title){
44638 this.title = title;
44640 this.region.updatePanelTitle(this, title);
44645 * Returns true is this panel was configured to be closable
44646 * @return {Boolean}
44648 isClosable : function(){
44649 return this.closable;
44652 beforeSlide : function(){
44654 this.resizeEl.clip();
44657 afterSlide : function(){
44659 this.resizeEl.unclip();
44663 * Force a content refresh from the URL specified in the {@link #setUrl} method.
44664 * Will fail silently if the {@link #setUrl} method has not been called.
44665 * This does not activate the panel, just updates its content.
44667 refresh : function(){
44668 if(this.refreshDelegate){
44669 this.loaded = false;
44670 this.refreshDelegate();
44675 * Destroys this panel
44677 destroy : function(){
44678 this.el.removeAllListeners();
44679 var tempEl = document.createElement("span");
44680 tempEl.appendChild(this.el.dom);
44681 tempEl.innerHTML = "";
44687 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
44697 * @param {Object} cfg Xtype definition of item to add.
44700 addxtype : function(cfg) {
44702 if (cfg.xtype.match(/^Form$/)) {
44703 var el = this.el.createChild();
44705 this.form = new Roo.form.Form(cfg);
44708 if ( this.form.allItems.length) this.form.render(el.dom);
44711 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
44715 var ret = new Roo[cfg.xtype](cfg);
44716 ret.render(false, ''); // render blank..
44726 * @class Roo.GridPanel
44727 * @extends Roo.ContentPanel
44729 * Create a new GridPanel.
44730 * @param {Roo.grid.Grid} grid The grid for this panel
44731 * @param {String/Object} config A string to set only the panel's title, or a config object
44733 Roo.GridPanel = function(grid, config){
44736 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
44737 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
44739 this.wrapper.dom.appendChild(grid.getGridEl().dom);
44741 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
44744 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
44746 // xtype created footer. - not sure if will work as we normally have to render first..
44747 if (this.footer && !this.footer.el && this.footer.xtype) {
44749 this.footer.container = this.grid.getView().getFooterPanel(true);
44750 this.footer.dataSource = this.grid.dataSource;
44751 this.footer = Roo.factory(this.footer, Roo);
44755 grid.monitorWindowResize = false; // turn off autosizing
44756 grid.autoHeight = false;
44757 grid.autoWidth = false;
44759 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
44762 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
44763 getId : function(){
44764 return this.grid.id;
44768 * Returns the grid for this panel
44769 * @return {Roo.grid.Grid}
44771 getGrid : function(){
44775 setSize : function(width, height){
44776 if(!this.ignoreResize(width, height)){
44777 var grid = this.grid;
44778 var size = this.adjustForComponents(width, height);
44779 grid.getGridEl().setSize(size.width, size.height);
44784 beforeSlide : function(){
44785 this.grid.getView().scroller.clip();
44788 afterSlide : function(){
44789 this.grid.getView().scroller.unclip();
44792 destroy : function(){
44793 this.grid.destroy();
44795 Roo.GridPanel.superclass.destroy.call(this);
44801 * @class Roo.NestedLayoutPanel
44802 * @extends Roo.ContentPanel
44804 * Create a new NestedLayoutPanel.
44807 * @param {Roo.BorderLayout} layout The layout for this panel
44808 * @param {String/Object} config A string to set only the title or a config object
44810 Roo.NestedLayoutPanel = function(layout, config)
44812 // construct with only one argument..
44813 /* FIXME - implement nicer consturctors
44814 if (layout.layout) {
44816 layout = config.layout;
44817 delete config.layout;
44819 if (layout.xtype && !layout.getEl) {
44820 // then layout needs constructing..
44821 layout = Roo.factory(layout, Roo);
44825 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
44827 layout.monitorWindowResize = false; // turn off autosizing
44828 this.layout = layout;
44829 this.layout.getEl().addClass("x-layout-nested-layout");
44835 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
44837 setSize : function(width, height){
44838 if(!this.ignoreResize(width, height)){
44839 var size = this.adjustForComponents(width, height);
44840 var el = this.layout.getEl();
44841 el.setSize(size.width, size.height);
44842 var touch = el.dom.offsetWidth;
44843 this.layout.layout();
44844 // ie requires a double layout on the first pass
44845 if(Roo.isIE && !this.initialized){
44846 this.initialized = true;
44847 this.layout.layout();
44852 // activate all subpanels if not currently active..
44854 setActiveState : function(active){
44855 this.active = active;
44857 this.fireEvent("deactivate", this);
44861 this.fireEvent("activate", this);
44862 // not sure if this should happen before or after..
44863 if (!this.layout) {
44864 return; // should not happen..
44867 for (var r in this.layout.regions) {
44868 reg = this.layout.getRegion(r);
44869 if (reg.getActivePanel()) {
44870 //reg.showPanel(reg.getActivePanel()); // force it to activate..
44871 reg.setActivePanel(reg.getActivePanel());
44874 if (!reg.panels.length) {
44877 reg.showPanel(reg.getPanel(0));
44886 * Returns the nested BorderLayout for this panel
44887 * @return {Roo.BorderLayout}
44889 getLayout : function(){
44890 return this.layout;
44894 * Adds a xtype elements to the layout of the nested panel
44898 xtype : 'ContentPanel',
44905 xtype : 'NestedLayoutPanel',
44911 items : [ ... list of content panels or nested layout panels.. ]
44915 * @param {Object} cfg Xtype definition of item to add.
44917 addxtype : function(cfg) {
44918 return this.layout.addxtype(cfg);
44923 Roo.ScrollPanel = function(el, config, content){
44924 config = config || {};
44925 config.fitToFrame = true;
44926 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
44928 this.el.dom.style.overflow = "hidden";
44929 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
44930 this.el.removeClass("x-layout-inactive-content");
44931 this.el.on("mousewheel", this.onWheel, this);
44933 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
44934 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
44935 up.unselectable(); down.unselectable();
44936 up.on("click", this.scrollUp, this);
44937 down.on("click", this.scrollDown, this);
44938 up.addClassOnOver("x-scroller-btn-over");
44939 down.addClassOnOver("x-scroller-btn-over");
44940 up.addClassOnClick("x-scroller-btn-click");
44941 down.addClassOnClick("x-scroller-btn-click");
44942 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
44944 this.resizeEl = this.el;
44945 this.el = wrap; this.up = up; this.down = down;
44948 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
44950 wheelIncrement : 5,
44951 scrollUp : function(){
44952 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
44955 scrollDown : function(){
44956 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
44959 afterScroll : function(){
44960 var el = this.resizeEl;
44961 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
44962 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44963 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44966 setSize : function(){
44967 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
44968 this.afterScroll();
44971 onWheel : function(e){
44972 var d = e.getWheelDelta();
44973 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
44974 this.afterScroll();
44978 setContent : function(content, loadScripts){
44979 this.resizeEl.update(content, loadScripts);
44993 * @class Roo.TreePanel
44994 * @extends Roo.ContentPanel
44996 * Create a new TreePanel.
44997 * @param {String/Object} config A string to set only the panel's title, or a config object
44998 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
45000 Roo.TreePanel = function(config){
45001 var el = config.el;
45002 var tree = config.tree;
45003 delete config.tree;
45004 delete config.el; // hopefull!
45005 Roo.TreePanel.superclass.constructor.call(this, el, config);
45006 var treeEl = el.createChild();
45007 this.tree = new Roo.tree.TreePanel(treeEl , tree);
45008 //console.log(tree);
45009 this.on('activate', function()
45011 if (this.tree.rendered) {
45014 //console.log('render tree');
45015 this.tree.render();
45018 this.on('resize', function (cp, w, h) {
45019 this.tree.innerCt.setWidth(w);
45020 this.tree.innerCt.setHeight(h);
45021 this.tree.innerCt.setStyle('overflow-y', 'auto');
45028 Roo.extend(Roo.TreePanel, Roo.ContentPanel);
45042 * Ext JS Library 1.1.1
45043 * Copyright(c) 2006-2007, Ext JS, LLC.
45045 * Originally Released Under LGPL - original licence link has changed is not relivant.
45048 * <script type="text/javascript">
45053 * @class Roo.ReaderLayout
45054 * @extends Roo.BorderLayout
45055 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
45056 * center region containing two nested regions (a top one for a list view and one for item preview below),
45057 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
45058 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
45059 * expedites the setup of the overall layout and regions for this common application style.
45062 var reader = new Roo.ReaderLayout();
45063 var CP = Roo.ContentPanel; // shortcut for adding
45065 reader.beginUpdate();
45066 reader.add("north", new CP("north", "North"));
45067 reader.add("west", new CP("west", {title: "West"}));
45068 reader.add("east", new CP("east", {title: "East"}));
45070 reader.regions.listView.add(new CP("listView", "List"));
45071 reader.regions.preview.add(new CP("preview", "Preview"));
45072 reader.endUpdate();
45075 * Create a new ReaderLayout
45076 * @param {Object} config Configuration options
45077 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
45078 * document.body if omitted)
45080 Roo.ReaderLayout = function(config, renderTo){
45081 var c = config || {size:{}};
45082 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
45083 north: c.north !== false ? Roo.apply({
45087 }, c.north) : false,
45088 west: c.west !== false ? Roo.apply({
45096 margins:{left:5,right:0,bottom:5,top:5},
45097 cmargins:{left:5,right:5,bottom:5,top:5}
45098 }, c.west) : false,
45099 east: c.east !== false ? Roo.apply({
45107 margins:{left:0,right:5,bottom:5,top:5},
45108 cmargins:{left:5,right:5,bottom:5,top:5}
45109 }, c.east) : false,
45110 center: Roo.apply({
45111 tabPosition: 'top',
45115 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
45119 this.el.addClass('x-reader');
45121 this.beginUpdate();
45123 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
45124 south: c.preview !== false ? Roo.apply({
45131 cmargins:{top:5,left:0, right:0, bottom:0}
45132 }, c.preview) : false,
45133 center: Roo.apply({
45139 this.add('center', new Roo.NestedLayoutPanel(inner,
45140 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
45144 this.regions.preview = inner.getRegion('south');
45145 this.regions.listView = inner.getRegion('center');
45148 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
45150 * Ext JS Library 1.1.1
45151 * Copyright(c) 2006-2007, Ext JS, LLC.
45153 * Originally Released Under LGPL - original licence link has changed is not relivant.
45156 * <script type="text/javascript">
45160 * @class Roo.grid.Grid
45161 * @extends Roo.util.Observable
45162 * This class represents the primary interface of a component based grid control.
45163 * <br><br>Usage:<pre><code>
45164 var grid = new Roo.grid.Grid("my-container-id", {
45167 selModel: mySelectionModel,
45168 autoSizeColumns: true,
45169 monitorWindowResize: false,
45170 trackMouseOver: true
45175 * <b>Common Problems:</b><br/>
45176 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
45177 * element will correct this<br/>
45178 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
45179 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
45180 * are unpredictable.<br/>
45181 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
45182 * grid to calculate dimensions/offsets.<br/>
45184 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
45185 * The container MUST have some type of size defined for the grid to fill. The container will be
45186 * automatically set to position relative if it isn't already.
45187 * @param {Object} config A config object that sets properties on this grid.
45189 Roo.grid.Grid = function(container, config){
45190 // initialize the container
45191 this.container = Roo.get(container);
45192 this.container.update("");
45193 this.container.setStyle("overflow", "hidden");
45194 this.container.addClass('x-grid-container');
45196 this.id = this.container.id;
45198 Roo.apply(this, config);
45199 // check and correct shorthanded configs
45201 this.dataSource = this.ds;
45205 this.colModel = this.cm;
45209 this.selModel = this.sm;
45213 if (this.selModel) {
45214 this.selModel = Roo.factory(this.selModel, Roo.grid);
45215 this.sm = this.selModel;
45216 this.sm.xmodule = this.xmodule || false;
45218 if (typeof(this.colModel.config) == 'undefined') {
45219 this.colModel = new Roo.grid.ColumnModel(this.colModel);
45220 this.cm = this.colModel;
45221 this.cm.xmodule = this.xmodule || false;
45223 if (this.dataSource) {
45224 this.dataSource= Roo.factory(this.dataSource, Roo.data);
45225 this.ds = this.dataSource;
45226 this.ds.xmodule = this.xmodule || false;
45233 this.container.setWidth(this.width);
45237 this.container.setHeight(this.height);
45244 * The raw click event for the entire grid.
45245 * @param {Roo.EventObject} e
45250 * The raw dblclick event for the entire grid.
45251 * @param {Roo.EventObject} e
45255 * @event contextmenu
45256 * The raw contextmenu event for the entire grid.
45257 * @param {Roo.EventObject} e
45259 "contextmenu" : true,
45262 * The raw mousedown event for the entire grid.
45263 * @param {Roo.EventObject} e
45265 "mousedown" : true,
45268 * The raw mouseup event for the entire grid.
45269 * @param {Roo.EventObject} e
45274 * The raw mouseover event for the entire grid.
45275 * @param {Roo.EventObject} e
45277 "mouseover" : true,
45280 * The raw mouseout event for the entire grid.
45281 * @param {Roo.EventObject} e
45286 * The raw keypress event for the entire grid.
45287 * @param {Roo.EventObject} e
45292 * The raw keydown event for the entire grid.
45293 * @param {Roo.EventObject} e
45301 * Fires when a cell is clicked
45302 * @param {Grid} this
45303 * @param {Number} rowIndex
45304 * @param {Number} columnIndex
45305 * @param {Roo.EventObject} e
45307 "cellclick" : true,
45309 * @event celldblclick
45310 * Fires when a cell is double clicked
45311 * @param {Grid} this
45312 * @param {Number} rowIndex
45313 * @param {Number} columnIndex
45314 * @param {Roo.EventObject} e
45316 "celldblclick" : true,
45319 * Fires when a row is clicked
45320 * @param {Grid} this
45321 * @param {Number} rowIndex
45322 * @param {Roo.EventObject} e
45326 * @event rowdblclick
45327 * Fires when a row is double clicked
45328 * @param {Grid} this
45329 * @param {Number} rowIndex
45330 * @param {Roo.EventObject} e
45332 "rowdblclick" : true,
45334 * @event headerclick
45335 * Fires when a header is clicked
45336 * @param {Grid} this
45337 * @param {Number} columnIndex
45338 * @param {Roo.EventObject} e
45340 "headerclick" : true,
45342 * @event headerdblclick
45343 * Fires when a header cell is double clicked
45344 * @param {Grid} this
45345 * @param {Number} columnIndex
45346 * @param {Roo.EventObject} e
45348 "headerdblclick" : true,
45350 * @event rowcontextmenu
45351 * Fires when a row is right clicked
45352 * @param {Grid} this
45353 * @param {Number} rowIndex
45354 * @param {Roo.EventObject} e
45356 "rowcontextmenu" : true,
45358 * @event cellcontextmenu
45359 * Fires when a cell is right clicked
45360 * @param {Grid} this
45361 * @param {Number} rowIndex
45362 * @param {Number} cellIndex
45363 * @param {Roo.EventObject} e
45365 "cellcontextmenu" : true,
45367 * @event headercontextmenu
45368 * Fires when a header is right clicked
45369 * @param {Grid} this
45370 * @param {Number} columnIndex
45371 * @param {Roo.EventObject} e
45373 "headercontextmenu" : true,
45375 * @event bodyscroll
45376 * Fires when the body element is scrolled
45377 * @param {Number} scrollLeft
45378 * @param {Number} scrollTop
45380 "bodyscroll" : true,
45382 * @event columnresize
45383 * Fires when the user resizes a column
45384 * @param {Number} columnIndex
45385 * @param {Number} newSize
45387 "columnresize" : true,
45389 * @event columnmove
45390 * Fires when the user moves a column
45391 * @param {Number} oldIndex
45392 * @param {Number} newIndex
45394 "columnmove" : true,
45397 * Fires when row(s) start being dragged
45398 * @param {Grid} this
45399 * @param {Roo.GridDD} dd The drag drop object
45400 * @param {event} e The raw browser event
45402 "startdrag" : true,
45405 * Fires when a drag operation is complete
45406 * @param {Grid} this
45407 * @param {Roo.GridDD} dd The drag drop object
45408 * @param {event} e The raw browser event
45413 * Fires when dragged row(s) are dropped on a valid DD target
45414 * @param {Grid} this
45415 * @param {Roo.GridDD} dd The drag drop object
45416 * @param {String} targetId The target drag drop object
45417 * @param {event} e The raw browser event
45422 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
45423 * @param {Grid} this
45424 * @param {Roo.GridDD} dd The drag drop object
45425 * @param {String} targetId The target drag drop object
45426 * @param {event} e The raw browser event
45431 * Fires when the dragged row(s) first cross another DD target while being dragged
45432 * @param {Grid} this
45433 * @param {Roo.GridDD} dd The drag drop object
45434 * @param {String} targetId The target drag drop object
45435 * @param {event} e The raw browser event
45437 "dragenter" : true,
45440 * Fires when the dragged row(s) leave another DD target while being dragged
45441 * @param {Grid} this
45442 * @param {Roo.GridDD} dd The drag drop object
45443 * @param {String} targetId The target drag drop object
45444 * @param {event} e The raw browser event
45449 * Fires when the grid is rendered
45450 * @param {Grid} grid
45455 Roo.grid.Grid.superclass.constructor.call(this);
45457 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
45459 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
45461 minColumnWidth : 25,
45464 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
45465 * <b>on initial render.</b> It is more efficient to explicitly size the columns
45466 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
45468 autoSizeColumns : false,
45471 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
45473 autoSizeHeaders : true,
45476 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
45478 monitorWindowResize : true,
45481 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
45482 * rows measured to get a columns size. Default is 0 (all rows).
45484 maxRowsToMeasure : 0,
45487 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
45489 trackMouseOver : true,
45492 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
45494 enableDragDrop : false,
45497 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
45499 enableColumnMove : true,
45502 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
45504 enableColumnHide : true,
45507 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
45509 enableRowHeightSync : false,
45512 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
45517 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
45519 autoHeight : false,
45522 * @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.
45524 autoExpandColumn : false,
45527 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
45530 autoExpandMin : 50,
45533 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
45535 autoExpandMax : 1000,
45538 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
45543 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
45551 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
45552 * of a fixed width. Default is false.
45555 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
45558 * Called once after all setup has been completed and the grid is ready to be rendered.
45559 * @return {Roo.grid.Grid} this
45561 render : function(){
45562 var c = this.container;
45563 // try to detect autoHeight/width mode
45564 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
45565 this.autoHeight = true;
45567 var view = this.getView();
45570 c.on("click", this.onClick, this);
45571 c.on("dblclick", this.onDblClick, this);
45572 c.on("contextmenu", this.onContextMenu, this);
45573 c.on("keydown", this.onKeyDown, this);
45575 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
45577 this.getSelectionModel().init(this);
45582 this.loadMask = new Roo.LoadMask(this.container,
45583 Roo.apply({store:this.dataSource}, this.loadMask));
45587 if (this.toolbar && this.toolbar.xtype) {
45588 this.toolbar.container = this.getView().getHeaderPanel(true);
45589 this.toolbar = new Ext.Toolbar(this.toolbar);
45591 if (this.footer && this.footer.xtype) {
45592 this.footer.dataSource = this.getDataSource();
45593 this.footer.container = this.getView().getFooterPanel(true);
45594 this.footer = Roo.factory(this.footer, Roo);
45596 this.rendered = true;
45597 this.fireEvent('render', this);
45602 * Reconfigures the grid to use a different Store and Column Model.
45603 * The View will be bound to the new objects and refreshed.
45604 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
45605 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
45607 reconfigure : function(dataSource, colModel){
45609 this.loadMask.destroy();
45610 this.loadMask = new Roo.LoadMask(this.container,
45611 Roo.apply({store:dataSource}, this.loadMask));
45613 this.view.bind(dataSource, colModel);
45614 this.dataSource = dataSource;
45615 this.colModel = colModel;
45616 this.view.refresh(true);
45620 onKeyDown : function(e){
45621 this.fireEvent("keydown", e);
45625 * Destroy this grid.
45626 * @param {Boolean} removeEl True to remove the element
45628 destroy : function(removeEl, keepListeners){
45630 this.loadMask.destroy();
45632 var c = this.container;
45633 c.removeAllListeners();
45634 this.view.destroy();
45635 this.colModel.purgeListeners();
45636 if(!keepListeners){
45637 this.purgeListeners();
45640 if(removeEl === true){
45646 processEvent : function(name, e){
45647 this.fireEvent(name, e);
45648 var t = e.getTarget();
45650 var header = v.findHeaderIndex(t);
45651 if(header !== false){
45652 this.fireEvent("header" + name, this, header, e);
45654 var row = v.findRowIndex(t);
45655 var cell = v.findCellIndex(t);
45657 this.fireEvent("row" + name, this, row, e);
45658 if(cell !== false){
45659 this.fireEvent("cell" + name, this, row, cell, e);
45666 onClick : function(e){
45667 this.processEvent("click", e);
45671 onContextMenu : function(e, t){
45672 this.processEvent("contextmenu", e);
45676 onDblClick : function(e){
45677 this.processEvent("dblclick", e);
45681 walkCells : function(row, col, step, fn, scope){
45682 var cm = this.colModel, clen = cm.getColumnCount();
45683 var ds = this.dataSource, rlen = ds.getCount(), first = true;
45695 if(fn.call(scope || this, row, col, cm) === true){
45713 if(fn.call(scope || this, row, col, cm) === true){
45725 getSelections : function(){
45726 return this.selModel.getSelections();
45730 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
45731 * but if manual update is required this method will initiate it.
45733 autoSize : function(){
45735 this.view.layout();
45736 if(this.view.adjustForScroll){
45737 this.view.adjustForScroll();
45743 * Returns the grid's underlying element.
45744 * @return {Element} The element
45746 getGridEl : function(){
45747 return this.container;
45750 // private for compatibility, overridden by editor grid
45751 stopEditing : function(){},
45754 * Returns the grid's SelectionModel.
45755 * @return {SelectionModel}
45757 getSelectionModel : function(){
45758 if(!this.selModel){
45759 this.selModel = new Roo.grid.RowSelectionModel();
45761 return this.selModel;
45765 * Returns the grid's DataSource.
45766 * @return {DataSource}
45768 getDataSource : function(){
45769 return this.dataSource;
45773 * Returns the grid's ColumnModel.
45774 * @return {ColumnModel}
45776 getColumnModel : function(){
45777 return this.colModel;
45781 * Returns the grid's GridView object.
45782 * @return {GridView}
45784 getView : function(){
45786 this.view = new Roo.grid.GridView(this.viewConfig);
45791 * Called to get grid's drag proxy text, by default returns this.ddText.
45794 getDragDropText : function(){
45795 var count = this.selModel.getCount();
45796 return String.format(this.ddText, count, count == 1 ? '' : 's');
45800 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
45801 * %0 is replaced with the number of selected rows.
45804 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
45806 * Ext JS Library 1.1.1
45807 * Copyright(c) 2006-2007, Ext JS, LLC.
45809 * Originally Released Under LGPL - original licence link has changed is not relivant.
45812 * <script type="text/javascript">
45815 Roo.grid.AbstractGridView = function(){
45819 "beforerowremoved" : true,
45820 "beforerowsinserted" : true,
45821 "beforerefresh" : true,
45822 "rowremoved" : true,
45823 "rowsinserted" : true,
45824 "rowupdated" : true,
45827 Roo.grid.AbstractGridView.superclass.constructor.call(this);
45830 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
45831 rowClass : "x-grid-row",
45832 cellClass : "x-grid-cell",
45833 tdClass : "x-grid-td",
45834 hdClass : "x-grid-hd",
45835 splitClass : "x-grid-hd-split",
45837 init: function(grid){
45839 var cid = this.grid.getGridEl().id;
45840 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
45841 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
45842 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
45843 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
45846 getColumnRenderers : function(){
45847 var renderers = [];
45848 var cm = this.grid.colModel;
45849 var colCount = cm.getColumnCount();
45850 for(var i = 0; i < colCount; i++){
45851 renderers[i] = cm.getRenderer(i);
45856 getColumnIds : function(){
45858 var cm = this.grid.colModel;
45859 var colCount = cm.getColumnCount();
45860 for(var i = 0; i < colCount; i++){
45861 ids[i] = cm.getColumnId(i);
45866 getDataIndexes : function(){
45867 if(!this.indexMap){
45868 this.indexMap = this.buildIndexMap();
45870 return this.indexMap.colToData;
45873 getColumnIndexByDataIndex : function(dataIndex){
45874 if(!this.indexMap){
45875 this.indexMap = this.buildIndexMap();
45877 return this.indexMap.dataToCol[dataIndex];
45881 * Set a css style for a column dynamically.
45882 * @param {Number} colIndex The index of the column
45883 * @param {String} name The css property name
45884 * @param {String} value The css value
45886 setCSSStyle : function(colIndex, name, value){
45887 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
45888 Roo.util.CSS.updateRule(selector, name, value);
45891 generateRules : function(cm){
45892 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
45893 Roo.util.CSS.removeStyleSheet(rulesId);
45894 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
45895 var cid = cm.getColumnId(i);
45896 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
45897 this.tdSelector, cid, " {\n}\n",
45898 this.hdSelector, cid, " {\n}\n",
45899 this.splitSelector, cid, " {\n}\n");
45901 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
45905 * Ext JS Library 1.1.1
45906 * Copyright(c) 2006-2007, Ext JS, LLC.
45908 * Originally Released Under LGPL - original licence link has changed is not relivant.
45911 * <script type="text/javascript">
45915 // This is a support class used internally by the Grid components
45916 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
45918 this.view = grid.getView();
45919 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45920 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
45922 this.setHandleElId(Roo.id(hd));
45923 this.setOuterHandleElId(Roo.id(hd2));
45925 this.scroll = false;
45927 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
45929 getDragData : function(e){
45930 var t = Roo.lib.Event.getTarget(e);
45931 var h = this.view.findHeaderCell(t);
45933 return {ddel: h.firstChild, header:h};
45938 onInitDrag : function(e){
45939 this.view.headersDisabled = true;
45940 var clone = this.dragData.ddel.cloneNode(true);
45941 clone.id = Roo.id();
45942 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
45943 this.proxy.update(clone);
45947 afterValidDrop : function(){
45949 setTimeout(function(){
45950 v.headersDisabled = false;
45954 afterInvalidDrop : function(){
45956 setTimeout(function(){
45957 v.headersDisabled = false;
45963 * Ext JS Library 1.1.1
45964 * Copyright(c) 2006-2007, Ext JS, LLC.
45966 * Originally Released Under LGPL - original licence link has changed is not relivant.
45969 * <script type="text/javascript">
45972 // This is a support class used internally by the Grid components
45973 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
45975 this.view = grid.getView();
45976 // split the proxies so they don't interfere with mouse events
45977 this.proxyTop = Roo.DomHelper.append(document.body, {
45978 cls:"col-move-top", html:" "
45980 this.proxyBottom = Roo.DomHelper.append(document.body, {
45981 cls:"col-move-bottom", html:" "
45983 this.proxyTop.hide = this.proxyBottom.hide = function(){
45984 this.setLeftTop(-100,-100);
45985 this.setStyle("visibility", "hidden");
45987 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45988 // temporarily disabled
45989 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
45990 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
45992 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
45993 proxyOffsets : [-4, -9],
45994 fly: Roo.Element.fly,
45996 getTargetFromEvent : function(e){
45997 var t = Roo.lib.Event.getTarget(e);
45998 var cindex = this.view.findCellIndex(t);
45999 if(cindex !== false){
46000 return this.view.getHeaderCell(cindex);
46004 nextVisible : function(h){
46005 var v = this.view, cm = this.grid.colModel;
46008 if(!cm.isHidden(v.getCellIndex(h))){
46016 prevVisible : function(h){
46017 var v = this.view, cm = this.grid.colModel;
46020 if(!cm.isHidden(v.getCellIndex(h))){
46028 positionIndicator : function(h, n, e){
46029 var x = Roo.lib.Event.getPageX(e);
46030 var r = Roo.lib.Dom.getRegion(n.firstChild);
46031 var px, pt, py = r.top + this.proxyOffsets[1];
46032 if((r.right - x) <= (r.right-r.left)/2){
46033 px = r.right+this.view.borderWidth;
46039 var oldIndex = this.view.getCellIndex(h);
46040 var newIndex = this.view.getCellIndex(n);
46042 if(this.grid.colModel.isFixed(newIndex)){
46046 var locked = this.grid.colModel.isLocked(newIndex);
46051 if(oldIndex < newIndex){
46054 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
46057 px += this.proxyOffsets[0];
46058 this.proxyTop.setLeftTop(px, py);
46059 this.proxyTop.show();
46060 if(!this.bottomOffset){
46061 this.bottomOffset = this.view.mainHd.getHeight();
46063 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
46064 this.proxyBottom.show();
46068 onNodeEnter : function(n, dd, e, data){
46069 if(data.header != n){
46070 this.positionIndicator(data.header, n, e);
46074 onNodeOver : function(n, dd, e, data){
46075 var result = false;
46076 if(data.header != n){
46077 result = this.positionIndicator(data.header, n, e);
46080 this.proxyTop.hide();
46081 this.proxyBottom.hide();
46083 return result ? this.dropAllowed : this.dropNotAllowed;
46086 onNodeOut : function(n, dd, e, data){
46087 this.proxyTop.hide();
46088 this.proxyBottom.hide();
46091 onNodeDrop : function(n, dd, e, data){
46092 var h = data.header;
46094 var cm = this.grid.colModel;
46095 var x = Roo.lib.Event.getPageX(e);
46096 var r = Roo.lib.Dom.getRegion(n.firstChild);
46097 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
46098 var oldIndex = this.view.getCellIndex(h);
46099 var newIndex = this.view.getCellIndex(n);
46100 var locked = cm.isLocked(newIndex);
46104 if(oldIndex < newIndex){
46107 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
46110 cm.setLocked(oldIndex, locked, true);
46111 cm.moveColumn(oldIndex, newIndex);
46112 this.grid.fireEvent("columnmove", oldIndex, newIndex);
46120 * Ext JS Library 1.1.1
46121 * Copyright(c) 2006-2007, Ext JS, LLC.
46123 * Originally Released Under LGPL - original licence link has changed is not relivant.
46126 * <script type="text/javascript">
46130 * @class Roo.grid.GridView
46131 * @extends Roo.util.Observable
46134 * @param {Object} config
46136 Roo.grid.GridView = function(config){
46137 Roo.grid.GridView.superclass.constructor.call(this);
46140 Roo.apply(this, config);
46143 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
46146 * Override this function to apply custom css classes to rows during rendering
46147 * @param {Record} record The record
46148 * @param {Number} index
46149 * @method getRowClass
46151 rowClass : "x-grid-row",
46153 cellClass : "x-grid-col",
46155 tdClass : "x-grid-td",
46157 hdClass : "x-grid-hd",
46159 splitClass : "x-grid-split",
46161 sortClasses : ["sort-asc", "sort-desc"],
46163 enableMoveAnim : false,
46167 dh : Roo.DomHelper,
46169 fly : Roo.Element.fly,
46171 css : Roo.util.CSS,
46177 scrollIncrement : 22,
46179 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
46181 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
46183 bind : function(ds, cm){
46185 this.ds.un("load", this.onLoad, this);
46186 this.ds.un("datachanged", this.onDataChange, this);
46187 this.ds.un("add", this.onAdd, this);
46188 this.ds.un("remove", this.onRemove, this);
46189 this.ds.un("update", this.onUpdate, this);
46190 this.ds.un("clear", this.onClear, this);
46193 ds.on("load", this.onLoad, this);
46194 ds.on("datachanged", this.onDataChange, this);
46195 ds.on("add", this.onAdd, this);
46196 ds.on("remove", this.onRemove, this);
46197 ds.on("update", this.onUpdate, this);
46198 ds.on("clear", this.onClear, this);
46203 this.cm.un("widthchange", this.onColWidthChange, this);
46204 this.cm.un("headerchange", this.onHeaderChange, this);
46205 this.cm.un("hiddenchange", this.onHiddenChange, this);
46206 this.cm.un("columnmoved", this.onColumnMove, this);
46207 this.cm.un("columnlockchange", this.onColumnLock, this);
46210 this.generateRules(cm);
46211 cm.on("widthchange", this.onColWidthChange, this);
46212 cm.on("headerchange", this.onHeaderChange, this);
46213 cm.on("hiddenchange", this.onHiddenChange, this);
46214 cm.on("columnmoved", this.onColumnMove, this);
46215 cm.on("columnlockchange", this.onColumnLock, this);
46220 init: function(grid){
46221 Roo.grid.GridView.superclass.init.call(this, grid);
46223 this.bind(grid.dataSource, grid.colModel);
46225 grid.on("headerclick", this.handleHeaderClick, this);
46227 if(grid.trackMouseOver){
46228 grid.on("mouseover", this.onRowOver, this);
46229 grid.on("mouseout", this.onRowOut, this);
46231 grid.cancelTextSelection = function(){};
46232 this.gridId = grid.id;
46234 var tpls = this.templates || {};
46237 tpls.master = new Roo.Template(
46238 '<div class="x-grid" hidefocus="true">',
46239 '<div class="x-grid-topbar"></div>',
46240 '<div class="x-grid-scroller"><div></div></div>',
46241 '<div class="x-grid-locked">',
46242 '<div class="x-grid-header">{lockedHeader}</div>',
46243 '<div class="x-grid-body">{lockedBody}</div>',
46245 '<div class="x-grid-viewport">',
46246 '<div class="x-grid-header">{header}</div>',
46247 '<div class="x-grid-body">{body}</div>',
46249 '<div class="x-grid-bottombar"></div>',
46250 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
46251 '<div class="x-grid-resize-proxy"> </div>',
46254 tpls.master.disableformats = true;
46258 tpls.header = new Roo.Template(
46259 '<table border="0" cellspacing="0" cellpadding="0">',
46260 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
46263 tpls.header.disableformats = true;
46265 tpls.header.compile();
46268 tpls.hcell = new Roo.Template(
46269 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
46270 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
46273 tpls.hcell.disableFormats = true;
46275 tpls.hcell.compile();
46278 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
46279 tpls.hsplit.disableFormats = true;
46281 tpls.hsplit.compile();
46284 tpls.body = new Roo.Template(
46285 '<table border="0" cellspacing="0" cellpadding="0">',
46286 "<tbody>{rows}</tbody>",
46289 tpls.body.disableFormats = true;
46291 tpls.body.compile();
46294 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
46295 tpls.row.disableFormats = true;
46297 tpls.row.compile();
46300 tpls.cell = new Roo.Template(
46301 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
46302 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
46305 tpls.cell.disableFormats = true;
46307 tpls.cell.compile();
46309 this.templates = tpls;
46312 // remap these for backwards compat
46313 onColWidthChange : function(){
46314 this.updateColumns.apply(this, arguments);
46316 onHeaderChange : function(){
46317 this.updateHeaders.apply(this, arguments);
46319 onHiddenChange : function(){
46320 this.handleHiddenChange.apply(this, arguments);
46322 onColumnMove : function(){
46323 this.handleColumnMove.apply(this, arguments);
46325 onColumnLock : function(){
46326 this.handleLockChange.apply(this, arguments);
46329 onDataChange : function(){
46331 this.updateHeaderSortState();
46334 onClear : function(){
46338 onUpdate : function(ds, record){
46339 this.refreshRow(record);
46342 refreshRow : function(record){
46343 var ds = this.ds, index;
46344 if(typeof record == 'number'){
46346 record = ds.getAt(index);
46348 index = ds.indexOf(record);
46350 this.insertRows(ds, index, index, true);
46351 this.onRemove(ds, record, index+1, true);
46352 this.syncRowHeights(index, index);
46354 this.fireEvent("rowupdated", this, index, record);
46357 onAdd : function(ds, records, index){
46358 this.insertRows(ds, index, index + (records.length-1));
46361 onRemove : function(ds, record, index, isUpdate){
46362 if(isUpdate !== true){
46363 this.fireEvent("beforerowremoved", this, index, record);
46365 var bt = this.getBodyTable(), lt = this.getLockedTable();
46366 if(bt.rows[index]){
46367 bt.firstChild.removeChild(bt.rows[index]);
46369 if(lt.rows[index]){
46370 lt.firstChild.removeChild(lt.rows[index]);
46372 if(isUpdate !== true){
46373 this.stripeRows(index);
46374 this.syncRowHeights(index, index);
46376 this.fireEvent("rowremoved", this, index, record);
46380 onLoad : function(){
46381 this.scrollToTop();
46385 * Scrolls the grid to the top
46387 scrollToTop : function(){
46389 this.scroller.dom.scrollTop = 0;
46395 * Gets a panel in the header of the grid that can be used for toolbars etc.
46396 * After modifying the contents of this panel a call to grid.autoSize() may be
46397 * required to register any changes in size.
46398 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
46399 * @return Roo.Element
46401 getHeaderPanel : function(doShow){
46403 this.headerPanel.show();
46405 return this.headerPanel;
46409 * Gets a panel in the footer of the grid that can be used for toolbars etc.
46410 * After modifying the contents of this panel a call to grid.autoSize() may be
46411 * required to register any changes in size.
46412 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
46413 * @return Roo.Element
46415 getFooterPanel : function(doShow){
46417 this.footerPanel.show();
46419 return this.footerPanel;
46422 initElements : function(){
46423 var E = Roo.Element;
46424 var el = this.grid.getGridEl().dom.firstChild;
46425 var cs = el.childNodes;
46427 this.el = new E(el);
46428 this.headerPanel = new E(el.firstChild);
46429 this.headerPanel.enableDisplayMode("block");
46431 this.scroller = new E(cs[1]);
46432 this.scrollSizer = new E(this.scroller.dom.firstChild);
46434 this.lockedWrap = new E(cs[2]);
46435 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
46436 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
46438 this.mainWrap = new E(cs[3]);
46439 this.mainHd = new E(this.mainWrap.dom.firstChild);
46440 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
46442 this.footerPanel = new E(cs[4]);
46443 this.footerPanel.enableDisplayMode("block");
46445 this.focusEl = new E(cs[5]);
46446 this.focusEl.swallowEvent("click", true);
46447 this.resizeProxy = new E(cs[6]);
46449 this.headerSelector = String.format(
46450 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
46451 this.lockedHd.id, this.mainHd.id
46454 this.splitterSelector = String.format(
46455 '#{0} div.x-grid-split, #{1} div.x-grid-split',
46456 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
46459 idToCssName : function(s)
46461 return s.replace(/[^a-z0-9]+/ig, '-');
46464 getHeaderCell : function(index){
46465 return Roo.DomQuery.select(this.headerSelector)[index];
46468 getHeaderCellMeasure : function(index){
46469 return this.getHeaderCell(index).firstChild;
46472 getHeaderCellText : function(index){
46473 return this.getHeaderCell(index).firstChild.firstChild;
46476 getLockedTable : function(){
46477 return this.lockedBody.dom.firstChild;
46480 getBodyTable : function(){
46481 return this.mainBody.dom.firstChild;
46484 getLockedRow : function(index){
46485 return this.getLockedTable().rows[index];
46488 getRow : function(index){
46489 return this.getBodyTable().rows[index];
46492 getRowComposite : function(index){
46494 this.rowEl = new Roo.CompositeElementLite();
46496 var els = [], lrow, mrow;
46497 if(lrow = this.getLockedRow(index)){
46500 if(mrow = this.getRow(index)){
46503 this.rowEl.elements = els;
46507 getCell : function(rowIndex, colIndex){
46508 var locked = this.cm.getLockedCount();
46510 if(colIndex < locked){
46511 source = this.lockedBody.dom.firstChild;
46513 source = this.mainBody.dom.firstChild;
46514 colIndex -= locked;
46516 return source.rows[rowIndex].childNodes[colIndex];
46519 getCellText : function(rowIndex, colIndex){
46520 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
46523 getCellBox : function(cell){
46524 var b = this.fly(cell).getBox();
46525 if(Roo.isOpera){ // opera fails to report the Y
46526 b.y = cell.offsetTop + this.mainBody.getY();
46531 getCellIndex : function(cell){
46532 var id = String(cell.className).match(this.cellRE);
46534 return parseInt(id[1], 10);
46539 findHeaderIndex : function(n){
46540 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46541 return r ? this.getCellIndex(r) : false;
46544 findHeaderCell : function(n){
46545 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46546 return r ? r : false;
46549 findRowIndex : function(n){
46553 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
46554 return r ? r.rowIndex : false;
46557 findCellIndex : function(node){
46558 var stop = this.el.dom;
46559 while(node && node != stop){
46560 if(this.findRE.test(node.className)){
46561 return this.getCellIndex(node);
46563 node = node.parentNode;
46568 getColumnId : function(index){
46569 return this.cm.getColumnId(index);
46572 getSplitters : function(){
46573 if(this.splitterSelector){
46574 return Roo.DomQuery.select(this.splitterSelector);
46580 getSplitter : function(index){
46581 return this.getSplitters()[index];
46584 onRowOver : function(e, t){
46586 if((row = this.findRowIndex(t)) !== false){
46587 this.getRowComposite(row).addClass("x-grid-row-over");
46591 onRowOut : function(e, t){
46593 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
46594 this.getRowComposite(row).removeClass("x-grid-row-over");
46598 renderHeaders : function(){
46600 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
46601 var cb = [], lb = [], sb = [], lsb = [], p = {};
46602 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46603 p.cellId = "x-grid-hd-0-" + i;
46604 p.splitId = "x-grid-csplit-0-" + i;
46605 p.id = cm.getColumnId(i);
46606 p.title = cm.getColumnTooltip(i) || "";
46607 p.value = cm.getColumnHeader(i) || "";
46608 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
46609 if(!cm.isLocked(i)){
46610 cb[cb.length] = ct.apply(p);
46611 sb[sb.length] = st.apply(p);
46613 lb[lb.length] = ct.apply(p);
46614 lsb[lsb.length] = st.apply(p);
46617 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
46618 ht.apply({cells: cb.join(""), splits:sb.join("")})];
46621 updateHeaders : function(){
46622 var html = this.renderHeaders();
46623 this.lockedHd.update(html[0]);
46624 this.mainHd.update(html[1]);
46628 * Focuses the specified row.
46629 * @param {Number} row The row index
46631 focusRow : function(row){
46632 var x = this.scroller.dom.scrollLeft;
46633 this.focusCell(row, 0, false);
46634 this.scroller.dom.scrollLeft = x;
46638 * Focuses the specified cell.
46639 * @param {Number} row The row index
46640 * @param {Number} col The column index
46641 * @param {Boolean} hscroll false to disable horizontal scrolling
46643 focusCell : function(row, col, hscroll){
46644 var el = this.ensureVisible(row, col, hscroll);
46645 this.focusEl.alignTo(el, "tl-tl");
46647 this.focusEl.focus();
46649 this.focusEl.focus.defer(1, this.focusEl);
46654 * Scrolls the specified cell into view
46655 * @param {Number} row The row index
46656 * @param {Number} col The column index
46657 * @param {Boolean} hscroll false to disable horizontal scrolling
46659 ensureVisible : function(row, col, hscroll){
46660 if(typeof row != "number"){
46661 row = row.rowIndex;
46663 if(row < 0 && row >= this.ds.getCount()){
46666 col = (col !== undefined ? col : 0);
46667 var cm = this.grid.colModel;
46668 while(cm.isHidden(col)){
46672 var el = this.getCell(row, col);
46676 var c = this.scroller.dom;
46678 var ctop = parseInt(el.offsetTop, 10);
46679 var cleft = parseInt(el.offsetLeft, 10);
46680 var cbot = ctop + el.offsetHeight;
46681 var cright = cleft + el.offsetWidth;
46683 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
46684 var stop = parseInt(c.scrollTop, 10);
46685 var sleft = parseInt(c.scrollLeft, 10);
46686 var sbot = stop + ch;
46687 var sright = sleft + c.clientWidth;
46690 c.scrollTop = ctop;
46691 }else if(cbot > sbot){
46692 c.scrollTop = cbot-ch;
46695 if(hscroll !== false){
46697 c.scrollLeft = cleft;
46698 }else if(cright > sright){
46699 c.scrollLeft = cright-c.clientWidth;
46705 updateColumns : function(){
46706 this.grid.stopEditing();
46707 var cm = this.grid.colModel, colIds = this.getColumnIds();
46708 //var totalWidth = cm.getTotalWidth();
46710 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46711 //if(cm.isHidden(i)) continue;
46712 var w = cm.getColumnWidth(i);
46713 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46714 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
46716 this.updateSplitters();
46719 generateRules : function(cm){
46720 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
46721 Roo.util.CSS.removeStyleSheet(rulesId);
46722 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46723 var cid = cm.getColumnId(i);
46725 if(cm.config[i].align){
46726 align = 'text-align:'+cm.config[i].align+';';
46729 if(cm.isHidden(i)){
46730 hidden = 'display:none;';
46732 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
46734 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
46735 this.hdSelector, cid, " {\n", align, width, "}\n",
46736 this.tdSelector, cid, " {\n",hidden,"\n}\n",
46737 this.splitSelector, cid, " {\n", hidden , "\n}\n");
46739 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46742 updateSplitters : function(){
46743 var cm = this.cm, s = this.getSplitters();
46744 if(s){ // splitters not created yet
46745 var pos = 0, locked = true;
46746 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46747 if(cm.isHidden(i)) continue;
46748 var w = cm.getColumnWidth(i);
46749 if(!cm.isLocked(i) && locked){
46754 s[i].style.left = (pos-this.splitOffset) + "px";
46759 handleHiddenChange : function(colModel, colIndex, hidden){
46761 this.hideColumn(colIndex);
46763 this.unhideColumn(colIndex);
46767 hideColumn : function(colIndex){
46768 var cid = this.getColumnId(colIndex);
46769 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
46770 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
46772 this.updateHeaders();
46774 this.updateSplitters();
46778 unhideColumn : function(colIndex){
46779 var cid = this.getColumnId(colIndex);
46780 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
46781 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
46784 this.updateHeaders();
46786 this.updateSplitters();
46790 insertRows : function(dm, firstRow, lastRow, isUpdate){
46791 if(firstRow == 0 && lastRow == dm.getCount()-1){
46795 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
46797 var s = this.getScrollState();
46798 var markup = this.renderRows(firstRow, lastRow);
46799 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
46800 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
46801 this.restoreScroll(s);
46803 this.fireEvent("rowsinserted", this, firstRow, lastRow);
46804 this.syncRowHeights(firstRow, lastRow);
46805 this.stripeRows(firstRow);
46811 bufferRows : function(markup, target, index){
46812 var before = null, trows = target.rows, tbody = target.tBodies[0];
46813 if(index < trows.length){
46814 before = trows[index];
46816 var b = document.createElement("div");
46817 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
46818 var rows = b.firstChild.rows;
46819 for(var i = 0, len = rows.length; i < len; i++){
46821 tbody.insertBefore(rows[0], before);
46823 tbody.appendChild(rows[0]);
46830 deleteRows : function(dm, firstRow, lastRow){
46831 if(dm.getRowCount()<1){
46832 this.fireEvent("beforerefresh", this);
46833 this.mainBody.update("");
46834 this.lockedBody.update("");
46835 this.fireEvent("refresh", this);
46837 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
46838 var bt = this.getBodyTable();
46839 var tbody = bt.firstChild;
46840 var rows = bt.rows;
46841 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
46842 tbody.removeChild(rows[firstRow]);
46844 this.stripeRows(firstRow);
46845 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
46849 updateRows : function(dataSource, firstRow, lastRow){
46850 var s = this.getScrollState();
46852 this.restoreScroll(s);
46855 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
46859 this.updateHeaderSortState();
46862 getScrollState : function(){
46863 var sb = this.scroller.dom;
46864 return {left: sb.scrollLeft, top: sb.scrollTop};
46867 stripeRows : function(startRow){
46868 if(!this.grid.stripeRows || this.ds.getCount() < 1){
46871 startRow = startRow || 0;
46872 var rows = this.getBodyTable().rows;
46873 var lrows = this.getLockedTable().rows;
46874 var cls = ' x-grid-row-alt ';
46875 for(var i = startRow, len = rows.length; i < len; i++){
46876 var row = rows[i], lrow = lrows[i];
46877 var isAlt = ((i+1) % 2 == 0);
46878 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
46879 if(isAlt == hasAlt){
46883 row.className += " x-grid-row-alt";
46885 row.className = row.className.replace("x-grid-row-alt", "");
46888 lrow.className = row.className;
46893 restoreScroll : function(state){
46894 var sb = this.scroller.dom;
46895 sb.scrollLeft = state.left;
46896 sb.scrollTop = state.top;
46900 syncScroll : function(){
46901 var sb = this.scroller.dom;
46902 var sh = this.mainHd.dom;
46903 var bs = this.mainBody.dom;
46904 var lv = this.lockedBody.dom;
46905 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
46906 lv.scrollTop = bs.scrollTop = sb.scrollTop;
46909 handleScroll : function(e){
46911 var sb = this.scroller.dom;
46912 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
46916 handleWheel : function(e){
46917 var d = e.getWheelDelta();
46918 this.scroller.dom.scrollTop -= d*22;
46919 // set this here to prevent jumpy scrolling on large tables
46920 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
46924 renderRows : function(startRow, endRow){
46925 // pull in all the crap needed to render rows
46926 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
46927 var colCount = cm.getColumnCount();
46929 if(ds.getCount() < 1){
46933 // build a map for all the columns
46935 for(var i = 0; i < colCount; i++){
46936 var name = cm.getDataIndex(i);
46938 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
46939 renderer : cm.getRenderer(i),
46940 id : cm.getColumnId(i),
46941 locked : cm.isLocked(i)
46945 startRow = startRow || 0;
46946 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
46948 // records to render
46949 var rs = ds.getRange(startRow, endRow);
46951 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
46954 // As much as I hate to duplicate code, this was branched because FireFox really hates
46955 // [].join("") on strings. The performance difference was substantial enough to
46956 // branch this function
46957 doRender : Roo.isGecko ?
46958 function(cs, rs, ds, startRow, colCount, stripe){
46959 var ts = this.templates, ct = ts.cell, rt = ts.row;
46961 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
46962 for(var j = 0, len = rs.length; j < len; j++){
46963 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
46964 for(var i = 0; i < colCount; i++){
46966 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
46968 p.css = p.attr = "";
46969 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
46970 if(p.value == undefined || p.value === "") p.value = " ";
46971 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
46972 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
46974 var markup = ct.apply(p);
46982 if(stripe && ((rowIndex+1) % 2 == 0)){
46983 alt[0] = "x-grid-row-alt";
46986 alt[1] = " x-grid-dirty-row";
46989 if(this.getRowClass){
46990 alt[2] = this.getRowClass(r, rowIndex);
46992 rp.alt = alt.join(" ");
46993 lbuf+= rt.apply(rp);
46995 buf+= rt.apply(rp);
46997 return [lbuf, buf];
46999 function(cs, rs, ds, startRow, colCount, stripe){
47000 var ts = this.templates, ct = ts.cell, rt = ts.row;
47002 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
47003 for(var j = 0, len = rs.length; j < len; j++){
47004 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
47005 for(var i = 0; i < colCount; i++){
47007 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
47009 p.css = p.attr = "";
47010 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
47011 if(p.value == undefined || p.value === "") p.value = " ";
47012 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
47013 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
47015 var markup = ct.apply(p);
47017 cb[cb.length] = markup;
47019 lcb[lcb.length] = markup;
47023 if(stripe && ((rowIndex+1) % 2 == 0)){
47024 alt[0] = "x-grid-row-alt";
47027 alt[1] = " x-grid-dirty-row";
47030 if(this.getRowClass){
47031 alt[2] = this.getRowClass(r, rowIndex);
47033 rp.alt = alt.join(" ");
47034 rp.cells = lcb.join("");
47035 lbuf[lbuf.length] = rt.apply(rp);
47036 rp.cells = cb.join("");
47037 buf[buf.length] = rt.apply(rp);
47039 return [lbuf.join(""), buf.join("")];
47042 renderBody : function(){
47043 var markup = this.renderRows();
47044 var bt = this.templates.body;
47045 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
47049 * Refreshes the grid
47050 * @param {Boolean} headersToo
47052 refresh : function(headersToo){
47053 this.fireEvent("beforerefresh", this);
47054 this.grid.stopEditing();
47055 var result = this.renderBody();
47056 this.lockedBody.update(result[0]);
47057 this.mainBody.update(result[1]);
47058 if(headersToo === true){
47059 this.updateHeaders();
47060 this.updateColumns();
47061 this.updateSplitters();
47062 this.updateHeaderSortState();
47064 this.syncRowHeights();
47066 this.fireEvent("refresh", this);
47069 handleColumnMove : function(cm, oldIndex, newIndex){
47070 this.indexMap = null;
47071 var s = this.getScrollState();
47072 this.refresh(true);
47073 this.restoreScroll(s);
47074 this.afterMove(newIndex);
47077 afterMove : function(colIndex){
47078 if(this.enableMoveAnim && Roo.enableFx){
47079 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
47083 updateCell : function(dm, rowIndex, dataIndex){
47084 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
47085 if(typeof colIndex == "undefined"){ // not present in grid
47088 var cm = this.grid.colModel;
47089 var cell = this.getCell(rowIndex, colIndex);
47090 var cellText = this.getCellText(rowIndex, colIndex);
47093 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
47094 id : cm.getColumnId(colIndex),
47095 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
47097 var renderer = cm.getRenderer(colIndex);
47098 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
47099 if(typeof val == "undefined" || val === "") val = " ";
47100 cellText.innerHTML = val;
47101 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
47102 this.syncRowHeights(rowIndex, rowIndex);
47105 calcColumnWidth : function(colIndex, maxRowsToMeasure){
47107 if(this.grid.autoSizeHeaders){
47108 var h = this.getHeaderCellMeasure(colIndex);
47109 maxWidth = Math.max(maxWidth, h.scrollWidth);
47112 if(this.cm.isLocked(colIndex)){
47113 tb = this.getLockedTable();
47116 tb = this.getBodyTable();
47117 index = colIndex - this.cm.getLockedCount();
47120 var rows = tb.rows;
47121 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
47122 for(var i = 0; i < stopIndex; i++){
47123 var cell = rows[i].childNodes[index].firstChild;
47124 maxWidth = Math.max(maxWidth, cell.scrollWidth);
47127 return maxWidth + /*margin for error in IE*/ 5;
47130 * Autofit a column to its content.
47131 * @param {Number} colIndex
47132 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
47134 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
47135 if(this.cm.isHidden(colIndex)){
47136 return; // can't calc a hidden column
47139 var cid = this.cm.getColumnId(colIndex);
47140 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
47141 if(this.grid.autoSizeHeaders){
47142 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
47145 var newWidth = this.calcColumnWidth(colIndex);
47146 this.cm.setColumnWidth(colIndex,
47147 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
47148 if(!suppressEvent){
47149 this.grid.fireEvent("columnresize", colIndex, newWidth);
47154 * Autofits all columns to their content and then expands to fit any extra space in the grid
47156 autoSizeColumns : function(){
47157 var cm = this.grid.colModel;
47158 var colCount = cm.getColumnCount();
47159 for(var i = 0; i < colCount; i++){
47160 this.autoSizeColumn(i, true, true);
47162 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
47165 this.updateColumns();
47171 * Autofits all columns to the grid's width proportionate with their current size
47172 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
47174 fitColumns : function(reserveScrollSpace){
47175 var cm = this.grid.colModel;
47176 var colCount = cm.getColumnCount();
47180 for (i = 0; i < colCount; i++){
47181 if(!cm.isHidden(i) && !cm.isFixed(i)){
47182 w = cm.getColumnWidth(i);
47188 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
47189 if(reserveScrollSpace){
47192 var frac = (avail - cm.getTotalWidth())/width;
47193 while (cols.length){
47196 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
47198 this.updateColumns();
47202 onRowSelect : function(rowIndex){
47203 var row = this.getRowComposite(rowIndex);
47204 row.addClass("x-grid-row-selected");
47207 onRowDeselect : function(rowIndex){
47208 var row = this.getRowComposite(rowIndex);
47209 row.removeClass("x-grid-row-selected");
47212 onCellSelect : function(row, col){
47213 var cell = this.getCell(row, col);
47215 Roo.fly(cell).addClass("x-grid-cell-selected");
47219 onCellDeselect : function(row, col){
47220 var cell = this.getCell(row, col);
47222 Roo.fly(cell).removeClass("x-grid-cell-selected");
47226 updateHeaderSortState : function(){
47227 var state = this.ds.getSortState();
47231 this.sortState = state;
47232 var sortColumn = this.cm.findColumnIndex(state.field);
47233 if(sortColumn != -1){
47234 var sortDir = state.direction;
47235 var sc = this.sortClasses;
47236 var hds = this.el.select(this.headerSelector).removeClass(sc);
47237 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
47241 handleHeaderClick : function(g, index){
47242 if(this.headersDisabled){
47245 var dm = g.dataSource, cm = g.colModel;
47246 if(!cm.isSortable(index)){
47250 dm.sort(cm.getDataIndex(index));
47254 destroy : function(){
47256 this.colMenu.removeAll();
47257 Roo.menu.MenuMgr.unregister(this.colMenu);
47258 this.colMenu.getEl().remove();
47259 delete this.colMenu;
47262 this.hmenu.removeAll();
47263 Roo.menu.MenuMgr.unregister(this.hmenu);
47264 this.hmenu.getEl().remove();
47267 if(this.grid.enableColumnMove){
47268 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47270 for(var dd in dds){
47271 if(!dds[dd].config.isTarget && dds[dd].dragElId){
47272 var elid = dds[dd].dragElId;
47274 Roo.get(elid).remove();
47275 } else if(dds[dd].config.isTarget){
47276 dds[dd].proxyTop.remove();
47277 dds[dd].proxyBottom.remove();
47280 if(Roo.dd.DDM.locationCache[dd]){
47281 delete Roo.dd.DDM.locationCache[dd];
47284 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47287 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
47288 this.bind(null, null);
47289 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
47292 handleLockChange : function(){
47293 this.refresh(true);
47296 onDenyColumnLock : function(){
47300 onDenyColumnHide : function(){
47304 handleHdMenuClick : function(item){
47305 var index = this.hdCtxIndex;
47306 var cm = this.cm, ds = this.ds;
47309 ds.sort(cm.getDataIndex(index), "ASC");
47312 ds.sort(cm.getDataIndex(index), "DESC");
47315 var lc = cm.getLockedCount();
47316 if(cm.getColumnCount(true) <= lc+1){
47317 this.onDenyColumnLock();
47321 cm.setLocked(index, true, true);
47322 cm.moveColumn(index, lc);
47323 this.grid.fireEvent("columnmove", index, lc);
47325 cm.setLocked(index, true);
47329 var lc = cm.getLockedCount();
47330 if((lc-1) != index){
47331 cm.setLocked(index, false, true);
47332 cm.moveColumn(index, lc-1);
47333 this.grid.fireEvent("columnmove", index, lc-1);
47335 cm.setLocked(index, false);
47339 index = cm.getIndexById(item.id.substr(4));
47341 if(item.checked && cm.getColumnCount(true) <= 1){
47342 this.onDenyColumnHide();
47345 cm.setHidden(index, item.checked);
47351 beforeColMenuShow : function(){
47352 var cm = this.cm, colCount = cm.getColumnCount();
47353 this.colMenu.removeAll();
47354 for(var i = 0; i < colCount; i++){
47355 this.colMenu.add(new Roo.menu.CheckItem({
47356 id: "col-"+cm.getColumnId(i),
47357 text: cm.getColumnHeader(i),
47358 checked: !cm.isHidden(i),
47364 handleHdCtx : function(g, index, e){
47366 var hd = this.getHeaderCell(index);
47367 this.hdCtxIndex = index;
47368 var ms = this.hmenu.items, cm = this.cm;
47369 ms.get("asc").setDisabled(!cm.isSortable(index));
47370 ms.get("desc").setDisabled(!cm.isSortable(index));
47371 if(this.grid.enableColLock !== false){
47372 ms.get("lock").setDisabled(cm.isLocked(index));
47373 ms.get("unlock").setDisabled(!cm.isLocked(index));
47375 this.hmenu.show(hd, "tl-bl");
47378 handleHdOver : function(e){
47379 var hd = this.findHeaderCell(e.getTarget());
47380 if(hd && !this.headersDisabled){
47381 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
47382 this.fly(hd).addClass("x-grid-hd-over");
47387 handleHdOut : function(e){
47388 var hd = this.findHeaderCell(e.getTarget());
47390 this.fly(hd).removeClass("x-grid-hd-over");
47394 handleSplitDblClick : function(e, t){
47395 var i = this.getCellIndex(t);
47396 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
47397 this.autoSizeColumn(i, true);
47402 render : function(){
47405 var colCount = cm.getColumnCount();
47407 if(this.grid.monitorWindowResize === true){
47408 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47410 var header = this.renderHeaders();
47411 var body = this.templates.body.apply({rows:""});
47412 var html = this.templates.master.apply({
47415 lockedHeader: header[0],
47419 //this.updateColumns();
47421 this.grid.getGridEl().dom.innerHTML = html;
47423 this.initElements();
47425 this.scroller.on("scroll", this.handleScroll, this);
47426 this.lockedBody.on("mousewheel", this.handleWheel, this);
47427 this.mainBody.on("mousewheel", this.handleWheel, this);
47429 this.mainHd.on("mouseover", this.handleHdOver, this);
47430 this.mainHd.on("mouseout", this.handleHdOut, this);
47431 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
47432 {delegate: "."+this.splitClass});
47434 this.lockedHd.on("mouseover", this.handleHdOver, this);
47435 this.lockedHd.on("mouseout", this.handleHdOut, this);
47436 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
47437 {delegate: "."+this.splitClass});
47439 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
47440 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47443 this.updateSplitters();
47445 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
47446 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47447 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47450 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
47451 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
47453 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
47454 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
47456 if(this.grid.enableColLock !== false){
47457 this.hmenu.add('-',
47458 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
47459 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
47462 if(this.grid.enableColumnHide !== false){
47464 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
47465 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
47466 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
47468 this.hmenu.add('-',
47469 {id:"columns", text: this.columnsText, menu: this.colMenu}
47472 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
47474 this.grid.on("headercontextmenu", this.handleHdCtx, this);
47477 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
47478 this.dd = new Roo.grid.GridDragZone(this.grid, {
47479 ddGroup : this.grid.ddGroup || 'GridDD'
47484 for(var i = 0; i < colCount; i++){
47485 if(cm.isHidden(i)){
47486 this.hideColumn(i);
47488 if(cm.config[i].align){
47489 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
47490 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
47494 this.updateHeaderSortState();
47496 this.beforeInitialResize();
47499 // two part rendering gives faster view to the user
47500 this.renderPhase2.defer(1, this);
47503 renderPhase2 : function(){
47504 // render the rows now
47506 if(this.grid.autoSizeColumns){
47507 this.autoSizeColumns();
47511 beforeInitialResize : function(){
47515 onColumnSplitterMoved : function(i, w){
47516 this.userResized = true;
47517 var cm = this.grid.colModel;
47518 cm.setColumnWidth(i, w, true);
47519 var cid = cm.getColumnId(i);
47520 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47521 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
47522 this.updateSplitters();
47524 this.grid.fireEvent("columnresize", i, w);
47527 syncRowHeights : function(startIndex, endIndex){
47528 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
47529 startIndex = startIndex || 0;
47530 var mrows = this.getBodyTable().rows;
47531 var lrows = this.getLockedTable().rows;
47532 var len = mrows.length-1;
47533 endIndex = Math.min(endIndex || len, len);
47534 for(var i = startIndex; i <= endIndex; i++){
47535 var m = mrows[i], l = lrows[i];
47536 var h = Math.max(m.offsetHeight, l.offsetHeight);
47537 m.style.height = l.style.height = h + "px";
47542 layout : function(initialRender, is2ndPass){
47544 var auto = g.autoHeight;
47545 var scrollOffset = 16;
47546 var c = g.getGridEl(), cm = this.cm,
47547 expandCol = g.autoExpandColumn,
47549 //c.beginMeasure();
47551 if(!c.dom.offsetWidth){ // display:none?
47553 this.lockedWrap.show();
47554 this.mainWrap.show();
47559 var hasLock = this.cm.isLocked(0);
47561 var tbh = this.headerPanel.getHeight();
47562 var bbh = this.footerPanel.getHeight();
47565 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
47566 var newHeight = ch + c.getBorderWidth("tb");
47568 newHeight = Math.min(g.maxHeight, newHeight);
47570 c.setHeight(newHeight);
47574 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
47577 var s = this.scroller;
47579 var csize = c.getSize(true);
47581 this.el.setSize(csize.width, csize.height);
47583 this.headerPanel.setWidth(csize.width);
47584 this.footerPanel.setWidth(csize.width);
47586 var hdHeight = this.mainHd.getHeight();
47587 var vw = csize.width;
47588 var vh = csize.height - (tbh + bbh);
47592 var bt = this.getBodyTable();
47593 var ltWidth = hasLock ?
47594 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
47596 var scrollHeight = bt.offsetHeight;
47597 var scrollWidth = ltWidth + bt.offsetWidth;
47598 var vscroll = false, hscroll = false;
47600 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
47602 var lw = this.lockedWrap, mw = this.mainWrap;
47603 var lb = this.lockedBody, mb = this.mainBody;
47605 setTimeout(function(){
47606 var t = s.dom.offsetTop;
47607 var w = s.dom.clientWidth,
47608 h = s.dom.clientHeight;
47611 lw.setSize(ltWidth, h);
47613 mw.setLeftTop(ltWidth, t);
47614 mw.setSize(w-ltWidth, h);
47616 lb.setHeight(h-hdHeight);
47617 mb.setHeight(h-hdHeight);
47619 if(is2ndPass !== true && !gv.userResized && expandCol){
47620 // high speed resize without full column calculation
47622 var ci = cm.getIndexById(expandCol);
47624 ci = cm.findColumnIndex(expandCol);
47626 ci = Math.max(0, ci); // make sure it's got at least the first col.
47627 var expandId = cm.getColumnId(ci);
47628 var tw = cm.getTotalWidth(false);
47629 var currentWidth = cm.getColumnWidth(ci);
47630 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
47631 if(currentWidth != cw){
47632 cm.setColumnWidth(ci, cw, true);
47633 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47634 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
47635 gv.updateSplitters();
47636 gv.layout(false, true);
47648 onWindowResize : function(){
47649 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
47655 appendFooter : function(parentEl){
47659 sortAscText : "Sort Ascending",
47660 sortDescText : "Sort Descending",
47661 lockText : "Lock Column",
47662 unlockText : "Unlock Column",
47663 columnsText : "Columns"
47667 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
47668 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
47669 this.proxy.el.addClass('x-grid3-col-dd');
47672 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
47673 handleMouseDown : function(e){
47677 callHandleMouseDown : function(e){
47678 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
47683 * Ext JS Library 1.1.1
47684 * Copyright(c) 2006-2007, Ext JS, LLC.
47686 * Originally Released Under LGPL - original licence link has changed is not relivant.
47689 * <script type="text/javascript">
47693 // This is a support class used internally by the Grid components
47694 Roo.grid.SplitDragZone = function(grid, hd, hd2){
47696 this.view = grid.getView();
47697 this.proxy = this.view.resizeProxy;
47698 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
47699 "gridSplitters" + this.grid.getGridEl().id, {
47700 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
47702 this.setHandleElId(Roo.id(hd));
47703 this.setOuterHandleElId(Roo.id(hd2));
47704 this.scroll = false;
47706 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
47707 fly: Roo.Element.fly,
47709 b4StartDrag : function(x, y){
47710 this.view.headersDisabled = true;
47711 this.proxy.setHeight(this.view.mainWrap.getHeight());
47712 var w = this.cm.getColumnWidth(this.cellIndex);
47713 var minw = Math.max(w-this.grid.minColumnWidth, 0);
47714 this.resetConstraints();
47715 this.setXConstraint(minw, 1000);
47716 this.setYConstraint(0, 0);
47717 this.minX = x - minw;
47718 this.maxX = x + 1000;
47720 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
47724 handleMouseDown : function(e){
47725 ev = Roo.EventObject.setEvent(e);
47726 var t = this.fly(ev.getTarget());
47727 if(t.hasClass("x-grid-split")){
47728 this.cellIndex = this.view.getCellIndex(t.dom);
47729 this.split = t.dom;
47730 this.cm = this.grid.colModel;
47731 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
47732 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
47737 endDrag : function(e){
47738 this.view.headersDisabled = false;
47739 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
47740 var diff = endX - this.startPos;
47741 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
47744 autoOffset : function(){
47745 this.setDelta(0,0);
47749 * Ext JS Library 1.1.1
47750 * Copyright(c) 2006-2007, Ext JS, LLC.
47752 * Originally Released Under LGPL - original licence link has changed is not relivant.
47755 * <script type="text/javascript">
47759 // This is a support class used internally by the Grid components
47760 Roo.grid.GridDragZone = function(grid, config){
47761 this.view = grid.getView();
47762 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
47763 if(this.view.lockedBody){
47764 this.setHandleElId(Roo.id(this.view.mainBody.dom));
47765 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
47767 this.scroll = false;
47769 this.ddel = document.createElement('div');
47770 this.ddel.className = 'x-grid-dd-wrap';
47773 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
47774 ddGroup : "GridDD",
47776 getDragData : function(e){
47777 var t = Roo.lib.Event.getTarget(e);
47778 var rowIndex = this.view.findRowIndex(t);
47779 if(rowIndex !== false){
47780 var sm = this.grid.selModel;
47781 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
47782 // sm.mouseDown(e, t);
47784 if (e.hasModifier()){
47785 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
47787 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
47792 onInitDrag : function(e){
47793 var data = this.dragData;
47794 this.ddel.innerHTML = this.grid.getDragDropText();
47795 this.proxy.update(this.ddel);
47796 // fire start drag?
47799 afterRepair : function(){
47800 this.dragging = false;
47803 getRepairXY : function(e, data){
47807 onEndDrag : function(data, e){
47811 onValidDrop : function(dd, e, id){
47816 beforeInvalidDrop : function(e, id){
47821 * Ext JS Library 1.1.1
47822 * Copyright(c) 2006-2007, Ext JS, LLC.
47824 * Originally Released Under LGPL - original licence link has changed is not relivant.
47827 * <script type="text/javascript">
47832 * @class Roo.grid.ColumnModel
47833 * @extends Roo.util.Observable
47834 * This is the default implementation of a ColumnModel used by the Grid. It defines
47835 * the columns in the grid.
47838 var colModel = new Roo.grid.ColumnModel([
47839 {header: "Ticker", width: 60, sortable: true, locked: true},
47840 {header: "Company Name", width: 150, sortable: true},
47841 {header: "Market Cap.", width: 100, sortable: true},
47842 {header: "$ Sales", width: 100, sortable: true, renderer: money},
47843 {header: "Employees", width: 100, sortable: true, resizable: false}
47848 * The config options listed for this class are options which may appear in each
47849 * individual column definition.
47850 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
47852 * @param {Object} config An Array of column config objects. See this class's
47853 * config objects for details.
47855 Roo.grid.ColumnModel = function(config){
47857 * The config passed into the constructor
47859 this.config = config;
47862 // if no id, create one
47863 // if the column does not have a dataIndex mapping,
47864 // map it to the order it is in the config
47865 for(var i = 0, len = config.length; i < len; i++){
47867 if(typeof c.dataIndex == "undefined"){
47870 if(typeof c.renderer == "string"){
47871 c.renderer = Roo.util.Format[c.renderer];
47873 if(typeof c.id == "undefined"){
47876 if(c.editor && c.editor.xtype){
47877 c.editor = Roo.factory(c.editor, Roo.grid);
47879 if(c.editor && c.editor.isFormField){
47880 c.editor = new Roo.grid.GridEditor(c.editor);
47882 this.lookup[c.id] = c;
47886 * The width of columns which have no width specified (defaults to 100)
47889 this.defaultWidth = 100;
47892 * Default sortable of columns which have no sortable specified (defaults to false)
47895 this.defaultSortable = false;
47899 * @event widthchange
47900 * Fires when the width of a column changes.
47901 * @param {ColumnModel} this
47902 * @param {Number} columnIndex The column index
47903 * @param {Number} newWidth The new width
47905 "widthchange": true,
47907 * @event headerchange
47908 * Fires when the text of a header changes.
47909 * @param {ColumnModel} this
47910 * @param {Number} columnIndex The column index
47911 * @param {Number} newText The new header text
47913 "headerchange": true,
47915 * @event hiddenchange
47916 * Fires when a column is hidden or "unhidden".
47917 * @param {ColumnModel} this
47918 * @param {Number} columnIndex The column index
47919 * @param {Boolean} hidden true if hidden, false otherwise
47921 "hiddenchange": true,
47923 * @event columnmoved
47924 * Fires when a column is moved.
47925 * @param {ColumnModel} this
47926 * @param {Number} oldIndex
47927 * @param {Number} newIndex
47929 "columnmoved" : true,
47931 * @event columlockchange
47932 * Fires when a column's locked state is changed
47933 * @param {ColumnModel} this
47934 * @param {Number} colIndex
47935 * @param {Boolean} locked true if locked
47937 "columnlockchange" : true
47939 Roo.grid.ColumnModel.superclass.constructor.call(this);
47941 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
47943 * @cfg {String} header The header text to display in the Grid view.
47946 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
47947 * {@link Roo.data.Record} definition from which to draw the column's value. If not
47948 * specified, the column's index is used as an index into the Record's data Array.
47951 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
47952 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
47955 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
47956 * Defaults to the value of the {@link #defaultSortable} property.
47957 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
47960 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
47963 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
47966 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
47969 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
47972 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
47973 * given the cell's data value. See {@link #setRenderer}. If not specified, the
47974 * default renderer uses the raw data value.
47977 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
47980 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
47984 * Returns the id of the column at the specified index.
47985 * @param {Number} index The column index
47986 * @return {String} the id
47988 getColumnId : function(index){
47989 return this.config[index].id;
47993 * Returns the column for a specified id.
47994 * @param {String} id The column id
47995 * @return {Object} the column
47997 getColumnById : function(id){
47998 return this.lookup[id];
48002 * Returns the index for a specified column id.
48003 * @param {String} id The column id
48004 * @return {Number} the index, or -1 if not found
48006 getIndexById : function(id){
48007 for(var i = 0, len = this.config.length; i < len; i++){
48008 if(this.config[i].id == id){
48015 * Returns the index for a specified column dataIndex.
48016 * @param {String} dataIndex The column dataIndex
48017 * @return {Number} the index, or -1 if not found
48020 findColumnIndex : function(dataIndex){
48021 for(var i = 0, len = this.config.length; i < len; i++){
48022 if(this.config[i].dataIndex == dataIndex){
48030 moveColumn : function(oldIndex, newIndex){
48031 var c = this.config[oldIndex];
48032 this.config.splice(oldIndex, 1);
48033 this.config.splice(newIndex, 0, c);
48034 this.dataMap = null;
48035 this.fireEvent("columnmoved", this, oldIndex, newIndex);
48038 isLocked : function(colIndex){
48039 return this.config[colIndex].locked === true;
48042 setLocked : function(colIndex, value, suppressEvent){
48043 if(this.isLocked(colIndex) == value){
48046 this.config[colIndex].locked = value;
48047 if(!suppressEvent){
48048 this.fireEvent("columnlockchange", this, colIndex, value);
48052 getTotalLockedWidth : function(){
48053 var totalWidth = 0;
48054 for(var i = 0; i < this.config.length; i++){
48055 if(this.isLocked(i) && !this.isHidden(i)){
48056 this.totalWidth += this.getColumnWidth(i);
48062 getLockedCount : function(){
48063 for(var i = 0, len = this.config.length; i < len; i++){
48064 if(!this.isLocked(i)){
48071 * Returns the number of columns.
48074 getColumnCount : function(visibleOnly){
48075 if(visibleOnly === true){
48077 for(var i = 0, len = this.config.length; i < len; i++){
48078 if(!this.isHidden(i)){
48084 return this.config.length;
48088 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
48089 * @param {Function} fn
48090 * @param {Object} scope (optional)
48091 * @return {Array} result
48093 getColumnsBy : function(fn, scope){
48095 for(var i = 0, len = this.config.length; i < len; i++){
48096 var c = this.config[i];
48097 if(fn.call(scope||this, c, i) === true){
48105 * Returns true if the specified column is sortable.
48106 * @param {Number} col The column index
48107 * @return {Boolean}
48109 isSortable : function(col){
48110 if(typeof this.config[col].sortable == "undefined"){
48111 return this.defaultSortable;
48113 return this.config[col].sortable;
48117 * Returns the rendering (formatting) function defined for the column.
48118 * @param {Number} col The column index.
48119 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
48121 getRenderer : function(col){
48122 if(!this.config[col].renderer){
48123 return Roo.grid.ColumnModel.defaultRenderer;
48125 return this.config[col].renderer;
48129 * Sets the rendering (formatting) function for a column.
48130 * @param {Number} col The column index
48131 * @param {Function} fn The function to use to process the cell's raw data
48132 * to return HTML markup for the grid view. The render function is called with
48133 * the following parameters:<ul>
48134 * <li>Data value.</li>
48135 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
48136 * <li>css A CSS style string to apply to the table cell.</li>
48137 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
48138 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
48139 * <li>Row index</li>
48140 * <li>Column index</li>
48141 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
48143 setRenderer : function(col, fn){
48144 this.config[col].renderer = fn;
48148 * Returns the width for the specified column.
48149 * @param {Number} col The column index
48152 getColumnWidth : function(col){
48153 return this.config[col].width || this.defaultWidth;
48157 * Sets the width for a column.
48158 * @param {Number} col The column index
48159 * @param {Number} width The new width
48161 setColumnWidth : function(col, width, suppressEvent){
48162 this.config[col].width = width;
48163 this.totalWidth = null;
48164 if(!suppressEvent){
48165 this.fireEvent("widthchange", this, col, width);
48170 * Returns the total width of all columns.
48171 * @param {Boolean} includeHidden True to include hidden column widths
48174 getTotalWidth : function(includeHidden){
48175 if(!this.totalWidth){
48176 this.totalWidth = 0;
48177 for(var i = 0, len = this.config.length; i < len; i++){
48178 if(includeHidden || !this.isHidden(i)){
48179 this.totalWidth += this.getColumnWidth(i);
48183 return this.totalWidth;
48187 * Returns the header for the specified column.
48188 * @param {Number} col The column index
48191 getColumnHeader : function(col){
48192 return this.config[col].header;
48196 * Sets the header for a column.
48197 * @param {Number} col The column index
48198 * @param {String} header The new header
48200 setColumnHeader : function(col, header){
48201 this.config[col].header = header;
48202 this.fireEvent("headerchange", this, col, header);
48206 * Returns the tooltip for the specified column.
48207 * @param {Number} col The column index
48210 getColumnTooltip : function(col){
48211 return this.config[col].tooltip;
48214 * Sets the tooltip for a column.
48215 * @param {Number} col The column index
48216 * @param {String} tooltip The new tooltip
48218 setColumnTooltip : function(col, tooltip){
48219 this.config[col].tooltip = tooltip;
48223 * Returns the dataIndex for the specified column.
48224 * @param {Number} col The column index
48227 getDataIndex : function(col){
48228 return this.config[col].dataIndex;
48232 * Sets the dataIndex for a column.
48233 * @param {Number} col The column index
48234 * @param {Number} dataIndex The new dataIndex
48236 setDataIndex : function(col, dataIndex){
48237 this.config[col].dataIndex = dataIndex;
48243 * Returns true if the cell is editable.
48244 * @param {Number} colIndex The column index
48245 * @param {Number} rowIndex The row index
48246 * @return {Boolean}
48248 isCellEditable : function(colIndex, rowIndex){
48249 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
48253 * Returns the editor defined for the cell/column.
48254 * return false or null to disable editing.
48255 * @param {Number} colIndex The column index
48256 * @param {Number} rowIndex The row index
48259 getCellEditor : function(colIndex, rowIndex){
48260 return this.config[colIndex].editor;
48264 * Sets if a column is editable.
48265 * @param {Number} col The column index
48266 * @param {Boolean} editable True if the column is editable
48268 setEditable : function(col, editable){
48269 this.config[col].editable = editable;
48274 * Returns true if the column is hidden.
48275 * @param {Number} colIndex The column index
48276 * @return {Boolean}
48278 isHidden : function(colIndex){
48279 return this.config[colIndex].hidden;
48284 * Returns true if the column width cannot be changed
48286 isFixed : function(colIndex){
48287 return this.config[colIndex].fixed;
48291 * Returns true if the column can be resized
48292 * @return {Boolean}
48294 isResizable : function(colIndex){
48295 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
48298 * Sets if a column is hidden.
48299 * @param {Number} colIndex The column index
48300 * @param {Boolean} hidden True if the column is hidden
48302 setHidden : function(colIndex, hidden){
48303 this.config[colIndex].hidden = hidden;
48304 this.totalWidth = null;
48305 this.fireEvent("hiddenchange", this, colIndex, hidden);
48309 * Sets the editor for a column.
48310 * @param {Number} col The column index
48311 * @param {Object} editor The editor object
48313 setEditor : function(col, editor){
48314 this.config[col].editor = editor;
48318 Roo.grid.ColumnModel.defaultRenderer = function(value){
48319 if(typeof value == "string" && value.length < 1){
48325 // Alias for backwards compatibility
48326 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
48329 * Ext JS Library 1.1.1
48330 * Copyright(c) 2006-2007, Ext JS, LLC.
48332 * Originally Released Under LGPL - original licence link has changed is not relivant.
48335 * <script type="text/javascript">
48339 * @class Roo.grid.AbstractSelectionModel
48340 * @extends Roo.util.Observable
48341 * Abstract base class for grid SelectionModels. It provides the interface that should be
48342 * implemented by descendant classes. This class should not be directly instantiated.
48345 Roo.grid.AbstractSelectionModel = function(){
48346 this.locked = false;
48347 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
48350 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
48351 /** @ignore Called by the grid automatically. Do not call directly. */
48352 init : function(grid){
48358 * Locks the selections.
48361 this.locked = true;
48365 * Unlocks the selections.
48367 unlock : function(){
48368 this.locked = false;
48372 * Returns true if the selections are locked.
48373 * @return {Boolean}
48375 isLocked : function(){
48376 return this.locked;
48380 * Ext JS Library 1.1.1
48381 * Copyright(c) 2006-2007, Ext JS, LLC.
48383 * Originally Released Under LGPL - original licence link has changed is not relivant.
48386 * <script type="text/javascript">
48389 * @extends Roo.grid.AbstractSelectionModel
48390 * @class Roo.grid.RowSelectionModel
48391 * The default SelectionModel used by {@link Roo.grid.Grid}.
48392 * It supports multiple selections and keyboard selection/navigation.
48394 * @param {Object} config
48396 Roo.grid.RowSelectionModel = function(config){
48397 Roo.apply(this, config);
48398 this.selections = new Roo.util.MixedCollection(false, function(o){
48403 this.lastActive = false;
48407 * @event selectionchange
48408 * Fires when the selection changes
48409 * @param {SelectionModel} this
48411 "selectionchange" : true,
48413 * @event afterselectionchange
48414 * Fires after the selection changes (eg. by key press or clicking)
48415 * @param {SelectionModel} this
48417 "afterselectionchange" : true,
48419 * @event beforerowselect
48420 * Fires when a row is selected being selected, return false to cancel.
48421 * @param {SelectionModel} this
48422 * @param {Number} rowIndex The selected index
48423 * @param {Boolean} keepExisting False if other selections will be cleared
48425 "beforerowselect" : true,
48428 * Fires when a row is selected.
48429 * @param {SelectionModel} this
48430 * @param {Number} rowIndex The selected index
48431 * @param {Roo.data.Record} r The record
48433 "rowselect" : true,
48435 * @event rowdeselect
48436 * Fires when a row is deselected.
48437 * @param {SelectionModel} this
48438 * @param {Number} rowIndex The selected index
48440 "rowdeselect" : true
48442 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
48443 this.locked = false;
48446 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
48448 * @cfg {Boolean} singleSelect
48449 * True to allow selection of only one row at a time (defaults to false)
48451 singleSelect : false,
48454 initEvents : function(){
48456 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
48457 this.grid.on("mousedown", this.handleMouseDown, this);
48458 }else{ // allow click to work like normal
48459 this.grid.on("rowclick", this.handleDragableRowClick, this);
48462 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
48463 "up" : function(e){
48465 this.selectPrevious(e.shiftKey);
48466 }else if(this.last !== false && this.lastActive !== false){
48467 var last = this.last;
48468 this.selectRange(this.last, this.lastActive-1);
48469 this.grid.getView().focusRow(this.lastActive);
48470 if(last !== false){
48474 this.selectFirstRow();
48476 this.fireEvent("afterselectionchange", this);
48478 "down" : function(e){
48480 this.selectNext(e.shiftKey);
48481 }else if(this.last !== false && this.lastActive !== false){
48482 var last = this.last;
48483 this.selectRange(this.last, this.lastActive+1);
48484 this.grid.getView().focusRow(this.lastActive);
48485 if(last !== false){
48489 this.selectFirstRow();
48491 this.fireEvent("afterselectionchange", this);
48496 var view = this.grid.view;
48497 view.on("refresh", this.onRefresh, this);
48498 view.on("rowupdated", this.onRowUpdated, this);
48499 view.on("rowremoved", this.onRemove, this);
48503 onRefresh : function(){
48504 var ds = this.grid.dataSource, i, v = this.grid.view;
48505 var s = this.selections;
48506 s.each(function(r){
48507 if((i = ds.indexOfId(r.id)) != -1){
48516 onRemove : function(v, index, r){
48517 this.selections.remove(r);
48521 onRowUpdated : function(v, index, r){
48522 if(this.isSelected(r)){
48523 v.onRowSelect(index);
48529 * @param {Array} records The records to select
48530 * @param {Boolean} keepExisting (optional) True to keep existing selections
48532 selectRecords : function(records, keepExisting){
48534 this.clearSelections();
48536 var ds = this.grid.dataSource;
48537 for(var i = 0, len = records.length; i < len; i++){
48538 this.selectRow(ds.indexOf(records[i]), true);
48543 * Gets the number of selected rows.
48546 getCount : function(){
48547 return this.selections.length;
48551 * Selects the first row in the grid.
48553 selectFirstRow : function(){
48558 * Select the last row.
48559 * @param {Boolean} keepExisting (optional) True to keep existing selections
48561 selectLastRow : function(keepExisting){
48562 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
48566 * Selects the row immediately following the last selected row.
48567 * @param {Boolean} keepExisting (optional) True to keep existing selections
48569 selectNext : function(keepExisting){
48570 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
48571 this.selectRow(this.last+1, keepExisting);
48572 this.grid.getView().focusRow(this.last);
48577 * Selects the row that precedes the last selected row.
48578 * @param {Boolean} keepExisting (optional) True to keep existing selections
48580 selectPrevious : function(keepExisting){
48582 this.selectRow(this.last-1, keepExisting);
48583 this.grid.getView().focusRow(this.last);
48588 * Returns the selected records
48589 * @return {Array} Array of selected records
48591 getSelections : function(){
48592 return [].concat(this.selections.items);
48596 * Returns the first selected record.
48599 getSelected : function(){
48600 return this.selections.itemAt(0);
48605 * Clears all selections.
48607 clearSelections : function(fast){
48608 if(this.locked) return;
48610 var ds = this.grid.dataSource;
48611 var s = this.selections;
48612 s.each(function(r){
48613 this.deselectRow(ds.indexOfId(r.id));
48617 this.selections.clear();
48624 * Selects all rows.
48626 selectAll : function(){
48627 if(this.locked) return;
48628 this.selections.clear();
48629 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
48630 this.selectRow(i, true);
48635 * Returns True if there is a selection.
48636 * @return {Boolean}
48638 hasSelection : function(){
48639 return this.selections.length > 0;
48643 * Returns True if the specified row is selected.
48644 * @param {Number/Record} record The record or index of the record to check
48645 * @return {Boolean}
48647 isSelected : function(index){
48648 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
48649 return (r && this.selections.key(r.id) ? true : false);
48653 * Returns True if the specified record id is selected.
48654 * @param {String} id The id of record to check
48655 * @return {Boolean}
48657 isIdSelected : function(id){
48658 return (this.selections.key(id) ? true : false);
48662 handleMouseDown : function(e, t){
48663 var view = this.grid.getView(), rowIndex;
48664 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
48667 if(e.shiftKey && this.last !== false){
48668 var last = this.last;
48669 this.selectRange(last, rowIndex, e.ctrlKey);
48670 this.last = last; // reset the last
48671 view.focusRow(rowIndex);
48673 var isSelected = this.isSelected(rowIndex);
48674 if(e.button !== 0 && isSelected){
48675 view.focusRow(rowIndex);
48676 }else if(e.ctrlKey && isSelected){
48677 this.deselectRow(rowIndex);
48678 }else if(!isSelected){
48679 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
48680 view.focusRow(rowIndex);
48683 this.fireEvent("afterselectionchange", this);
48686 handleDragableRowClick : function(grid, rowIndex, e)
48688 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
48689 this.selectRow(rowIndex, false);
48690 grid.view.focusRow(rowIndex);
48691 this.fireEvent("afterselectionchange", this);
48696 * Selects multiple rows.
48697 * @param {Array} rows Array of the indexes of the row to select
48698 * @param {Boolean} keepExisting (optional) True to keep existing selections
48700 selectRows : function(rows, keepExisting){
48702 this.clearSelections();
48704 for(var i = 0, len = rows.length; i < len; i++){
48705 this.selectRow(rows[i], true);
48710 * Selects a range of rows. All rows in between startRow and endRow are also selected.
48711 * @param {Number} startRow The index of the first row in the range
48712 * @param {Number} endRow The index of the last row in the range
48713 * @param {Boolean} keepExisting (optional) True to retain existing selections
48715 selectRange : function(startRow, endRow, keepExisting){
48716 if(this.locked) return;
48718 this.clearSelections();
48720 if(startRow <= endRow){
48721 for(var i = startRow; i <= endRow; i++){
48722 this.selectRow(i, true);
48725 for(var i = startRow; i >= endRow; i--){
48726 this.selectRow(i, true);
48732 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
48733 * @param {Number} startRow The index of the first row in the range
48734 * @param {Number} endRow The index of the last row in the range
48736 deselectRange : function(startRow, endRow, preventViewNotify){
48737 if(this.locked) return;
48738 for(var i = startRow; i <= endRow; i++){
48739 this.deselectRow(i, preventViewNotify);
48745 * @param {Number} row The index of the row to select
48746 * @param {Boolean} keepExisting (optional) True to keep existing selections
48748 selectRow : function(index, keepExisting, preventViewNotify){
48749 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
48750 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
48751 if(!keepExisting || this.singleSelect){
48752 this.clearSelections();
48754 var r = this.grid.dataSource.getAt(index);
48755 this.selections.add(r);
48756 this.last = this.lastActive = index;
48757 if(!preventViewNotify){
48758 this.grid.getView().onRowSelect(index);
48760 this.fireEvent("rowselect", this, index, r);
48761 this.fireEvent("selectionchange", this);
48767 * @param {Number} row The index of the row to deselect
48769 deselectRow : function(index, preventViewNotify){
48770 if(this.locked) return;
48771 if(this.last == index){
48774 if(this.lastActive == index){
48775 this.lastActive = false;
48777 var r = this.grid.dataSource.getAt(index);
48778 this.selections.remove(r);
48779 if(!preventViewNotify){
48780 this.grid.getView().onRowDeselect(index);
48782 this.fireEvent("rowdeselect", this, index);
48783 this.fireEvent("selectionchange", this);
48787 restoreLast : function(){
48789 this.last = this._last;
48794 acceptsNav : function(row, col, cm){
48795 return !cm.isHidden(col) && cm.isCellEditable(col, row);
48799 onEditorKey : function(field, e){
48800 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
48805 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
48807 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
48809 }else if(k == e.ENTER && !e.ctrlKey){
48813 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
48815 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
48817 }else if(k == e.ESC){
48821 g.startEditing(newCell[0], newCell[1]);
48826 * Ext JS Library 1.1.1
48827 * Copyright(c) 2006-2007, Ext JS, LLC.
48829 * Originally Released Under LGPL - original licence link has changed is not relivant.
48832 * <script type="text/javascript">
48835 * @class Roo.grid.CellSelectionModel
48836 * @extends Roo.grid.AbstractSelectionModel
48837 * This class provides the basic implementation for cell selection in a grid.
48839 * @param {Object} config The object containing the configuration of this model.
48841 Roo.grid.CellSelectionModel = function(config){
48842 Roo.apply(this, config);
48844 this.selection = null;
48848 * @event beforerowselect
48849 * Fires before a cell is selected.
48850 * @param {SelectionModel} this
48851 * @param {Number} rowIndex The selected row index
48852 * @param {Number} colIndex The selected cell index
48854 "beforecellselect" : true,
48856 * @event cellselect
48857 * Fires when a cell is selected.
48858 * @param {SelectionModel} this
48859 * @param {Number} rowIndex The selected row index
48860 * @param {Number} colIndex The selected cell index
48862 "cellselect" : true,
48864 * @event selectionchange
48865 * Fires when the active selection changes.
48866 * @param {SelectionModel} this
48867 * @param {Object} selection null for no selection or an object (o) with two properties
48869 <li>o.record: the record object for the row the selection is in</li>
48870 <li>o.cell: An array of [rowIndex, columnIndex]</li>
48873 "selectionchange" : true
48875 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
48878 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
48881 initEvents : function(){
48882 this.grid.on("mousedown", this.handleMouseDown, this);
48883 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
48884 var view = this.grid.view;
48885 view.on("refresh", this.onViewChange, this);
48886 view.on("rowupdated", this.onRowUpdated, this);
48887 view.on("beforerowremoved", this.clearSelections, this);
48888 view.on("beforerowsinserted", this.clearSelections, this);
48889 if(this.grid.isEditor){
48890 this.grid.on("beforeedit", this.beforeEdit, this);
48895 beforeEdit : function(e){
48896 this.select(e.row, e.column, false, true, e.record);
48900 onRowUpdated : function(v, index, r){
48901 if(this.selection && this.selection.record == r){
48902 v.onCellSelect(index, this.selection.cell[1]);
48907 onViewChange : function(){
48908 this.clearSelections(true);
48912 * Returns the currently selected cell,.
48913 * @return {Array} The selected cell (row, column) or null if none selected.
48915 getSelectedCell : function(){
48916 return this.selection ? this.selection.cell : null;
48920 * Clears all selections.
48921 * @param {Boolean} true to prevent the gridview from being notified about the change.
48923 clearSelections : function(preventNotify){
48924 var s = this.selection;
48926 if(preventNotify !== true){
48927 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
48929 this.selection = null;
48930 this.fireEvent("selectionchange", this, null);
48935 * Returns true if there is a selection.
48936 * @return {Boolean}
48938 hasSelection : function(){
48939 return this.selection ? true : false;
48943 handleMouseDown : function(e, t){
48944 var v = this.grid.getView();
48945 if(this.isLocked()){
48948 var row = v.findRowIndex(t);
48949 var cell = v.findCellIndex(t);
48950 if(row !== false && cell !== false){
48951 this.select(row, cell);
48957 * @param {Number} rowIndex
48958 * @param {Number} collIndex
48960 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
48961 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
48962 this.clearSelections();
48963 r = r || this.grid.dataSource.getAt(rowIndex);
48966 cell : [rowIndex, colIndex]
48968 if(!preventViewNotify){
48969 var v = this.grid.getView();
48970 v.onCellSelect(rowIndex, colIndex);
48971 if(preventFocus !== true){
48972 v.focusCell(rowIndex, colIndex);
48975 this.fireEvent("cellselect", this, rowIndex, colIndex);
48976 this.fireEvent("selectionchange", this, this.selection);
48981 isSelectable : function(rowIndex, colIndex, cm){
48982 return !cm.isHidden(colIndex);
48986 handleKeyDown : function(e){
48987 if(!e.isNavKeyPress()){
48990 var g = this.grid, s = this.selection;
48993 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
48995 this.select(cell[0], cell[1]);
49000 var walk = function(row, col, step){
49001 return g.walkCells(row, col, step, sm.isSelectable, sm);
49003 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
49009 newCell = walk(r, c-1, -1);
49011 newCell = walk(r, c+1, 1);
49015 newCell = walk(r+1, c, 1);
49018 newCell = walk(r-1, c, -1);
49021 newCell = walk(r, c+1, 1);
49024 newCell = walk(r, c-1, -1);
49027 if(g.isEditor && !g.editing){
49028 g.startEditing(r, c);
49035 this.select(newCell[0], newCell[1]);
49040 acceptsNav : function(row, col, cm){
49041 return !cm.isHidden(col) && cm.isCellEditable(col, row);
49044 onEditorKey : function(field, e){
49045 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
49048 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
49050 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
49053 }else if(k == e.ENTER && !e.ctrlKey){
49056 }else if(k == e.ESC){
49060 g.startEditing(newCell[0], newCell[1]);
49065 * Ext JS Library 1.1.1
49066 * Copyright(c) 2006-2007, Ext JS, LLC.
49068 * Originally Released Under LGPL - original licence link has changed is not relivant.
49071 * <script type="text/javascript">
49075 * @class Roo.grid.EditorGrid
49076 * @extends Roo.grid.Grid
49077 * Class for creating and editable grid.
49078 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49079 * The container MUST have some type of size defined for the grid to fill. The container will be
49080 * automatically set to position relative if it isn't already.
49081 * @param {Object} dataSource The data model to bind to
49082 * @param {Object} colModel The column model with info about this grid's columns
49084 Roo.grid.EditorGrid = function(container, config){
49085 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
49086 this.getGridEl().addClass("xedit-grid");
49088 if(!this.selModel){
49089 this.selModel = new Roo.grid.CellSelectionModel();
49092 this.activeEditor = null;
49096 * @event beforeedit
49097 * Fires before cell editing is triggered. The edit event object has the following properties <br />
49098 * <ul style="padding:5px;padding-left:16px;">
49099 * <li>grid - This grid</li>
49100 * <li>record - The record being edited</li>
49101 * <li>field - The field name being edited</li>
49102 * <li>value - The value for the field being edited.</li>
49103 * <li>row - The grid row index</li>
49104 * <li>column - The grid column index</li>
49105 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
49107 * @param {Object} e An edit event (see above for description)
49109 "beforeedit" : true,
49112 * Fires after a cell is edited. <br />
49113 * <ul style="padding:5px;padding-left:16px;">
49114 * <li>grid - This grid</li>
49115 * <li>record - The record being edited</li>
49116 * <li>field - The field name being edited</li>
49117 * <li>value - The value being set</li>
49118 * <li>originalValue - The original value for the field, before the edit.</li>
49119 * <li>row - The grid row index</li>
49120 * <li>column - The grid column index</li>
49122 * @param {Object} e An edit event (see above for description)
49124 "afteredit" : true,
49126 * @event validateedit
49127 * Fires after a cell is edited, but before the value is set in the record.
49128 * You can use this to modify the value being set in the field, Return false
49129 * to cancel the change. The edit event object has the following properties <br />
49130 * <ul style="padding:5px;padding-left:16px;">
49131 * <li>editor - This editor</li>
49132 * <li>grid - This grid</li>
49133 * <li>record - The record being edited</li>
49134 * <li>field - The field name being edited</li>
49135 * <li>value - The value being set</li>
49136 * <li>originalValue - The original value for the field, before the edit.</li>
49137 * <li>row - The grid row index</li>
49138 * <li>column - The grid column index</li>
49139 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
49141 * @param {Object} e An edit event (see above for description)
49143 "validateedit" : true
49145 this.on("bodyscroll", this.stopEditing, this);
49146 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
49149 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
49151 * @cfg {Number} clicksToEdit
49152 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
49159 trackMouseOver: false, // causes very odd FF errors
49161 onCellDblClick : function(g, row, col){
49162 this.startEditing(row, col);
49165 onEditComplete : function(ed, value, startValue){
49166 this.editing = false;
49167 this.activeEditor = null;
49168 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
49170 var field = this.colModel.getDataIndex(ed.col);
49175 originalValue: startValue,
49182 if(String(value) !== String(startValue)){
49184 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
49185 r.set(field, e.value);
49186 delete e.cancel; //?? why!!!
49187 this.fireEvent("afteredit", e);
49190 this.fireEvent("afteredit", e); // always fir it!
49192 this.view.focusCell(ed.row, ed.col);
49196 * Starts editing the specified for the specified row/column
49197 * @param {Number} rowIndex
49198 * @param {Number} colIndex
49200 startEditing : function(row, col){
49201 this.stopEditing();
49202 if(this.colModel.isCellEditable(col, row)){
49203 this.view.ensureVisible(row, col, true);
49204 var r = this.dataSource.getAt(row);
49205 var field = this.colModel.getDataIndex(col);
49210 value: r.data[field],
49215 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
49216 this.editing = true;
49217 var ed = this.colModel.getCellEditor(col, row);
49223 ed.render(ed.parentEl || document.body);
49226 (function(){ // complex but required for focus issues in safari, ie and opera
49230 ed.on("complete", this.onEditComplete, this, {single: true});
49231 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
49232 this.activeEditor = ed;
49233 var v = r.data[field];
49234 ed.startEdit(this.view.getCell(row, col), v);
49235 }).defer(50, this);
49241 * Stops any active editing
49243 stopEditing : function(){
49244 if(this.activeEditor){
49245 this.activeEditor.completeEdit();
49247 this.activeEditor = null;
49251 * Ext JS Library 1.1.1
49252 * Copyright(c) 2006-2007, Ext JS, LLC.
49254 * Originally Released Under LGPL - original licence link has changed is not relivant.
49257 * <script type="text/javascript">
49260 // private - not really -- you end up using it !
49261 // This is a support class used internally by the Grid components
49264 * @class Roo.grid.GridEditor
49265 * @extends Roo.Editor
49266 * Class for creating and editable grid elements.
49267 * @param {Object} config any settings (must include field)
49269 Roo.grid.GridEditor = function(field, config){
49270 if (!config && field.field) {
49272 field = Roo.factory(config.field, Roo.form);
49274 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
49275 field.monitorTab = false;
49278 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
49281 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
49284 alignment: "tl-tl",
49287 cls: "x-small-editor x-grid-editor",
49292 * Ext JS Library 1.1.1
49293 * Copyright(c) 2006-2007, Ext JS, LLC.
49295 * Originally Released Under LGPL - original licence link has changed is not relivant.
49298 * <script type="text/javascript">
49303 Roo.grid.PropertyRecord = Roo.data.Record.create([
49304 {name:'name',type:'string'}, 'value'
49308 Roo.grid.PropertyStore = function(grid, source){
49310 this.store = new Roo.data.Store({
49311 recordType : Roo.grid.PropertyRecord
49313 this.store.on('update', this.onUpdate, this);
49315 this.setSource(source);
49317 Roo.grid.PropertyStore.superclass.constructor.call(this);
49322 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
49323 setSource : function(o){
49325 this.store.removeAll();
49328 if(this.isEditableValue(o[k])){
49329 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
49332 this.store.loadRecords({records: data}, {}, true);
49335 onUpdate : function(ds, record, type){
49336 if(type == Roo.data.Record.EDIT){
49337 var v = record.data['value'];
49338 var oldValue = record.modified['value'];
49339 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
49340 this.source[record.id] = v;
49342 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
49349 getProperty : function(row){
49350 return this.store.getAt(row);
49353 isEditableValue: function(val){
49354 if(val && val instanceof Date){
49356 }else if(typeof val == 'object' || typeof val == 'function'){
49362 setValue : function(prop, value){
49363 this.source[prop] = value;
49364 this.store.getById(prop).set('value', value);
49367 getSource : function(){
49368 return this.source;
49372 Roo.grid.PropertyColumnModel = function(grid, store){
49375 g.PropertyColumnModel.superclass.constructor.call(this, [
49376 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
49377 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
49379 this.store = store;
49380 this.bselect = Roo.DomHelper.append(document.body, {
49381 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
49382 {tag: 'option', value: 'true', html: 'true'},
49383 {tag: 'option', value: 'false', html: 'false'}
49386 Roo.id(this.bselect);
49389 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
49390 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
49391 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
49392 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
49393 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
49395 this.renderCellDelegate = this.renderCell.createDelegate(this);
49396 this.renderPropDelegate = this.renderProp.createDelegate(this);
49399 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
49403 valueText : 'Value',
49405 dateFormat : 'm/j/Y',
49408 renderDate : function(dateVal){
49409 return dateVal.dateFormat(this.dateFormat);
49412 renderBool : function(bVal){
49413 return bVal ? 'true' : 'false';
49416 isCellEditable : function(colIndex, rowIndex){
49417 return colIndex == 1;
49420 getRenderer : function(col){
49422 this.renderCellDelegate : this.renderPropDelegate;
49425 renderProp : function(v){
49426 return this.getPropertyName(v);
49429 renderCell : function(val){
49431 if(val instanceof Date){
49432 rv = this.renderDate(val);
49433 }else if(typeof val == 'boolean'){
49434 rv = this.renderBool(val);
49436 return Roo.util.Format.htmlEncode(rv);
49439 getPropertyName : function(name){
49440 var pn = this.grid.propertyNames;
49441 return pn && pn[name] ? pn[name] : name;
49444 getCellEditor : function(colIndex, rowIndex){
49445 var p = this.store.getProperty(rowIndex);
49446 var n = p.data['name'], val = p.data['value'];
49448 if(typeof(this.grid.customEditors[n]) == 'string'){
49449 return this.editors[this.grid.customEditors[n]];
49451 if(typeof(this.grid.customEditors[n]) != 'undefined'){
49452 return this.grid.customEditors[n];
49454 if(val instanceof Date){
49455 return this.editors['date'];
49456 }else if(typeof val == 'number'){
49457 return this.editors['number'];
49458 }else if(typeof val == 'boolean'){
49459 return this.editors['boolean'];
49461 return this.editors['string'];
49467 * @class Roo.grid.PropertyGrid
49468 * @extends Roo.grid.EditorGrid
49469 * This class represents the interface of a component based property grid control.
49470 * <br><br>Usage:<pre><code>
49471 var grid = new Roo.grid.PropertyGrid("my-container-id", {
49479 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49480 * The container MUST have some type of size defined for the grid to fill. The container will be
49481 * automatically set to position relative if it isn't already.
49482 * @param {Object} config A config object that sets properties on this grid.
49484 Roo.grid.PropertyGrid = function(container, config){
49485 config = config || {};
49486 var store = new Roo.grid.PropertyStore(this);
49487 this.store = store;
49488 var cm = new Roo.grid.PropertyColumnModel(this, store);
49489 store.store.sort('name', 'ASC');
49490 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
49493 enableColLock:false,
49494 enableColumnMove:false,
49496 trackMouseOver: false,
49499 this.getGridEl().addClass('x-props-grid');
49500 this.lastEditRow = null;
49501 this.on('columnresize', this.onColumnResize, this);
49504 * @event beforepropertychange
49505 * Fires before a property changes (return false to stop?)
49506 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
49507 * @param {String} id Record Id
49508 * @param {String} newval New Value
49509 * @param {String} oldval Old Value
49511 "beforepropertychange": true,
49513 * @event propertychange
49514 * Fires after a property changes
49515 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
49516 * @param {String} id Record Id
49517 * @param {String} newval New Value
49518 * @param {String} oldval Old Value
49520 "propertychange": true
49522 this.customEditors = this.customEditors || {};
49524 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
49527 * @cfg {Object} customEditors map of colnames=> custom editors.
49528 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
49529 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
49530 * false disables editing of the field.
49534 * @cfg {Object} propertyNames map of property Names to their displayed value
49537 render : function(){
49538 Roo.grid.PropertyGrid.superclass.render.call(this);
49539 this.autoSize.defer(100, this);
49542 autoSize : function(){
49543 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
49545 this.view.fitColumns();
49549 onColumnResize : function(){
49550 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
49554 * Sets the data for the Grid
49555 * accepts a Key => Value object of all the elements avaiable.
49556 * @param {Object} data to appear in grid.
49558 setSource : function(source){
49559 this.store.setSource(source);
49563 * Gets all the data from the grid.
49564 * @return {Object} data data stored in grid
49566 getSource : function(){
49567 return this.store.getSource();
49571 * Ext JS Library 1.1.1
49572 * Copyright(c) 2006-2007, Ext JS, LLC.
49574 * Originally Released Under LGPL - original licence link has changed is not relivant.
49577 * <script type="text/javascript">
49581 * @class Roo.LoadMask
49582 * A simple utility class for generically masking elements while loading data. If the element being masked has
49583 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
49584 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
49585 * element's UpdateManager load indicator and will be destroyed after the initial load.
49587 * Create a new LoadMask
49588 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
49589 * @param {Object} config The config object
49591 Roo.LoadMask = function(el, config){
49592 this.el = Roo.get(el);
49593 Roo.apply(this, config);
49595 this.store.on('beforeload', this.onBeforeLoad, this);
49596 this.store.on('load', this.onLoad, this);
49597 this.store.on('loadexception', this.onLoad, this);
49598 this.removeMask = false;
49600 var um = this.el.getUpdateManager();
49601 um.showLoadIndicator = false; // disable the default indicator
49602 um.on('beforeupdate', this.onBeforeLoad, this);
49603 um.on('update', this.onLoad, this);
49604 um.on('failure', this.onLoad, this);
49605 this.removeMask = true;
49609 Roo.LoadMask.prototype = {
49611 * @cfg {Boolean} removeMask
49612 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
49613 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
49616 * @cfg {String} msg
49617 * The text to display in a centered loading message box (defaults to 'Loading...')
49619 msg : 'Loading...',
49621 * @cfg {String} msgCls
49622 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
49624 msgCls : 'x-mask-loading',
49627 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
49633 * Disables the mask to prevent it from being displayed
49635 disable : function(){
49636 this.disabled = true;
49640 * Enables the mask so that it can be displayed
49642 enable : function(){
49643 this.disabled = false;
49647 onLoad : function(){
49648 this.el.unmask(this.removeMask);
49652 onBeforeLoad : function(){
49653 if(!this.disabled){
49654 this.el.mask(this.msg, this.msgCls);
49659 destroy : function(){
49661 this.store.un('beforeload', this.onBeforeLoad, this);
49662 this.store.un('load', this.onLoad, this);
49663 this.store.un('loadexception', this.onLoad, this);
49665 var um = this.el.getUpdateManager();
49666 um.un('beforeupdate', this.onBeforeLoad, this);
49667 um.un('update', this.onLoad, this);
49668 um.un('failure', this.onLoad, this);
49673 * Ext JS Library 1.1.1
49674 * Copyright(c) 2006-2007, Ext JS, LLC.
49676 * Originally Released Under LGPL - original licence link has changed is not relivant.
49679 * <script type="text/javascript">
49681 Roo.XTemplate = function(){
49682 Roo.XTemplate.superclass.constructor.apply(this, arguments);
49685 s = ['<tpl>', s, '</tpl>'].join('');
49687 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
49689 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
49690 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
49691 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
49695 while(m = s.match(re)){
49696 var m2 = m[0].match(nameRe);
49697 var m3 = m[0].match(ifRe);
49698 var m4 = m[0].match(execRe);
49699 var exp = null, fn = null, exec = null;
49700 var name = m2 && m2[1] ? m2[1] : '';
49702 exp = m3 && m3[1] ? m3[1] : null;
49704 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
49708 exp = m4 && m4[1] ? m4[1] : null;
49710 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
49715 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
49716 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
49717 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
49727 s = s.replace(m[0], '{xtpl'+ id + '}');
49730 for(var i = tpls.length-1; i >= 0; --i){
49731 this.compileTpl(tpls[i]);
49733 this.master = tpls[tpls.length-1];
49736 Roo.extend(Roo.XTemplate, Roo.Template, {
49738 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
49740 applySubTemplate : function(id, values, parent){
49741 var t = this.tpls[id];
49742 if(t.test && !t.test.call(this, values, parent)){
49745 if(t.exec && t.exec.call(this, values, parent)){
49748 var vs = t.target ? t.target.call(this, values, parent) : values;
49749 parent = t.target ? values : parent;
49750 if(t.target && vs instanceof Array){
49752 for(var i = 0, len = vs.length; i < len; i++){
49753 buf[buf.length] = t.compiled.call(this, vs[i], parent);
49755 return buf.join('');
49757 return t.compiled.call(this, vs, parent);
49760 compileTpl : function(tpl){
49761 var fm = Roo.util.Format;
49762 var useF = this.disableFormats !== true;
49763 var sep = Roo.isGecko ? "+" : ",";
49764 var fn = function(m, name, format, args){
49765 if(name.substr(0, 4) == 'xtpl'){
49766 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
49769 if(name.indexOf('.') != -1){
49772 v = "values['" + name + "']";
49774 if(format && useF){
49775 args = args ? ',' + args : "";
49776 if(format.substr(0, 5) != "this."){
49777 format = "fm." + format + '(';
49779 format = 'this.call("'+ format.substr(5) + '", ';
49783 args= ''; format = "("+v+" === undefined ? '' : ";
49785 return "'"+ sep + format + v + args + ")"+sep+"'";
49788 // branched to use + in gecko and [].join() in others
49790 body = "tpl.compiled = function(values, parent){ return '" +
49791 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
49794 body = ["tpl.compiled = function(values, parent){ return ['"];
49795 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
49796 body.push("'].join('');};");
49797 body = body.join('');
49799 /** eval:var:zzzzzzz */
49804 applyTemplate : function(values){
49805 return this.master.compiled.call(this, values, {});
49809 apply : function(){
49810 return this.applyTemplate.apply(this, arguments);
49813 compile : function(){return this;}
49816 Roo.XTemplate.from = function(el){
49817 el = Roo.getDom(el);
49818 return new Roo.XTemplate(el.value || el.innerHTML);
49820 * Original code for Roojs - LGPL
49821 * <script type="text/javascript">
49825 * @class Roo.XComponent
49826 * A delayed Element creator...
49828 * Mypart.xyx = new Roo.XComponent({
49830 parent : 'Mypart.xyz', // empty == document.element.!!
49834 disabled : function() {}
49836 tree : function() { // return an tree of xtype declared components
49840 xtype : 'NestedLayoutPanel',
49845 * @extends Roo.util.Observable
49847 * @param cfg {Object} configuration of component
49850 Roo.XComponent = function(cfg) {
49851 Roo.apply(this, cfg);
49855 * Fires when this the componnt is built
49856 * @param {Roo.XComponent} c the component
49860 * @event buildcomplete
49861 * Fires on the top level element when all elements have been built
49862 * @param {Roo.XComponent} c the top level component.
49864 'buildcomplete' : true,
49868 Roo.XComponent.register(this);
49869 this.modules = false;
49870 this.el = false; // where the layout goes..
49874 Roo.extend(Roo.XComponent, Roo.util.Observable, {
49877 * The created element (with Roo.factory())
49878 * @type {Roo.Layout}
49884 * for BC - use el in new code
49885 * @type {Roo.Layout}
49891 * for BC - use el in new code
49892 * @type {Roo.Layout}
49897 * @cfg {Function|boolean} disabled
49898 * If this module is disabled by some rule, return true from the funtion
49903 * @cfg {String} parent
49904 * Name of parent element which it get xtype added to..
49909 * @cfg {String} order
49910 * Used to set the order in which elements are created (usefull for multiple tabs)
49915 * @cfg {String} name
49916 * String to display while loading.
49920 * @cfg {Array} items
49921 * A single item array - the first element is the root of the tree..
49922 * It's done this way to stay compatible with the Xtype system...
49930 Roo.apply(Roo.XComponent, {
49933 * @property buildCompleted
49934 * True when the builder has completed building the interface.
49937 buildCompleted : false,
49940 * @property topModule
49941 * the upper most module - uses document.element as it's constructor.
49948 * @property modules
49949 * array of modules to be created by registration system.
49950 * @type Roo.XComponent
49957 * Register components to be built later.
49959 * This solves the following issues
49960 * - Building is not done on page load, but after an authentication process has occured.
49961 * - Interface elements are registered on page load
49962 * - Parent Interface elements may not be loaded before child, so this handles that..
49969 module : 'Pman.Tab.projectMgr',
49971 parent : 'Pman.layout',
49972 disabled : false, // or use a function..
49975 * * @param {Object} details about module
49977 register : function(obj) {
49978 this.modules.push(obj);
49982 * convert a string to an object..
49986 toObject : function(str)
49988 if (!str || typeof(str) == 'object') {
49991 var ar = str.split('.');
49995 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
49997 throw "Module not found : " + str;
49999 Roo.each(ar, function(e) {
50000 if (typeof(o[e]) == 'undefined') {
50001 throw "Module not found : " + str;
50011 * move modules into their correct place in the tree..
50014 preBuild : function ()
50017 Roo.each(this.modules , function (obj)
50019 obj.parent = this.toObject(obj.parent);
50022 this.topModule = obj;
50026 if (!obj.parent.modules) {
50027 obj.parent.modules = new Roo.util.MixedCollection(false,
50028 function(o) { return o.order + '' }
50032 obj.parent.modules.add(obj);
50037 * make a list of modules to build.
50038 * @return {Array} list of modules.
50041 buildOrder : function()
50044 var cmp = function(a,b) {
50045 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
50048 if (!this.topModule || !this.topModule.modules) {
50049 throw "No top level modules to build";
50052 // make a flat list in order of modules to build.
50053 var mods = [ this.topModule ];
50056 // add modules to their parents..
50057 var addMod = function(m) {
50058 // console.log(m.modKey);
50062 m.modules.keySort('ASC', cmp );
50063 m.modules.each(addMod);
50065 // not sure if this is used any more..
50067 m.finalize.name = m.name + " (clean up) ";
50068 mods.push(m.finalize);
50072 this.topModule.modules.keySort('ASC', cmp );
50073 this.topModule.modules.each(addMod);
50078 * Build the registered modules.
50079 * @param {Object} parent element.
50080 * @param {Function} optional method to call after module has been added.
50088 var mods = this.buildOrder();
50090 //this.allmods = mods;
50091 //console.log(mods);
50093 if (!mods.length) { // should not happen
50094 throw "NO modules!!!";
50099 // flash it up as modal - so we store the mask!?
50100 Roo.MessageBox.show({ title: 'loading' });
50101 Roo.MessageBox.show({
50102 title: "Please wait...",
50103 msg: "Building Interface...",
50110 var total = mods.length;
50113 var progressRun = function() {
50114 if (!mods.length) {
50115 console.log('hide?');
50116 Roo.MessageBox.hide();
50117 _this.topModule.fireEvent('buildcomplete', _this.topModule);
50121 var m = mods.shift();
50123 if (typeof(m) == 'function') { // not sure if this is supported any more..
50125 return progressRun.defer(10, _this);
50128 Roo.MessageBox.updateProgress(
50129 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
50131 (m.name ? (' - ' + m.name) : '')
50136 var disabled = (typeof(m.disabled) == 'function') ?
50137 m.disabled.call(m.module.disabled) : m.disabled;
50141 return progressRun(); // we do not update the display!
50145 // it's a top level one..
50146 var layoutbase = new Ext.BorderLayout(document.body, {
50152 tabPosition: 'top',
50153 //resizeTabs: true,
50154 alwaysShowTabs: true,
50158 var tree = m.tree();
50159 tree.region = 'center';
50160 m.el = layoutbase.addxtype(tree);
50162 m.layout = m.panel.layout;
50163 return progressRun.defer(10, _this);
50166 var tree = m.tree();
50167 tree.region = tree.region || m.region;
50168 m.el = m.parent.el.addxtype(tree);
50169 m.fireEvent('built', m);
50171 m.layout = m.panel.layout;
50172 progressRun.defer(10, _this);
50175 progressRun.defer(1, _this);
50185 //<script type="text/javascript">
50190 * @extends Roo.LayoutDialog
50191 * A generic Login Dialog..... - only one needed in theory!?!?
50193 * Fires XComponent builder on success...
50196 * username,password, lang = for login actions.
50197 * check = 1 for periodic checking that sesion is valid.
50198 * passwordRequest = email request password
50199 * logout = 1 = to logout
50201 * Affects: (this id="????" elements)
50202 * loading (removed) (used to indicate application is loading)
50203 * loading-mask (hides) (used to hide application when it's building loading)
50209 * Myapp.login = Roo.Login({
50225 Roo.Login = function(cfg)
50228 'refreshed' : true,
50231 Roo.apply(this,cfg);
50233 Roo.onReady(function() {
50239 Roo.Login.superclass.constructor.call(this, this);
50240 //this.addxtype(this.items[0]);
50246 Roo.extend(Roo.Login, Roo.LayoutDialog, {
50249 * @cfg {String} method
50250 * Method used to query for login details.
50255 * @cfg {String} url
50256 * URL to query login data. - eg. baseURL + '/Login.php'
50262 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
50267 * @property checkFails
50268 * Number of times we have attempted to get authentication check, and failed.
50273 * @property intervalID
50274 * The window interval that does the constant login checking.
50280 onLoad : function() // called on page load...
50284 if (Roo.get('loading')) { // clear any loading indicator..
50285 Roo.get('loading').remove();
50288 //this.switchLang('en'); // set the language to english..
50291 success: function(response, opts) { // check successfull...
50293 var res = this.processResponse(response);
50294 this.checkFails =0;
50295 if (!res.success) { // error!
50296 this.checkFails = 5;
50297 //console.log('call failure');
50298 return this.failure(response,opts);
50301 if (!res.data.id) { // id=0 == login failure.
50302 return this.show();
50306 //console.log(success);
50307 this.fillAuth(res.data);
50308 this.checkFails =0;
50309 Roo.XComponent.build();
50311 failure : this.show
50317 check: function(cfg) // called every so often to refresh cookie etc..
50319 if (cfg.again) { // could be undefined..
50322 this.checkFails = 0;
50325 if (this.sending) {
50326 if ( this.checkFails > 4) {
50327 Roo.MessageBox.alert("Error",
50328 "Error getting authentication status. - try reloading, or wait a while", function() {
50329 _this.sending = false;
50334 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
50337 this.sending = true;
50344 method: this.method,
50345 success: cfg.success || this.success,
50346 failure : cfg.failure || this.failure,
50356 window.onbeforeunload = function() { }; // false does not work for IE..
50366 failure : function() {
50367 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
50368 document.location = document.location.toString() + '?ts=' + Math.random();
50372 success : function() {
50373 _this.user = false;
50374 this.checkFails =0;
50376 document.location = document.location.toString() + '?ts=' + Math.random();
50383 processResponse : function (response)
50387 res = Roo.decode(response.responseText);
50389 if (typeof(res) != 'object') {
50390 res = { success : false, errorMsg : res, errors : true };
50392 if (typeof(res.success) == 'undefined') {
50393 res.success = false;
50397 res = { success : false, errorMsg : response.responseText, errors : true };
50402 success : function(response, opts) // check successfull...
50404 this.sending = false;
50405 var res = this.processResponse(response);
50406 if (!res.success) {
50407 return this.failure(response, opts);
50409 if (!res.data || !res.data.id) {
50410 return this.failure(response,opts);
50412 //console.log(res);
50413 this.fillAuth(res.data);
50415 this.checkFails =0;
50420 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
50422 this.authUser = -1;
50423 this.sending = false;
50424 var res = this.processResponse(response);
50425 //console.log(res);
50426 if ( this.checkFails > 2) {
50428 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
50429 "Error getting authentication status. - try reloading");
50432 opts.callCfg.again = true;
50433 this.check.defer(1000, this, [ opts.callCfg ]);
50439 fillAuth: function(au) {
50440 this.startAuthCheck();
50441 this.authUserId = au.id;
50442 this.authUser = au;
50443 this.lastChecked = new Date();
50444 this.fireEvent('refreshed', au);
50445 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
50446 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
50447 au.lang = au.lang || 'en';
50448 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
50449 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
50450 this.switchLang(au.lang );
50453 // open system... - -on setyp..
50454 if (this.authUserId < 0) {
50455 Roo.MessageBox.alert("Warning",
50456 "This is an open system - please set up a admin user with a password.");
50459 //Pman.onload(); // which should do nothing if it's a re-auth result...
50464 startAuthCheck : function() // starter for timeout checking..
50466 if (this.intervalID) { // timer already in place...
50470 this.intervalID = window.setInterval(function() {
50471 _this.check(false);
50472 }, 120000); // every 120 secs = 2mins..
50478 switchLang : function (lang)
50480 _T = typeof(_T) == 'undefined' ? false : _T;
50481 if (!_T || !lang.length) {
50485 if (!_T && lang != 'en') {
50486 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
50490 if (typeof(_T.en) == 'undefined') {
50492 Roo.apply(_T.en, _T);
50495 if (typeof(_T[lang]) == 'undefined') {
50496 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
50501 Roo.apply(_T, _T[lang]);
50502 // just need to set the text values for everything...
50504 /* this will not work ...
50508 function formLabel(name, val) {
50509 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
50512 formLabel('password', "Password"+':');
50513 formLabel('username', "Email Address"+':');
50514 formLabel('lang', "Language"+':');
50515 this.dialog.setTitle("Login");
50516 this.dialog.buttons[0].setText("Forgot Password");
50517 this.dialog.buttons[1].setText("Login");
50536 collapsible: false,
50538 center: { // needed??
50541 // tabPosition: 'top',
50544 alwaysShowTabs: false
50548 show : function(dlg)
50550 //console.log(this);
50551 this.form = this.layout.getRegion('center').activePanel.form;
50552 this.form.dialog = dlg;
50553 this.buttons[0].form = this.form;
50554 this.buttons[0].dialog = dlg
50555 this.buttons[1].form = this.form;
50556 this.buttons[1].dialog = dlg;
50558 //this.resizeToLogo.defer(1000,this);
50559 // this is all related to resizing for logos..
50560 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
50562 // this.resizeToLogo.defer(1000,this);
50565 //var w = Ext.lib.Dom.getViewWidth() - 100;
50566 //var h = Ext.lib.Dom.getViewHeight() - 100;
50567 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
50569 if (this.disabled) {
50574 if (this.user.id < 0) { // used for inital setup situations.
50578 if (this.intervalID) {
50579 // remove the timer
50580 window.clearInterval(this.intervalID);
50581 this.intervalID = false;
50585 if (Roo.get('loading')) {
50586 Roo.get('loading').remove();
50588 if (Roo.get('loading-mask')) {
50589 Roo.get('loading-mask').hide();
50592 //incomming._node = tnode;
50594 //this.dialog.modal = !modal;
50595 //this.dialog.show();
50599 this.form.setValues({
50600 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
50601 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
50604 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
50605 if (this.form.findField('username').getValue().length > 0 ){
50606 this.form.findField('password').focus();
50608 this.form.findField('username').focus();
50616 xtype : 'ContentPanel',
50628 style : 'margin: 10px;',
50631 actionfailed : function(f, act) {
50632 // form can return { errors: .... }
50634 //act.result.errors // invalid form element list...
50635 //act.result.errorMsg// invalid form element list...
50637 this.dialog.el.unmask();
50638 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
50639 "Login failed - communication error - try again.");
50642 actioncomplete: function(re, act) {
50644 Roo.state.Manager.set(
50645 this.dialog.realm + '.username',
50646 this.findField('username').getValue()
50648 Roo.state.Manager.set(
50649 this.dialog.realm + '.lang',
50650 this.findField('lang').getValue()
50653 this.dialog.fillAuth(act.result.data);
50655 this.dialog.hide();
50657 if (Roo.get('loading-mask')) {
50658 Roo.get('loading-mask').show();
50660 Roo.XComponent.build();
50668 xtype : 'TextField',
50670 fieldLabel: "Email Address",
50673 autoCreate : {tag: "input", type: "text", size: "20"}
50676 xtype : 'TextField',
50678 fieldLabel: "Password",
50679 inputType: 'password',
50682 autoCreate : {tag: "input", type: "text", size: "20"},
50684 specialkey : function(e,ev) {
50685 if (ev.keyCode == 13) {
50686 this.form.dialog.el.mask("Logging in");
50687 this.form.doAction('submit', {
50688 url: this.form.dialog.url,
50689 method: this.form.dialog.method,
50696 xtype : 'ComboBox',
50698 fieldLabel: "Language",
50701 xtype : 'SimpleStore',
50702 fields: ['lang', 'ldisp'],
50704 [ 'en', 'English' ],
50705 [ 'zh_HK' , '\u7E41\u4E2D' ],
50706 [ 'zh_CN', '\u7C21\u4E2D' ]
50710 valueField : 'lang',
50711 hiddenName: 'lang',
50713 displayField:'ldisp',
50717 triggerAction: 'all',
50718 emptyText:'Select a Language...',
50719 selectOnFocus:true,
50721 select : function(cb, rec, ix) {
50722 this.form.switchLang(rec.data.lang);
50738 text : "Forgot Password",
50740 click : function() {
50741 //console.log(this);
50742 var n = this.form.findField('username').getValue();
50744 Roo.MessageBox.alert("Error", "Fill in your email address");
50748 url: this.dialog.url,
50752 method: this.dialog.method,
50753 success: function(response, opts) { // check successfull...
50755 var res = this.dialog.processResponse(response);
50756 if (!res.success) { // error!
50757 Roo.MessageBox.alert("Error" ,
50758 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
50761 Roo.MessageBox.alert("Notice" ,
50762 "Please check you email for the Password Reset message");
50764 failure : function() {
50765 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
50778 click : function () {
50780 this.dialog.el.mask("Logging in");
50781 this.form.doAction('submit', {
50782 url: this.dialog.url,
50783 method: this.dialog.method