4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
90 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
93 enableGarbageCollector : true,
96 * True to automatically purge event listeners after uncaching an element (defaults to false).
97 * Note: this only happens if enableGarbageCollector is true.
100 enableListenerCollection:false,
103 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
104 * the IE insecure content warning (defaults to javascript:false).
107 SSL_SECURE_URL : "javascript:false",
110 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
111 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
114 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
116 emptyFn : function(){},
119 * Copies all the properties of config to obj if they don't already exist.
120 * @param {Object} obj The receiver of the properties
121 * @param {Object} config The source of the properties
122 * @return {Object} returns obj
124 applyIf : function(o, c){
127 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134 * Applies event listeners to elements by selectors when the document is ready.
135 * The event name is specified with an @ suffix.
138 // add a listener for click on all anchors in element with id foo
139 '#foo a@click' : function(e, t){
143 // add the same listener to multiple selectors (separated by comma BEFORE the @)
144 '#foo a, #bar span.some-class@mouseover' : function(){
149 * @param {Object} obj The list of behaviors to apply
151 addBehaviors : function(o){
153 Roo.onReady(function(){
158 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
160 var parts = b.split('@');
161 if(parts[1]){ // for Object prototype breakers
164 cache[s] = Roo.select(s);
166 cache[s].on(parts[1], o[b]);
173 * Generates unique ids. If the element already has an id, it is unchanged
174 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
175 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
176 * @return {String} The generated Id.
178 id : function(el, prefix){
179 prefix = prefix || "roo-gen";
181 var id = prefix + (++idSeed);
182 return el ? (el.id ? el.id : (el.id = id)) : id;
187 * Extends one class with another class and optionally overrides members with the passed literal. This class
188 * also adds the function "override()" to the class that can be used to override
189 * members on an instance.
190 * @param {Object} subclass The class inheriting the functionality
191 * @param {Object} superclass The class being extended
192 * @param {Object} overrides (optional) A literal with members
197 var io = function(o){
202 return function(sb, sp, overrides){
203 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
206 sb = function(){sp.apply(this, arguments);};
208 var F = function(){}, sbp, spp = sp.prototype;
210 sbp = sb.prototype = new F();
214 if(spp.constructor == Object.prototype.constructor){
219 sb.override = function(o){
223 Roo.override(sb, overrides);
229 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
231 Roo.override(MyClass, {
232 newMethod1: function(){
235 newMethod2: function(foo){
240 * @param {Object} origclass The class to override
241 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
242 * containing one or more methods.
245 override : function(origclass, overrides){
247 var p = origclass.prototype;
248 for(var method in overrides){
249 p[method] = overrides[method];
254 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
256 Roo.namespace('Company', 'Company.data');
257 Company.Widget = function() { ... }
258 Company.data.CustomStore = function(config) { ... }
260 * @param {String} namespace1
261 * @param {String} namespace2
262 * @param {String} etc
265 namespace : function(){
266 var a=arguments, o=null, i, j, d, rt;
267 for (i=0; i<a.length; ++i) {
271 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
272 for (j=1; j<d.length; ++j) {
273 o[d[j]]=o[d[j]] || {};
279 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
281 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
282 Roo.factory(conf, Roo.data);
284 * @param {String} classname
285 * @param {String} namespace (optional)
289 factory : function(c, ns)
291 // no xtype, no ns or c.xns - or forced off by c.xns
292 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
295 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
296 if (c.constructor == ns[c.xtype]) {// already created...
300 console.log("Roo.Factory(" + c.xtype ")");
301 var ret = new ns[c.xtype](c);
305 c.xns = false; // prevent recursion..
310 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
314 urlEncode : function(o){
320 var ov = o[key], k = encodeURIComponent(key);
321 var type = typeof ov;
322 if(type == 'undefined'){
324 }else if(type != "function" && type != "object"){
325 buf.push(k, "=", encodeURIComponent(ov), "&");
326 }else if(ov instanceof Array){
328 for(var i = 0, len = ov.length; i < len; i++) {
329 buf.push(k, "=", encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
341 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
342 * @param {String} string
343 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
344 * @return {Object} A literal with members
346 urlDecode : function(string, overwrite){
347 if(!string || !string.length){
351 var pairs = string.split('&');
352 var pair, name, value;
353 for(var i = 0, len = pairs.length; i < len; i++){
354 pair = pairs[i].split('=');
355 name = decodeURIComponent(pair[0]);
356 value = decodeURIComponent(pair[1]);
357 if(overwrite !== true){
358 if(typeof obj[name] == "undefined"){
360 }else if(typeof obj[name] == "string"){
361 obj[name] = [obj[name]];
362 obj[name].push(value);
364 obj[name].push(value);
374 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
375 * passed array is not really an array, your function is called once with it.
376 * The supplied function is called with (Object item, Number index, Array allItems).
377 * @param {Array/NodeList/Mixed} array
378 * @param {Function} fn
379 * @param {Object} scope
381 each : function(array, fn, scope){
382 if(typeof array.length == "undefined" || typeof array == "string"){
385 for(var i = 0, len = array.length; i < len; i++){
386 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
391 combine : function(){
392 var as = arguments, l = as.length, r = [];
393 for(var i = 0; i < l; i++){
395 if(a instanceof Array){
397 }else if(a.length !== undefined && !a.substr){
398 r = r.concat(Array.prototype.slice.call(a, 0));
407 * Escapes the passed string for use in a regular expression
408 * @param {String} str
411 escapeRe : function(s) {
412 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
416 callback : function(cb, scope, args, delay){
417 if(typeof cb == "function"){
419 cb.defer(delay, scope, args || []);
421 cb.apply(scope, args || []);
427 * Return the dom node for the passed string (id), dom node, or Roo.Element
428 * @param {String/HTMLElement/Roo.Element} el
429 * @return HTMLElement
431 getDom : function(el){
435 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
439 * Shorthand for {@link Roo.ComponentMgr#get}
441 * @return Roo.Component
443 getCmp : function(id){
444 return Roo.ComponentMgr.get(id);
447 num : function(v, defaultValue){
448 if(typeof v != 'number'){
454 destroy : function(){
455 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
459 as.removeAllListeners();
463 if(typeof as.purgeListeners == 'function'){
466 if(typeof as.destroy == 'function'){
473 // inpired by a similar function in mootools library
475 * Returns the type of object that is passed in. If the object passed in is null or undefined it
476 * return false otherwise it returns one of the following values:<ul>
477 * <li><b>string</b>: If the object passed is a string</li>
478 * <li><b>number</b>: If the object passed is a number</li>
479 * <li><b>boolean</b>: If the object passed is a boolean value</li>
480 * <li><b>function</b>: If the object passed is a function reference</li>
481 * <li><b>object</b>: If the object passed is an object</li>
482 * <li><b>array</b>: If the object passed is an array</li>
483 * <li><b>regexp</b>: If the object passed is a regular expression</li>
484 * <li><b>element</b>: If the object passed is a DOM Element</li>
485 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
486 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
487 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
488 * @param {Mixed} object
492 if(o === undefined || o === null){
499 if(t == 'object' && o.nodeName) {
501 case 1: return 'element';
502 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
505 if(t == 'object' || t == 'function') {
506 switch(o.constructor) {
507 case Array: return 'array';
508 case RegExp: return 'regexp';
510 if(typeof o.length == 'number' && typeof o.item == 'function') {
518 * Returns true if the passed value is null, undefined or an empty string (optional).
519 * @param {Mixed} value The value to test
520 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
523 isEmpty : function(v, allowBlank){
524 return v === null || v === undefined || (!allowBlank ? v === '' : false);
538 isBorderBox : isBorderBox,
540 isWindows : isWindows,
547 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
548 * you may want to set this to true.
551 useShims : ((isIE && !isIE7) || (isGecko && isMac))
557 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
558 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
561 * Ext JS Library 1.1.1
562 * Copyright(c) 2006-2007, Ext JS, LLC.
564 * Originally Released Under LGPL - original licence link has changed is not relivant.
567 * <script type="text/javascript">
571 // wrappedn so fnCleanup is not in global scope...
573 function fnCleanUp() {
574 var p = Function.prototype;
575 delete p.createSequence;
577 delete p.createDelegate;
578 delete p.createCallback;
579 delete p.createInterceptor;
581 window.detachEvent("onunload", fnCleanUp);
583 window.attachEvent("onunload", fnCleanUp);
590 * These functions are available on every Function object (any JavaScript function).
592 Roo.apply(Function.prototype, {
594 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
595 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
596 * Will create a function that is bound to those 2 args.
597 * @return {Function} The new function
599 createCallback : function(/*args...*/){
600 // make args available, in function below
601 var args = arguments;
604 return method.apply(window, args);
609 * Creates a delegate (callback) that sets the scope to obj.
610 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
611 * Will create a function that is automatically scoped to this.
612 * @param {Object} obj (optional) The object for which the scope is set
613 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
614 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
615 * if a number the args are inserted at the specified position
616 * @return {Function} The new function
618 createDelegate : function(obj, args, appendArgs){
621 var callArgs = args || arguments;
622 if(appendArgs === true){
623 callArgs = Array.prototype.slice.call(arguments, 0);
624 callArgs = callArgs.concat(args);
625 }else if(typeof appendArgs == "number"){
626 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
627 var applyArgs = [appendArgs, 0].concat(args); // create method call params
628 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
630 return method.apply(obj || window, callArgs);
635 * Calls this function after the number of millseconds specified.
636 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
637 * @param {Object} obj (optional) The object for which the scope is set
638 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
639 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
640 * if a number the args are inserted at the specified position
641 * @return {Number} The timeout id that can be used with clearTimeout
643 defer : function(millis, obj, args, appendArgs){
644 var fn = this.createDelegate(obj, args, appendArgs);
646 return setTimeout(fn, millis);
652 * Create a combined function call sequence of the original function + the passed function.
653 * The resulting function returns the results of the original function.
654 * The passed fcn is called with the parameters of the original function
655 * @param {Function} fcn The function to sequence
656 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
657 * @return {Function} The new function
659 createSequence : function(fcn, scope){
660 if(typeof fcn != "function"){
665 var retval = method.apply(this || window, arguments);
666 fcn.apply(scope || this || window, arguments);
672 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
673 * The resulting function returns the results of the original function.
674 * The passed fcn is called with the parameters of the original function.
676 * @param {Function} fcn The function to call before the original
677 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
678 * @return {Function} The new function
680 createInterceptor : function(fcn, scope){
681 if(typeof fcn != "function"){
688 if(fcn.apply(scope || this || window, arguments) === false){
691 return method.apply(this || window, arguments);
697 * Ext JS Library 1.1.1
698 * Copyright(c) 2006-2007, Ext JS, LLC.
700 * Originally Released Under LGPL - original licence link has changed is not relivant.
703 * <script type="text/javascript">
706 Roo.applyIf(String, {
711 * Escapes the passed string for ' and \
712 * @param {String} string The string to escape
713 * @return {String} The escaped string
716 escape : function(string) {
717 return string.replace(/('|\\)/g, "\\$1");
721 * Pads the left side of a string with a specified character. This is especially useful
722 * for normalizing number and date strings. Example usage:
724 var s = String.leftPad('123', 5, '0');
725 // s now contains the string: '00123'
727 * @param {String} string The original string
728 * @param {Number} size The total length of the output string
729 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
730 * @return {String} The padded string
733 leftPad : function (val, size, ch) {
734 var result = new String(val);
735 if(ch === null || ch === undefined || ch === '') {
738 while (result.length < size) {
739 result = ch + result;
745 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
746 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
748 var cls = 'my-class', text = 'Some text';
749 var s = String.format('<div class="{0}">{1}</div>', cls, text);
750 // s now contains the string: '<div class="my-class">Some text</div>'
752 * @param {String} string The tokenized string to be formatted
753 * @param {String} value1 The value to replace token {0}
754 * @param {String} value2 Etc...
755 * @return {String} The formatted string
758 format : function(format){
759 var args = Array.prototype.slice.call(arguments, 1);
760 return format.replace(/\{(\d+)\}/g, function(m, i){
761 return Roo.util.Format.htmlEncode(args[i]);
767 * Utility function that allows you to easily switch a string between two alternating values. The passed value
768 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
769 * they are already different, the first value passed in is returned. Note that this method returns the new value
770 * but does not change the current string.
772 // alternate sort directions
773 sort = sort.toggle('ASC', 'DESC');
775 // instead of conditional logic:
776 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
778 * @param {String} value The value to compare to the current string
779 * @param {String} other The new value to use if the string already equals the first value passed in
780 * @return {String} The new value
783 String.prototype.toggle = function(value, other){
784 return this == value ? other : value;
787 * Ext JS Library 1.1.1
788 * Copyright(c) 2006-2007, Ext JS, LLC.
790 * Originally Released Under LGPL - original licence link has changed is not relivant.
793 * <script type="text/javascript">
799 Roo.applyIf(Number.prototype, {
801 * Checks whether or not the current number is within a desired range. If the number is already within the
802 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
803 * exceeded. Note that this method returns the constrained value but does not change the current number.
804 * @param {Number} min The minimum number in the range
805 * @param {Number} max The maximum number in the range
806 * @return {Number} The constrained value if outside the range, otherwise the current value
808 constrain : function(min, max){
809 return Math.min(Math.max(this, min), max);
813 * Ext JS Library 1.1.1
814 * Copyright(c) 2006-2007, Ext JS, LLC.
816 * Originally Released Under LGPL - original licence link has changed is not relivant.
819 * <script type="text/javascript">
824 Roo.applyIf(Array.prototype, {
826 * Checks whether or not the specified object exists in the array.
827 * @param {Object} o The object to check for
828 * @return {Number} The index of o in the array (or -1 if it is not found)
830 indexOf : function(o){
831 for (var i = 0, len = this.length; i < len; i++){
832 if(this[i] == o) return i;
838 * Removes the specified object from the array. If the object is not found nothing happens.
839 * @param {Object} o The object to remove
841 remove : function(o){
842 var index = this.indexOf(o);
844 this.splice(index, 1);
849 * Ext JS Library 1.1.1
850 * Copyright(c) 2006-2007, Ext JS, LLC.
852 * Originally Released Under LGPL - original licence link has changed is not relivant.
855 * <script type="text/javascript">
861 * The date parsing and format syntax is a subset of
862 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
863 * supported will provide results equivalent to their PHP versions.
865 * Following is the list of all currently supported formats:
868 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
870 Format Output Description
871 ------ ---------- --------------------------------------------------------------
872 d 10 Day of the month, 2 digits with leading zeros
873 D Wed A textual representation of a day, three letters
874 j 10 Day of the month without leading zeros
875 l Wednesday A full textual representation of the day of the week
876 S th English ordinal day of month suffix, 2 chars (use with j)
877 w 3 Numeric representation of the day of the week
878 z 9 The julian date, or day of the year (0-365)
879 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
880 F January A full textual representation of the month
881 m 01 Numeric representation of a month, with leading zeros
882 M Jan Month name abbreviation, three letters
883 n 1 Numeric representation of a month, without leading zeros
884 t 31 Number of days in the given month
885 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
886 Y 2007 A full numeric representation of a year, 4 digits
887 y 07 A two digit representation of a year
888 a pm Lowercase Ante meridiem and Post meridiem
889 A PM Uppercase Ante meridiem and Post meridiem
890 g 3 12-hour format of an hour without leading zeros
891 G 15 24-hour format of an hour without leading zeros
892 h 03 12-hour format of an hour with leading zeros
893 H 15 24-hour format of an hour with leading zeros
894 i 05 Minutes with leading zeros
895 s 01 Seconds, with leading zeros
896 O -0600 Difference to Greenwich time (GMT) in hours
897 T CST Timezone setting of the machine running the code
898 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
901 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
903 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
904 document.write(dt.format('Y-m-d')); //2007-01-10
905 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
906 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
909 * Here are some standard date/time patterns that you might find helpful. They
910 * are not part of the source of Date.js, but to use them you can simply copy this
911 * block of code into any script that is included after Date.js and they will also become
912 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
915 ISO8601Long:"Y-m-d H:i:s",
916 ISO8601Short:"Y-m-d",
918 LongDate: "l, F d, Y",
919 FullDateTime: "l, F d, Y g:i:s A",
923 SortableDateTime: "Y-m-d\\TH:i:s",
924 UniversalSortableDateTime: "Y-m-d H:i:sO",
932 document.write(dt.format(Date.patterns.ShortDate));
937 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
938 * They generate precompiled functions from date formats instead of parsing and
939 * processing the pattern every time you format a date. These functions are available
940 * on every Date object (any javascript function).
942 * The original article and download are here:
943 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
950 Returns the number of milliseconds between this date and date
951 @param {Date} date (optional) Defaults to now
952 @return {Number} The diff in milliseconds
953 @member Date getElapsed
955 Date.prototype.getElapsed = function(date) {
956 return Math.abs((date || new Date()).getTime()-this.getTime());
958 // was in date file..
962 Date.parseFunctions = {count:0};
964 Date.parseRegexes = [];
966 Date.formatFunctions = {count:0};
969 Date.prototype.dateFormat = function(format) {
970 if (Date.formatFunctions[format] == null) {
971 Date.createNewFormat(format);
973 var func = Date.formatFunctions[format];
979 * Formats a date given the supplied format string
980 * @param {String} format The format string
981 * @return {String} The formatted date
984 Date.prototype.format = Date.prototype.dateFormat;
987 Date.createNewFormat = function(format) {
988 var funcName = "format" + Date.formatFunctions.count++;
989 Date.formatFunctions[format] = funcName;
990 var code = "Date.prototype." + funcName + " = function(){return ";
993 for (var i = 0; i < format.length; ++i) {
994 ch = format.charAt(i);
995 if (!special && ch == "\\") {
1000 code += "'" + String.escape(ch) + "' + ";
1003 code += Date.getFormatCode(ch);
1006 /** eval:var:zzzzzzzzzzzzz */
1007 eval(code.substring(0, code.length - 3) + ";}");
1011 Date.getFormatCode = function(character) {
1012 switch (character) {
1014 return "String.leftPad(this.getDate(), 2, '0') + ";
1016 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1018 return "this.getDate() + ";
1020 return "Date.dayNames[this.getDay()] + ";
1022 return "this.getSuffix() + ";
1024 return "this.getDay() + ";
1026 return "this.getDayOfYear() + ";
1028 return "this.getWeekOfYear() + ";
1030 return "Date.monthNames[this.getMonth()] + ";
1032 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1034 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1036 return "(this.getMonth() + 1) + ";
1038 return "this.getDaysInMonth() + ";
1040 return "(this.isLeapYear() ? 1 : 0) + ";
1042 return "this.getFullYear() + ";
1044 return "('' + this.getFullYear()).substring(2, 4) + ";
1046 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1048 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1050 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1052 return "this.getHours() + ";
1054 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1056 return "String.leftPad(this.getHours(), 2, '0') + ";
1058 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1060 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1062 return "this.getGMTOffset() + ";
1064 return "this.getTimezone() + ";
1066 return "(this.getTimezoneOffset() * -60) + ";
1068 return "'" + String.escape(character) + "' + ";
1073 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1074 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1075 * the date format that is not specified will default to the current date value for that part. Time parts can also
1076 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1077 * string or the parse operation will fail.
1080 //dt = Fri May 25 2007 (current date)
1081 var dt = new Date();
1083 //dt = Thu May 25 2006 (today's month/day in 2006)
1084 dt = Date.parseDate("2006", "Y");
1086 //dt = Sun Jan 15 2006 (all date parts specified)
1087 dt = Date.parseDate("2006-1-15", "Y-m-d");
1089 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1090 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1092 * @param {String} input The unparsed date as a string
1093 * @param {String} format The format the date is in
1094 * @return {Date} The parsed date
1097 Date.parseDate = function(input, format) {
1098 if (Date.parseFunctions[format] == null) {
1099 Date.createParser(format);
1101 var func = Date.parseFunctions[format];
1102 return Date[func](input);
1106 Date.createParser = function(format) {
1107 var funcName = "parse" + Date.parseFunctions.count++;
1108 var regexNum = Date.parseRegexes.length;
1109 var currentGroup = 1;
1110 Date.parseFunctions[format] = funcName;
1112 var code = "Date." + funcName + " = function(input){\n"
1113 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1114 + "var d = new Date();\n"
1115 + "y = d.getFullYear();\n"
1116 + "m = d.getMonth();\n"
1117 + "d = d.getDate();\n"
1118 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1119 + "if (results && results.length > 0) {";
1122 var special = false;
1124 for (var i = 0; i < format.length; ++i) {
1125 ch = format.charAt(i);
1126 if (!special && ch == "\\") {
1131 regex += String.escape(ch);
1134 var obj = Date.formatCodeToRegex(ch, currentGroup);
1135 currentGroup += obj.g;
1137 if (obj.g && obj.c) {
1143 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1144 + "{v = new Date(y, m, d, h, i, s);}\n"
1145 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1146 + "{v = new Date(y, m, d, h, i);}\n"
1147 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1148 + "{v = new Date(y, m, d, h);}\n"
1149 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1150 + "{v = new Date(y, m, d);}\n"
1151 + "else if (y >= 0 && m >= 0)\n"
1152 + "{v = new Date(y, m);}\n"
1153 + "else if (y >= 0)\n"
1154 + "{v = new Date(y);}\n"
1155 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1156 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1157 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1160 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1161 /** eval:var:zzzzzzzzzzzzz */
1166 Date.formatCodeToRegex = function(character, currentGroup) {
1167 switch (character) {
1171 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1174 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1175 s:"(\\d{1,2})"}; // day of month without leading zeroes
1178 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1179 s:"(\\d{2})"}; // day of month with leading zeroes
1183 s:"(?:" + Date.dayNames.join("|") + ")"};
1187 s:"(?:st|nd|rd|th)"};
1202 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1203 s:"(" + Date.monthNames.join("|") + ")"};
1206 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1207 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1210 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1211 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1214 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1215 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1226 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1230 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1231 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1235 c:"if (results[" + currentGroup + "] == 'am') {\n"
1236 + "if (h == 12) { h = 0; }\n"
1237 + "} else { if (h < 12) { h += 12; }}",
1241 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1242 + "if (h == 12) { h = 0; }\n"
1243 + "} else { if (h < 12) { h += 12; }}",
1248 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1249 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1253 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1254 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1257 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1261 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1266 "o = results[", currentGroup, "];\n",
1267 "var sn = o.substring(0,1);\n", // get + / - sign
1268 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1269 "var mn = o.substring(3,5) % 60;\n", // get minutes
1270 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1271 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1277 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1280 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1281 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1282 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1286 s:String.escape(character)};
1291 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1292 * @return {String} The abbreviated timezone name (e.g. 'CST')
1294 Date.prototype.getTimezone = function() {
1295 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1299 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1300 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1302 Date.prototype.getGMTOffset = function() {
1303 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1304 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1305 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1309 * Get the numeric day number of the year, adjusted for leap year.
1310 * @return {Number} 0 through 364 (365 in leap years)
1312 Date.prototype.getDayOfYear = function() {
1314 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1315 for (var i = 0; i < this.getMonth(); ++i) {
1316 num += Date.daysInMonth[i];
1318 return num + this.getDate() - 1;
1322 * Get the string representation of the numeric week number of the year
1323 * (equivalent to the format specifier 'W').
1324 * @return {String} '00' through '52'
1326 Date.prototype.getWeekOfYear = function() {
1327 // Skip to Thursday of this week
1328 var now = this.getDayOfYear() + (4 - this.getDay());
1329 // Find the first Thursday of the year
1330 var jan1 = new Date(this.getFullYear(), 0, 1);
1331 var then = (7 - jan1.getDay() + 4);
1332 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1336 * Whether or not the current date is in a leap year.
1337 * @return {Boolean} True if the current date is in a leap year, else false
1339 Date.prototype.isLeapYear = function() {
1340 var year = this.getFullYear();
1341 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1345 * Get the first day of the current month, adjusted for leap year. The returned value
1346 * is the numeric day index within the week (0-6) which can be used in conjunction with
1347 * the {@link #monthNames} array to retrieve the textual day name.
1350 var dt = new Date('1/10/2007');
1351 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1353 * @return {Number} The day number (0-6)
1355 Date.prototype.getFirstDayOfMonth = function() {
1356 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1357 return (day < 0) ? (day + 7) : day;
1361 * Get the last day of the current month, adjusted for leap year. The returned value
1362 * is the numeric day index within the week (0-6) which can be used in conjunction with
1363 * the {@link #monthNames} array to retrieve the textual day name.
1366 var dt = new Date('1/10/2007');
1367 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1369 * @return {Number} The day number (0-6)
1371 Date.prototype.getLastDayOfMonth = function() {
1372 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1373 return (day < 0) ? (day + 7) : day;
1378 * Get the first date of this date's month
1381 Date.prototype.getFirstDateOfMonth = function() {
1382 return new Date(this.getFullYear(), this.getMonth(), 1);
1386 * Get the last date of this date's month
1389 Date.prototype.getLastDateOfMonth = function() {
1390 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1393 * Get the number of days in the current month, adjusted for leap year.
1394 * @return {Number} The number of days in the month
1396 Date.prototype.getDaysInMonth = function() {
1397 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1398 return Date.daysInMonth[this.getMonth()];
1402 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1403 * @return {String} 'st, 'nd', 'rd' or 'th'
1405 Date.prototype.getSuffix = function() {
1406 switch (this.getDate()) {
1423 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1426 * An array of textual month names.
1427 * Override these values for international dates, for example...
1428 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1447 * An array of textual day names.
1448 * Override these values for international dates, for example...
1449 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1465 Date.monthNumbers = {
1480 * Creates and returns a new Date instance with the exact same date value as the called instance.
1481 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1482 * variable will also be changed. When the intention is to create a new variable that will not
1483 * modify the original instance, you should create a clone.
1485 * Example of correctly cloning a date:
1488 var orig = new Date('10/1/2006');
1491 document.write(orig); //returns 'Thu Oct 05 2006'!
1494 var orig = new Date('10/1/2006');
1495 var copy = orig.clone();
1497 document.write(orig); //returns 'Thu Oct 01 2006'
1499 * @return {Date} The new Date instance
1501 Date.prototype.clone = function() {
1502 return new Date(this.getTime());
1506 * Clears any time information from this date
1507 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1508 @return {Date} this or the clone
1510 Date.prototype.clearTime = function(clone){
1512 return this.clone().clearTime();
1517 this.setMilliseconds(0);
1522 // safari setMonth is broken
1524 Date.brokenSetMonth = Date.prototype.setMonth;
1525 Date.prototype.setMonth = function(num){
1527 var n = Math.ceil(-num);
1528 var back_year = Math.ceil(n/12);
1529 var month = (n % 12) ? 12 - n % 12 : 0 ;
1530 this.setFullYear(this.getFullYear() - back_year);
1531 return Date.brokenSetMonth.call(this, month);
1533 return Date.brokenSetMonth.apply(this, arguments);
1538 /** Date interval constant
1542 /** Date interval constant
1546 /** Date interval constant
1550 /** Date interval constant
1554 /** Date interval constant
1558 /** Date interval constant
1562 /** Date interval constant
1568 * Provides a convenient method of performing basic date arithmetic. This method
1569 * does not modify the Date instance being called - it creates and returns
1570 * a new Date instance containing the resulting date value.
1575 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1576 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1578 //Negative values will subtract correctly:
1579 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1580 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1582 //You can even chain several calls together in one line!
1583 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1584 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1587 * @param {String} interval A valid date interval enum value
1588 * @param {Number} value The amount to add to the current date
1589 * @return {Date} The new Date instance
1591 Date.prototype.add = function(interval, value){
1592 var d = this.clone();
1593 if (!interval || value === 0) return d;
1594 switch(interval.toLowerCase()){
1596 d.setMilliseconds(this.getMilliseconds() + value);
1599 d.setSeconds(this.getSeconds() + value);
1602 d.setMinutes(this.getMinutes() + value);
1605 d.setHours(this.getHours() + value);
1608 d.setDate(this.getDate() + value);
1611 var day = this.getDate();
1613 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1616 d.setMonth(this.getMonth() + value);
1619 d.setFullYear(this.getFullYear() + value);
1625 * Ext JS Library 1.1.1
1626 * Copyright(c) 2006-2007, Ext JS, LLC.
1628 * Originally Released Under LGPL - original licence link has changed is not relivant.
1631 * <script type="text/javascript">
1635 getViewWidth : function(full) {
1636 return full ? this.getDocumentWidth() : this.getViewportWidth();
1639 getViewHeight : function(full) {
1640 return full ? this.getDocumentHeight() : this.getViewportHeight();
1643 getDocumentHeight: function() {
1644 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1645 return Math.max(scrollHeight, this.getViewportHeight());
1648 getDocumentWidth: function() {
1649 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1650 return Math.max(scrollWidth, this.getViewportWidth());
1653 getViewportHeight: function() {
1654 var height = self.innerHeight;
1655 var mode = document.compatMode;
1657 if ((mode || Roo.isIE) && !Roo.isOpera) {
1658 height = (mode == "CSS1Compat") ?
1659 document.documentElement.clientHeight :
1660 document.body.clientHeight;
1666 getViewportWidth: function() {
1667 var width = self.innerWidth;
1668 var mode = document.compatMode;
1670 if (mode || Roo.isIE) {
1671 width = (mode == "CSS1Compat") ?
1672 document.documentElement.clientWidth :
1673 document.body.clientWidth;
1678 isAncestor : function(p, c) {
1685 if (p.contains && !Roo.isSafari) {
1686 return p.contains(c);
1687 } else if (p.compareDocumentPosition) {
1688 return !!(p.compareDocumentPosition(c) & 16);
1690 var parent = c.parentNode;
1695 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1698 parent = parent.parentNode;
1704 getRegion : function(el) {
1705 return Roo.lib.Region.getRegion(el);
1708 getY : function(el) {
1709 return this.getXY(el)[1];
1712 getX : function(el) {
1713 return this.getXY(el)[0];
1716 getXY : function(el) {
1717 var p, pe, b, scroll, bd = document.body;
1718 el = Roo.getDom(el);
1719 var fly = Roo.lib.AnimBase.fly;
1720 if (el.getBoundingClientRect) {
1721 b = el.getBoundingClientRect();
1722 scroll = fly(document).getScroll();
1723 return [b.left + scroll.left, b.top + scroll.top];
1729 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1736 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1743 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1744 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1751 if (p != el && pe.getStyle('overflow') != 'visible') {
1759 if (Roo.isSafari && hasAbsolute) {
1764 if (Roo.isGecko && !hasAbsolute) {
1766 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1767 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1771 while (p && p != bd) {
1772 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1784 setXY : function(el, xy) {
1785 el = Roo.fly(el, '_setXY');
1787 var pts = el.translatePoints(xy);
1788 if (xy[0] !== false) {
1789 el.dom.style.left = pts.left + "px";
1791 if (xy[1] !== false) {
1792 el.dom.style.top = pts.top + "px";
1796 setX : function(el, x) {
1797 this.setXY(el, [x, false]);
1800 setY : function(el, y) {
1801 this.setXY(el, [false, y]);
1805 * Portions of this file are based on pieces of Yahoo User Interface Library
1806 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1807 * YUI licensed under the BSD License:
1808 * http://developer.yahoo.net/yui/license.txt
1809 * <script type="text/javascript">
1813 Roo.lib.Event = function() {
1814 var loadComplete = false;
1816 var unloadListeners = [];
1818 var onAvailStack = [];
1820 var lastError = null;
1833 startInterval: function() {
1834 if (!this._interval) {
1836 var callback = function() {
1837 self._tryPreloadAttach();
1839 this._interval = setInterval(callback, this.POLL_INTERVAL);
1844 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1845 onAvailStack.push({ id: p_id,
1848 override: p_override,
1849 checkReady: false });
1851 retryCount = this.POLL_RETRYS;
1852 this.startInterval();
1856 addListener: function(el, eventName, fn) {
1857 el = Roo.getDom(el);
1862 if ("unload" == eventName) {
1863 unloadListeners[unloadListeners.length] =
1864 [el, eventName, fn];
1868 var wrappedFn = function(e) {
1869 return fn(Roo.lib.Event.getEvent(e));
1872 var li = [el, eventName, fn, wrappedFn];
1874 var index = listeners.length;
1875 listeners[index] = li;
1877 this.doAdd(el, eventName, wrappedFn, false);
1883 removeListener: function(el, eventName, fn) {
1886 el = Roo.getDom(el);
1889 return this.purgeElement(el, false, eventName);
1893 if ("unload" == eventName) {
1895 for (i = 0,len = unloadListeners.length; i < len; i++) {
1896 var li = unloadListeners[i];
1899 li[1] == eventName &&
1901 unloadListeners.splice(i, 1);
1909 var cacheItem = null;
1912 var index = arguments[3];
1914 if ("undefined" == typeof index) {
1915 index = this._getCacheIndex(el, eventName, fn);
1919 cacheItem = listeners[index];
1922 if (!el || !cacheItem) {
1926 this.doRemove(el, eventName, cacheItem[this.WFN], false);
1928 delete listeners[index][this.WFN];
1929 delete listeners[index][this.FN];
1930 listeners.splice(index, 1);
1937 getTarget: function(ev, resolveTextNode) {
1938 ev = ev.browserEvent || ev;
1939 var t = ev.target || ev.srcElement;
1940 return this.resolveTextNode(t);
1944 resolveTextNode: function(node) {
1945 if (Roo.isSafari && node && 3 == node.nodeType) {
1946 return node.parentNode;
1953 getPageX: function(ev) {
1954 ev = ev.browserEvent || ev;
1956 if (!x && 0 !== x) {
1957 x = ev.clientX || 0;
1960 x += this.getScroll()[1];
1968 getPageY: function(ev) {
1969 ev = ev.browserEvent || ev;
1971 if (!y && 0 !== y) {
1972 y = ev.clientY || 0;
1975 y += this.getScroll()[0];
1984 getXY: function(ev) {
1985 ev = ev.browserEvent || ev;
1986 return [this.getPageX(ev), this.getPageY(ev)];
1990 getRelatedTarget: function(ev) {
1991 ev = ev.browserEvent || ev;
1992 var t = ev.relatedTarget;
1994 if (ev.type == "mouseout") {
1996 } else if (ev.type == "mouseover") {
2001 return this.resolveTextNode(t);
2005 getTime: function(ev) {
2006 ev = ev.browserEvent || ev;
2008 var t = new Date().getTime();
2012 this.lastError = ex;
2021 stopEvent: function(ev) {
2022 this.stopPropagation(ev);
2023 this.preventDefault(ev);
2027 stopPropagation: function(ev) {
2028 ev = ev.browserEvent || ev;
2029 if (ev.stopPropagation) {
2030 ev.stopPropagation();
2032 ev.cancelBubble = true;
2037 preventDefault: function(ev) {
2038 ev = ev.browserEvent || ev;
2039 if(ev.preventDefault) {
2040 ev.preventDefault();
2042 ev.returnValue = false;
2047 getEvent: function(e) {
2048 var ev = e || window.event;
2050 var c = this.getEvent.caller;
2052 ev = c.arguments[0];
2053 if (ev && Event == ev.constructor) {
2063 getCharCode: function(ev) {
2064 ev = ev.browserEvent || ev;
2065 return ev.charCode || ev.keyCode || 0;
2069 _getCacheIndex: function(el, eventName, fn) {
2070 for (var i = 0,len = listeners.length; i < len; ++i) {
2071 var li = listeners[i];
2073 li[this.FN] == fn &&
2074 li[this.EL] == el &&
2075 li[this.TYPE] == eventName) {
2087 getEl: function(id) {
2088 return document.getElementById(id);
2092 clearCache: function() {
2096 _load: function(e) {
2097 loadComplete = true;
2098 var EU = Roo.lib.Event;
2102 EU.doRemove(window, "load", EU._load);
2107 _tryPreloadAttach: function() {
2116 var tryAgain = !loadComplete;
2118 tryAgain = (retryCount > 0);
2123 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2124 var item = onAvailStack[i];
2126 var el = this.getEl(item.id);
2129 if (!item.checkReady ||
2132 (document && document.body)) {
2135 if (item.override) {
2136 if (item.override === true) {
2139 scope = item.override;
2142 item.fn.call(scope, item.obj);
2143 onAvailStack[i] = null;
2146 notAvail.push(item);
2151 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2155 this.startInterval();
2157 clearInterval(this._interval);
2158 this._interval = null;
2161 this.locked = false;
2168 purgeElement: function(el, recurse, eventName) {
2169 var elListeners = this.getListeners(el, eventName);
2171 for (var i = 0,len = elListeners.length; i < len; ++i) {
2172 var l = elListeners[i];
2173 this.removeListener(el, l.type, l.fn);
2177 if (recurse && el && el.childNodes) {
2178 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2179 this.purgeElement(el.childNodes[i], recurse, eventName);
2185 getListeners: function(el, eventName) {
2186 var results = [], searchLists;
2188 searchLists = [listeners, unloadListeners];
2189 } else if (eventName == "unload") {
2190 searchLists = [unloadListeners];
2192 searchLists = [listeners];
2195 for (var j = 0; j < searchLists.length; ++j) {
2196 var searchList = searchLists[j];
2197 if (searchList && searchList.length > 0) {
2198 for (var i = 0,len = searchList.length; i < len; ++i) {
2199 var l = searchList[i];
2200 if (l && l[this.EL] === el &&
2201 (!eventName || eventName === l[this.TYPE])) {
2206 adjust: l[this.ADJ_SCOPE],
2214 return (results.length) ? results : null;
2218 _unload: function(e) {
2220 var EU = Roo.lib.Event, i, j, l, len, index;
2222 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2223 l = unloadListeners[i];
2226 if (l[EU.ADJ_SCOPE]) {
2227 if (l[EU.ADJ_SCOPE] === true) {
2230 scope = l[EU.ADJ_SCOPE];
2233 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2234 unloadListeners[i] = null;
2240 unloadListeners = null;
2242 if (listeners && listeners.length > 0) {
2243 j = listeners.length;
2246 l = listeners[index];
2248 EU.removeListener(l[EU.EL], l[EU.TYPE],
2258 EU.doRemove(window, "unload", EU._unload);
2263 getScroll: function() {
2264 var dd = document.documentElement, db = document.body;
2265 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2266 return [dd.scrollTop, dd.scrollLeft];
2268 return [db.scrollTop, db.scrollLeft];
2275 doAdd: function () {
2276 if (window.addEventListener) {
2277 return function(el, eventName, fn, capture) {
2278 el.addEventListener(eventName, fn, (capture));
2280 } else if (window.attachEvent) {
2281 return function(el, eventName, fn, capture) {
2282 el.attachEvent("on" + eventName, fn);
2291 doRemove: function() {
2292 if (window.removeEventListener) {
2293 return function (el, eventName, fn, capture) {
2294 el.removeEventListener(eventName, fn, (capture));
2296 } else if (window.detachEvent) {
2297 return function (el, eventName, fn) {
2298 el.detachEvent("on" + eventName, fn);
2310 var E = Roo.lib.Event;
2311 E.on = E.addListener;
2312 E.un = E.removeListener;
2314 if (document && document.body) {
2317 E.doAdd(window, "load", E._load);
2319 E.doAdd(window, "unload", E._unload);
2320 E._tryPreloadAttach();
2324 * Portions of this file are based on pieces of Yahoo User Interface Library
2325 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2326 * YUI licensed under the BSD License:
2327 * http://developer.yahoo.net/yui/license.txt
2328 * <script type="text/javascript">
2335 request : function(method, uri, cb, data, options) {
2337 var hs = options.headers;
2340 if(hs.hasOwnProperty(h)){
2341 this.initHeader(h, hs[h], false);
2345 if(options.xmlData){
2346 this.initHeader('Content-Type', 'text/xml', false);
2348 data = options.xmlData;
2352 return this.asyncRequest(method, uri, cb, data);
2355 serializeForm : function(form) {
2356 if(typeof form == 'string') {
2357 form = (document.getElementById(form) || document.forms[form]);
2360 var el, name, val, disabled, data = '', hasSubmit = false;
2361 for (var i = 0; i < form.elements.length; i++) {
2362 el = form.elements[i];
2363 disabled = form.elements[i].disabled;
2364 name = form.elements[i].name;
2365 val = form.elements[i].value;
2367 if (!disabled && name){
2371 case 'select-multiple':
2372 for (var j = 0; j < el.options.length; j++) {
2373 if (el.options[j].selected) {
2375 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2378 data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2386 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2399 if(hasSubmit == false) {
2400 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2405 data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
2410 data = data.substr(0, data.length - 1);
2418 useDefaultHeader:true,
2420 defaultPostHeader:'application/x-www-form-urlencoded',
2422 useDefaultXhrHeader:true,
2424 defaultXhrHeader:'XMLHttpRequest',
2426 hasDefaultHeaders:true,
2438 setProgId:function(id)
2440 this.activeX.unshift(id);
2443 setDefaultPostHeader:function(b)
2445 this.useDefaultHeader = b;
2448 setDefaultXhrHeader:function(b)
2450 this.useDefaultXhrHeader = b;
2453 setPollingInterval:function(i)
2455 if (typeof i == 'number' && isFinite(i)) {
2456 this.pollInterval = i;
2460 createXhrObject:function(transactionId)
2466 http = new XMLHttpRequest();
2468 obj = { conn:http, tId:transactionId };
2472 for (var i = 0; i < this.activeX.length; ++i) {
2476 http = new ActiveXObject(this.activeX[i]);
2478 obj = { conn:http, tId:transactionId };
2491 getConnectionObject:function()
2494 var tId = this.transactionId;
2498 o = this.createXhrObject(tId);
2500 this.transactionId++;
2511 asyncRequest:function(method, uri, callback, postData)
2513 var o = this.getConnectionObject();
2519 o.conn.open(method, uri, true);
2521 if (this.useDefaultXhrHeader) {
2522 if (!this.defaultHeaders['X-Requested-With']) {
2523 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2527 if(postData && this.useDefaultHeader){
2528 this.initHeader('Content-Type', this.defaultPostHeader);
2531 if (this.hasDefaultHeaders || this.hasHeaders) {
2535 this.handleReadyState(o, callback);
2536 o.conn.send(postData || null);
2542 handleReadyState:function(o, callback)
2546 if (callback && callback.timeout) {
2547 this.timeout[o.tId] = window.setTimeout(function() {
2548 oConn.abort(o, callback, true);
2549 }, callback.timeout);
2552 this.poll[o.tId] = window.setInterval(
2554 if (o.conn && o.conn.readyState == 4) {
2555 window.clearInterval(oConn.poll[o.tId]);
2556 delete oConn.poll[o.tId];
2558 if(callback && callback.timeout) {
2559 window.clearTimeout(oConn.timeout[o.tId]);
2560 delete oConn.timeout[o.tId];
2563 oConn.handleTransactionResponse(o, callback);
2566 , this.pollInterval);
2569 handleTransactionResponse:function(o, callback, isAbort)
2573 this.releaseObject(o);
2577 var httpStatus, responseObject;
2581 if (o.conn.status !== undefined && o.conn.status != 0) {
2582 httpStatus = o.conn.status;
2594 if (httpStatus >= 200 && httpStatus < 300) {
2595 responseObject = this.createResponseObject(o, callback.argument);
2596 if (callback.success) {
2597 if (!callback.scope) {
2598 callback.success(responseObject);
2603 callback.success.apply(callback.scope, [responseObject]);
2608 switch (httpStatus) {
2616 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2617 if (callback.failure) {
2618 if (!callback.scope) {
2619 callback.failure(responseObject);
2622 callback.failure.apply(callback.scope, [responseObject]);
2627 responseObject = this.createResponseObject(o, callback.argument);
2628 if (callback.failure) {
2629 if (!callback.scope) {
2630 callback.failure(responseObject);
2633 callback.failure.apply(callback.scope, [responseObject]);
2639 this.releaseObject(o);
2640 responseObject = null;
2643 createResponseObject:function(o, callbackArg)
2650 var headerStr = o.conn.getAllResponseHeaders();
2651 var header = headerStr.split('\n');
2652 for (var i = 0; i < header.length; i++) {
2653 var delimitPos = header[i].indexOf(':');
2654 if (delimitPos != -1) {
2655 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2663 obj.status = o.conn.status;
2664 obj.statusText = o.conn.statusText;
2665 obj.getResponseHeader = headerObj;
2666 obj.getAllResponseHeaders = headerStr;
2667 obj.responseText = o.conn.responseText;
2668 obj.responseXML = o.conn.responseXML;
2670 if (typeof callbackArg !== undefined) {
2671 obj.argument = callbackArg;
2677 createExceptionObject:function(tId, callbackArg, isAbort)
2680 var COMM_ERROR = 'communication failure';
2681 var ABORT_CODE = -1;
2682 var ABORT_ERROR = 'transaction aborted';
2688 obj.status = ABORT_CODE;
2689 obj.statusText = ABORT_ERROR;
2692 obj.status = COMM_CODE;
2693 obj.statusText = COMM_ERROR;
2697 obj.argument = callbackArg;
2703 initHeader:function(label, value, isDefault)
2705 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2707 if (headerObj[label] === undefined) {
2708 headerObj[label] = value;
2713 headerObj[label] = value + "," + headerObj[label];
2717 this.hasDefaultHeaders = true;
2720 this.hasHeaders = true;
2725 setHeader:function(o)
2727 if (this.hasDefaultHeaders) {
2728 for (var prop in this.defaultHeaders) {
2729 if (this.defaultHeaders.hasOwnProperty(prop)) {
2730 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2735 if (this.hasHeaders) {
2736 for (var prop in this.headers) {
2737 if (this.headers.hasOwnProperty(prop)) {
2738 o.conn.setRequestHeader(prop, this.headers[prop]);
2742 this.hasHeaders = false;
2746 resetDefaultHeaders:function() {
2747 delete this.defaultHeaders;
2748 this.defaultHeaders = {};
2749 this.hasDefaultHeaders = false;
2752 abort:function(o, callback, isTimeout)
2754 if(this.isCallInProgress(o)) {
2756 window.clearInterval(this.poll[o.tId]);
2757 delete this.poll[o.tId];
2759 delete this.timeout[o.tId];
2762 this.handleTransactionResponse(o, callback, true);
2772 isCallInProgress:function(o)
2775 return o.conn.readyState != 4 && o.conn.readyState != 0;
2784 releaseObject:function(o)
2793 'MSXML2.XMLHTTP.3.0',
2801 * Portions of this file are based on pieces of Yahoo User Interface Library
2802 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2803 * YUI licensed under the BSD License:
2804 * http://developer.yahoo.net/yui/license.txt
2805 * <script type="text/javascript">
2809 Roo.lib.Region = function(t, r, b, l) {
2819 Roo.lib.Region.prototype = {
2820 contains : function(region) {
2821 return ( region.left >= this.left &&
2822 region.right <= this.right &&
2823 region.top >= this.top &&
2824 region.bottom <= this.bottom );
2828 getArea : function() {
2829 return ( (this.bottom - this.top) * (this.right - this.left) );
2832 intersect : function(region) {
2833 var t = Math.max(this.top, region.top);
2834 var r = Math.min(this.right, region.right);
2835 var b = Math.min(this.bottom, region.bottom);
2836 var l = Math.max(this.left, region.left);
2838 if (b >= t && r >= l) {
2839 return new Roo.lib.Region(t, r, b, l);
2844 union : function(region) {
2845 var t = Math.min(this.top, region.top);
2846 var r = Math.max(this.right, region.right);
2847 var b = Math.max(this.bottom, region.bottom);
2848 var l = Math.min(this.left, region.left);
2850 return new Roo.lib.Region(t, r, b, l);
2853 adjust : function(t, l, b, r) {
2862 Roo.lib.Region.getRegion = function(el) {
2863 var p = Roo.lib.Dom.getXY(el);
2866 var r = p[0] + el.offsetWidth;
2867 var b = p[1] + el.offsetHeight;
2870 return new Roo.lib.Region(t, r, b, l);
2873 * Portions of this file are based on pieces of Yahoo User Interface Library
2874 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2875 * YUI licensed under the BSD License:
2876 * http://developer.yahoo.net/yui/license.txt
2877 * <script type="text/javascript">
2880 //@@dep Roo.lib.Region
2883 Roo.lib.Point = function(x, y) {
2884 if (x instanceof Array) {
2888 this.x = this.right = this.left = this[0] = x;
2889 this.y = this.top = this.bottom = this[1] = y;
2892 Roo.lib.Point.prototype = new Roo.lib.Region();
2894 * Portions of this file are based on pieces of Yahoo User Interface Library
2895 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2896 * YUI licensed under the BSD License:
2897 * http://developer.yahoo.net/yui/license.txt
2898 * <script type="text/javascript">
2905 scroll : function(el, args, duration, easing, cb, scope) {
2906 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
2909 motion : function(el, args, duration, easing, cb, scope) {
2910 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
2913 color : function(el, args, duration, easing, cb, scope) {
2914 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
2917 run : function(el, args, duration, easing, cb, scope, type) {
2918 type = type || Roo.lib.AnimBase;
2919 if (typeof easing == "string") {
2920 easing = Roo.lib.Easing[easing];
2922 var anim = new type(el, args, duration, easing);
2923 anim.animateX(function() {
2924 Roo.callback(cb, scope);
2930 * Portions of this file are based on pieces of Yahoo User Interface Library
2931 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2932 * YUI licensed under the BSD License:
2933 * http://developer.yahoo.net/yui/license.txt
2934 * <script type="text/javascript">
2942 if (!libFlyweight) {
2943 libFlyweight = new Roo.Element.Flyweight();
2945 libFlyweight.dom = el;
2946 return libFlyweight;
2949 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
2953 Roo.lib.AnimBase = function(el, attributes, duration, method) {
2955 this.init(el, attributes, duration, method);
2959 Roo.lib.AnimBase.fly = fly;
2963 Roo.lib.AnimBase.prototype = {
2965 toString: function() {
2966 var el = this.getEl();
2967 var id = el.id || el.tagName;
2968 return ("Anim " + id);
2972 noNegatives: /width|height|opacity|padding/i,
2973 offsetAttribute: /^((width|height)|(top|left))$/,
2974 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
2975 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
2979 doMethod: function(attr, start, end) {
2980 return this.method(this.currentFrame, start, end - start, this.totalFrames);
2984 setAttribute: function(attr, val, unit) {
2985 if (this.patterns.noNegatives.test(attr)) {
2986 val = (val > 0) ? val : 0;
2989 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
2993 getAttribute: function(attr) {
2994 var el = this.getEl();
2995 var val = fly(el).getStyle(attr);
2997 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
2998 return parseFloat(val);
3001 var a = this.patterns.offsetAttribute.exec(attr) || [];
3002 var pos = !!( a[3] );
3003 var box = !!( a[2] );
3006 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3007 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3016 getDefaultUnit: function(attr) {
3017 if (this.patterns.defaultUnit.test(attr)) {
3024 animateX : function(callback, scope) {
3025 var f = function() {
3026 this.onComplete.removeListener(f);
3027 if (typeof callback == "function") {
3028 callback.call(scope || this, this);
3031 this.onComplete.addListener(f, this);
3036 setRuntimeAttribute: function(attr) {
3039 var attributes = this.attributes;
3041 this.runtimeAttributes[attr] = {};
3043 var isset = function(prop) {
3044 return (typeof prop !== 'undefined');
3047 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3051 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3054 if (isset(attributes[attr]['to'])) {
3055 end = attributes[attr]['to'];
3056 } else if (isset(attributes[attr]['by'])) {
3057 if (start.constructor == Array) {
3059 for (var i = 0, len = start.length; i < len; ++i) {
3060 end[i] = start[i] + attributes[attr]['by'][i];
3063 end = start + attributes[attr]['by'];
3067 this.runtimeAttributes[attr].start = start;
3068 this.runtimeAttributes[attr].end = end;
3071 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3075 init: function(el, attributes, duration, method) {
3077 var isAnimated = false;
3080 var startTime = null;
3083 var actualFrames = 0;
3086 el = Roo.getDom(el);
3089 this.attributes = attributes || {};
3092 this.duration = duration || 1;
3095 this.method = method || Roo.lib.Easing.easeNone;
3098 this.useSeconds = true;
3101 this.currentFrame = 0;
3104 this.totalFrames = Roo.lib.AnimMgr.fps;
3107 this.getEl = function() {
3112 this.isAnimated = function() {
3117 this.getStartTime = function() {
3121 this.runtimeAttributes = {};
3124 this.animate = function() {
3125 if (this.isAnimated()) {
3129 this.currentFrame = 0;
3131 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3133 Roo.lib.AnimMgr.registerElement(this);
3137 this.stop = function(finish) {
3139 this.currentFrame = this.totalFrames;
3140 this._onTween.fire();
3142 Roo.lib.AnimMgr.stop(this);
3145 var onStart = function() {
3146 this.onStart.fire();
3148 this.runtimeAttributes = {};
3149 for (var attr in this.attributes) {
3150 this.setRuntimeAttribute(attr);
3155 startTime = new Date();
3159 var onTween = function() {
3161 duration: new Date() - this.getStartTime(),
3162 currentFrame: this.currentFrame
3165 data.toString = function() {
3167 'duration: ' + data.duration +
3168 ', currentFrame: ' + data.currentFrame
3172 this.onTween.fire(data);
3174 var runtimeAttributes = this.runtimeAttributes;
3176 for (var attr in runtimeAttributes) {
3177 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3183 var onComplete = function() {
3184 var actual_duration = (new Date() - startTime) / 1000 ;
3187 duration: actual_duration,
3188 frames: actualFrames,
3189 fps: actualFrames / actual_duration
3192 data.toString = function() {
3194 'duration: ' + data.duration +
3195 ', frames: ' + data.frames +
3196 ', fps: ' + data.fps
3202 this.onComplete.fire(data);
3206 this._onStart = new Roo.util.Event(this);
3207 this.onStart = new Roo.util.Event(this);
3208 this.onTween = new Roo.util.Event(this);
3209 this._onTween = new Roo.util.Event(this);
3210 this.onComplete = new Roo.util.Event(this);
3211 this._onComplete = new Roo.util.Event(this);
3212 this._onStart.addListener(onStart);
3213 this._onTween.addListener(onTween);
3214 this._onComplete.addListener(onComplete);
3219 * Portions of this file are based on pieces of Yahoo User Interface Library
3220 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3221 * YUI licensed under the BSD License:
3222 * http://developer.yahoo.net/yui/license.txt
3223 * <script type="text/javascript">
3227 Roo.lib.AnimMgr = new function() {
3244 this.registerElement = function(tween) {
3245 queue[queue.length] = tween;
3247 tween._onStart.fire();
3252 this.unRegister = function(tween, index) {
3253 tween._onComplete.fire();
3254 index = index || getIndex(tween);
3256 queue.splice(index, 1);
3260 if (tweenCount <= 0) {
3266 this.start = function() {
3267 if (thread === null) {
3268 thread = setInterval(this.run, this.delay);
3273 this.stop = function(tween) {
3275 clearInterval(thread);
3277 for (var i = 0, len = queue.length; i < len; ++i) {
3278 if (queue[0].isAnimated()) {
3279 this.unRegister(queue[0], 0);
3288 this.unRegister(tween);
3293 this.run = function() {
3294 for (var i = 0, len = queue.length; i < len; ++i) {
3295 var tween = queue[i];
3296 if (!tween || !tween.isAnimated()) {
3300 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3302 tween.currentFrame += 1;
3304 if (tween.useSeconds) {
3305 correctFrame(tween);
3307 tween._onTween.fire();
3310 Roo.lib.AnimMgr.stop(tween, i);
3315 var getIndex = function(anim) {
3316 for (var i = 0, len = queue.length; i < len; ++i) {
3317 if (queue[i] == anim) {
3325 var correctFrame = function(tween) {
3326 var frames = tween.totalFrames;
3327 var frame = tween.currentFrame;
3328 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3329 var elapsed = (new Date() - tween.getStartTime());
3332 if (elapsed < tween.duration * 1000) {
3333 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3335 tweak = frames - (frame + 1);
3337 if (tweak > 0 && isFinite(tweak)) {
3338 if (tween.currentFrame + tweak >= frames) {
3339 tweak = frames - (frame + 1);
3342 tween.currentFrame += tweak;
3346 * Portions of this file are based on pieces of Yahoo User Interface Library
3347 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3348 * YUI licensed under the BSD License:
3349 * http://developer.yahoo.net/yui/license.txt
3350 * <script type="text/javascript">
3353 Roo.lib.Bezier = new function() {
3355 this.getPosition = function(points, t) {
3356 var n = points.length;
3359 for (var i = 0; i < n; ++i) {
3360 tmp[i] = [points[i][0], points[i][1]];
3363 for (var j = 1; j < n; ++j) {
3364 for (i = 0; i < n - j; ++i) {
3365 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3366 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3370 return [ tmp[0][0], tmp[0][1] ];
3374 * Portions of this file are based on pieces of Yahoo User Interface Library
3375 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3376 * YUI licensed under the BSD License:
3377 * http://developer.yahoo.net/yui/license.txt
3378 * <script type="text/javascript">
3383 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3384 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3387 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3389 var fly = Roo.lib.AnimBase.fly;
3391 var superclass = Y.ColorAnim.superclass;
3392 var proto = Y.ColorAnim.prototype;
3394 proto.toString = function() {
3395 var el = this.getEl();
3396 var id = el.id || el.tagName;
3397 return ("ColorAnim " + id);
3400 proto.patterns.color = /color$/i;
3401 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3402 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3403 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3404 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3407 proto.parseColor = function(s) {
3408 if (s.length == 3) {
3412 var c = this.patterns.hex.exec(s);
3413 if (c && c.length == 4) {
3414 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3417 c = this.patterns.rgb.exec(s);
3418 if (c && c.length == 4) {
3419 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3422 c = this.patterns.hex3.exec(s);
3423 if (c && c.length == 4) {
3424 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3429 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3430 proto.getAttribute = function(attr) {
3431 var el = this.getEl();
3432 if (this.patterns.color.test(attr)) {
3433 var val = fly(el).getStyle(attr);
3435 if (this.patterns.transparent.test(val)) {
3436 var parent = el.parentNode;
3437 val = fly(parent).getStyle(attr);
3439 while (parent && this.patterns.transparent.test(val)) {
3440 parent = parent.parentNode;
3441 val = fly(parent).getStyle(attr);
3442 if (parent.tagName.toUpperCase() == 'HTML') {
3448 val = superclass.getAttribute.call(this, attr);
3453 proto.getAttribute = function(attr) {
3454 var el = this.getEl();
3455 if (this.patterns.color.test(attr)) {
3456 var val = fly(el).getStyle(attr);
3458 if (this.patterns.transparent.test(val)) {
3459 var parent = el.parentNode;
3460 val = fly(parent).getStyle(attr);
3462 while (parent && this.patterns.transparent.test(val)) {
3463 parent = parent.parentNode;
3464 val = fly(parent).getStyle(attr);
3465 if (parent.tagName.toUpperCase() == 'HTML') {
3471 val = superclass.getAttribute.call(this, attr);
3477 proto.doMethod = function(attr, start, end) {
3480 if (this.patterns.color.test(attr)) {
3482 for (var i = 0, len = start.length; i < len; ++i) {
3483 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3486 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3489 val = superclass.doMethod.call(this, attr, start, end);
3495 proto.setRuntimeAttribute = function(attr) {
3496 superclass.setRuntimeAttribute.call(this, attr);
3498 if (this.patterns.color.test(attr)) {
3499 var attributes = this.attributes;
3500 var start = this.parseColor(this.runtimeAttributes[attr].start);
3501 var end = this.parseColor(this.runtimeAttributes[attr].end);
3503 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3504 end = this.parseColor(attributes[attr].by);
3506 for (var i = 0, len = start.length; i < len; ++i) {
3507 end[i] = start[i] + end[i];
3511 this.runtimeAttributes[attr].start = start;
3512 this.runtimeAttributes[attr].end = end;
3518 * Portions of this file are based on pieces of Yahoo User Interface Library
3519 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3520 * YUI licensed under the BSD License:
3521 * http://developer.yahoo.net/yui/license.txt
3522 * <script type="text/javascript">
3528 easeNone: function (t, b, c, d) {
3529 return c * t / d + b;
3533 easeIn: function (t, b, c, d) {
3534 return c * (t /= d) * t + b;
3538 easeOut: function (t, b, c, d) {
3539 return -c * (t /= d) * (t - 2) + b;
3543 easeBoth: function (t, b, c, d) {
3544 if ((t /= d / 2) < 1) {
3545 return c / 2 * t * t + b;
3548 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3552 easeInStrong: function (t, b, c, d) {
3553 return c * (t /= d) * t * t * t + b;
3557 easeOutStrong: function (t, b, c, d) {
3558 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3562 easeBothStrong: function (t, b, c, d) {
3563 if ((t /= d / 2) < 1) {
3564 return c / 2 * t * t * t * t + b;
3567 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3572 elasticIn: function (t, b, c, d, a, p) {
3576 if ((t /= d) == 1) {
3583 if (!a || a < Math.abs(c)) {
3588 var s = p / (2 * Math.PI) * Math.asin(c / a);
3591 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3595 elasticOut: function (t, b, c, d, a, p) {
3599 if ((t /= d) == 1) {
3606 if (!a || a < Math.abs(c)) {
3611 var s = p / (2 * Math.PI) * Math.asin(c / a);
3614 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3618 elasticBoth: function (t, b, c, d, a, p) {
3623 if ((t /= d / 2) == 2) {
3631 if (!a || a < Math.abs(c)) {
3636 var s = p / (2 * Math.PI) * Math.asin(c / a);
3640 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3641 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3643 return a * Math.pow(2, -10 * (t -= 1)) *
3644 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3649 backIn: function (t, b, c, d, s) {
3650 if (typeof s == 'undefined') {
3653 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3657 backOut: function (t, b, c, d, s) {
3658 if (typeof s == 'undefined') {
3661 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3665 backBoth: function (t, b, c, d, s) {
3666 if (typeof s == 'undefined') {
3670 if ((t /= d / 2 ) < 1) {
3671 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3673 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3677 bounceIn: function (t, b, c, d) {
3678 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3682 bounceOut: function (t, b, c, d) {
3683 if ((t /= d) < (1 / 2.75)) {
3684 return c * (7.5625 * t * t) + b;
3685 } else if (t < (2 / 2.75)) {
3686 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3687 } else if (t < (2.5 / 2.75)) {
3688 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3690 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3694 bounceBoth: function (t, b, c, d) {
3696 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3698 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3701 * Portions of this file are based on pieces of Yahoo User Interface Library
3702 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3703 * YUI licensed under the BSD License:
3704 * http://developer.yahoo.net/yui/license.txt
3705 * <script type="text/javascript">
3709 Roo.lib.Motion = function(el, attributes, duration, method) {
3711 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3715 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3719 var superclass = Y.Motion.superclass;
3720 var proto = Y.Motion.prototype;
3722 proto.toString = function() {
3723 var el = this.getEl();
3724 var id = el.id || el.tagName;
3725 return ("Motion " + id);
3728 proto.patterns.points = /^points$/i;
3730 proto.setAttribute = function(attr, val, unit) {
3731 if (this.patterns.points.test(attr)) {
3732 unit = unit || 'px';
3733 superclass.setAttribute.call(this, 'left', val[0], unit);
3734 superclass.setAttribute.call(this, 'top', val[1], unit);
3736 superclass.setAttribute.call(this, attr, val, unit);
3740 proto.getAttribute = function(attr) {
3741 if (this.patterns.points.test(attr)) {
3743 superclass.getAttribute.call(this, 'left'),
3744 superclass.getAttribute.call(this, 'top')
3747 val = superclass.getAttribute.call(this, attr);
3753 proto.doMethod = function(attr, start, end) {
3756 if (this.patterns.points.test(attr)) {
3757 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3758 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3760 val = superclass.doMethod.call(this, attr, start, end);
3765 proto.setRuntimeAttribute = function(attr) {
3766 if (this.patterns.points.test(attr)) {
3767 var el = this.getEl();
3768 var attributes = this.attributes;
3770 var control = attributes['points']['control'] || [];
3774 if (control.length > 0 && !(control[0] instanceof Array)) {
3775 control = [control];
3778 for (i = 0,len = control.length; i < len; ++i) {
3779 tmp[i] = control[i];
3784 Roo.fly(el).position();
3786 if (isset(attributes['points']['from'])) {
3787 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3790 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3793 start = this.getAttribute('points');
3796 if (isset(attributes['points']['to'])) {
3797 end = translateValues.call(this, attributes['points']['to'], start);
3799 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3800 for (i = 0,len = control.length; i < len; ++i) {
3801 control[i] = translateValues.call(this, control[i], start);
3805 } else if (isset(attributes['points']['by'])) {
3806 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3808 for (i = 0,len = control.length; i < len; ++i) {
3809 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3813 this.runtimeAttributes[attr] = [start];
3815 if (control.length > 0) {
3816 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3819 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3822 superclass.setRuntimeAttribute.call(this, attr);
3826 var translateValues = function(val, start) {
3827 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3828 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3833 var isset = function(prop) {
3834 return (typeof prop !== 'undefined');
3838 * Portions of this file are based on pieces of Yahoo User Interface Library
3839 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3840 * YUI licensed under the BSD License:
3841 * http://developer.yahoo.net/yui/license.txt
3842 * <script type="text/javascript">
3846 Roo.lib.Scroll = function(el, attributes, duration, method) {
3848 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
3852 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
3856 var superclass = Y.Scroll.superclass;
3857 var proto = Y.Scroll.prototype;
3859 proto.toString = function() {
3860 var el = this.getEl();
3861 var id = el.id || el.tagName;
3862 return ("Scroll " + id);
3865 proto.doMethod = function(attr, start, end) {
3868 if (attr == 'scroll') {
3870 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
3871 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
3875 val = superclass.doMethod.call(this, attr, start, end);
3880 proto.getAttribute = function(attr) {
3882 var el = this.getEl();
3884 if (attr == 'scroll') {
3885 val = [ el.scrollLeft, el.scrollTop ];
3887 val = superclass.getAttribute.call(this, attr);
3893 proto.setAttribute = function(attr, val, unit) {
3894 var el = this.getEl();
3896 if (attr == 'scroll') {
3897 el.scrollLeft = val[0];
3898 el.scrollTop = val[1];
3900 superclass.setAttribute.call(this, attr, val, unit);
3906 * Ext JS Library 1.1.1
3907 * Copyright(c) 2006-2007, Ext JS, LLC.
3909 * Originally Released Under LGPL - original licence link has changed is not relivant.
3912 * <script type="text/javascript">
3917 * @class Roo.DomHelper
3918 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
3919 * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
3922 Roo.DomHelper = function(){
3923 var tempTableEl = null;
3924 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
3925 var tableRe = /^table|tbody|tr|td$/i;
3927 // build as innerHTML where available
3929 var createHtml = function(o){
3930 if(typeof o == 'string'){
3939 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
3940 if(attr == "style"){
3942 if(typeof s == "function"){
3945 if(typeof s == "string"){
3946 b += ' style="' + s + '"';
3947 }else if(typeof s == "object"){
3950 if(typeof s[key] != "function"){
3951 b += key + ":" + s[key] + ";";
3958 b += ' class="' + o["cls"] + '"';
3959 }else if(attr == "htmlFor"){
3960 b += ' for="' + o["htmlFor"] + '"';
3962 b += " " + attr + '="' + o[attr] + '"';
3966 if(emptyTags.test(o.tag)){
3970 var cn = o.children || o.cn;
3972 //http://bugs.kde.org/show_bug.cgi?id=71506
3973 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
3974 for(var i = 0, len = cn.length; i < len; i++) {
3975 b += createHtml(cn[i], b);
3978 b += createHtml(cn, b);
3984 b += "</" + o.tag + ">";
3991 var createDom = function(o, parentNode){
3993 // defininition craeted..
3995 if (o.ns && o.ns != 'html') {
3997 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
3998 xmlns[o.ns] = o.xmlns;
4001 if (typeof(xmlns[o.ns]) == 'undefined') {
4002 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4008 if (typeof(o) == 'string') {
4009 return parentNode.appendChild(document.createTextNode(o));
4011 o.tag = o.tag || div;
4012 if (o.ns && Roo.isIE) {
4014 o.tag = o.ns + ':' + o.tag;
4017 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4018 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4021 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4022 attr == "style" || typeof o[attr] == "function") continue;
4024 if(attr=="cls" && Roo.isIE){
4025 el.className = o["cls"];
4027 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4028 else el[attr] = o[attr];
4031 Roo.DomHelper.applyStyles(el, o.style);
4032 var cn = o.children || o.cn;
4034 //http://bugs.kde.org/show_bug.cgi?id=71506
4035 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4036 for(var i = 0, len = cn.length; i < len; i++) {
4037 createDom(cn[i], el);
4044 el.innerHTML = o.html;
4047 parentNode.appendChild(el);
4052 var ieTable = function(depth, s, h, e){
4053 tempTableEl.innerHTML = [s, h, e].join('');
4054 var i = -1, el = tempTableEl;
4061 // kill repeat to save bytes
4065 tbe = '</tbody>'+te,
4071 * Nasty code for IE's broken table implementation
4073 var insertIntoTable = function(tag, where, el, html){
4075 tempTableEl = document.createElement('div');
4080 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4083 if(where == 'beforebegin'){
4087 before = el.nextSibling;
4090 node = ieTable(4, trs, html, tre);
4092 else if(tag == 'tr'){
4093 if(where == 'beforebegin'){
4096 node = ieTable(3, tbs, html, tbe);
4097 } else if(where == 'afterend'){
4098 before = el.nextSibling;
4100 node = ieTable(3, tbs, html, tbe);
4101 } else{ // INTO a TR
4102 if(where == 'afterbegin'){
4103 before = el.firstChild;
4105 node = ieTable(4, trs, html, tre);
4107 } else if(tag == 'tbody'){
4108 if(where == 'beforebegin'){
4111 node = ieTable(2, ts, html, te);
4112 } else if(where == 'afterend'){
4113 before = el.nextSibling;
4115 node = ieTable(2, ts, html, te);
4117 if(where == 'afterbegin'){
4118 before = el.firstChild;
4120 node = ieTable(3, tbs, html, tbe);
4123 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4126 if(where == 'afterbegin'){
4127 before = el.firstChild;
4129 node = ieTable(2, ts, html, te);
4131 el.insertBefore(node, before);
4136 /** True to force the use of DOM instead of html fragments @type Boolean */
4140 * Returns the markup for the passed Element(s) config
4141 * @param {Object} o The Dom object spec (and children)
4144 markup : function(o){
4145 return createHtml(o);
4149 * Applies a style specification to an element
4150 * @param {String/HTMLElement} el The element to apply styles to
4151 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4152 * a function which returns such a specification.
4154 applyStyles : function(el, styles){
4157 if(typeof styles == "string"){
4158 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4160 while ((matches = re.exec(styles)) != null){
4161 el.setStyle(matches[1], matches[2]);
4163 }else if (typeof styles == "object"){
4164 for (var style in styles){
4165 el.setStyle(style, styles[style]);
4167 }else if (typeof styles == "function"){
4168 Roo.DomHelper.applyStyles(el, styles.call());
4174 * Inserts an HTML fragment into the Dom
4175 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4176 * @param {HTMLElement} el The context element
4177 * @param {String} html The HTML fragmenet
4178 * @return {HTMLElement} The new node
4180 insertHtml : function(where, el, html){
4181 where = where.toLowerCase();
4182 if(el.insertAdjacentHTML){
4183 if(tableRe.test(el.tagName)){
4185 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4191 el.insertAdjacentHTML('BeforeBegin', html);
4192 return el.previousSibling;
4194 el.insertAdjacentHTML('AfterBegin', html);
4195 return el.firstChild;
4197 el.insertAdjacentHTML('BeforeEnd', html);
4198 return el.lastChild;
4200 el.insertAdjacentHTML('AfterEnd', html);
4201 return el.nextSibling;
4203 throw 'Illegal insertion point -> "' + where + '"';
4205 var range = el.ownerDocument.createRange();
4209 range.setStartBefore(el);
4210 frag = range.createContextualFragment(html);
4211 el.parentNode.insertBefore(frag, el);
4212 return el.previousSibling;
4215 range.setStartBefore(el.firstChild);
4216 frag = range.createContextualFragment(html);
4217 el.insertBefore(frag, el.firstChild);
4218 return el.firstChild;
4220 el.innerHTML = html;
4221 return el.firstChild;
4225 range.setStartAfter(el.lastChild);
4226 frag = range.createContextualFragment(html);
4227 el.appendChild(frag);
4228 return el.lastChild;
4230 el.innerHTML = html;
4231 return el.lastChild;
4234 range.setStartAfter(el);
4235 frag = range.createContextualFragment(html);
4236 el.parentNode.insertBefore(frag, el.nextSibling);
4237 return el.nextSibling;
4239 throw 'Illegal insertion point -> "' + where + '"';
4243 * Creates new Dom element(s) and inserts them before el
4244 * @param {String/HTMLElement/Element} el The context element
4245 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4246 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4247 * @return {HTMLElement/Roo.Element} The new node
4249 insertBefore : function(el, o, returnElement){
4250 return this.doInsert(el, o, returnElement, "beforeBegin");
4254 * Creates new Dom element(s) and inserts them after el
4255 * @param {String/HTMLElement/Element} el The context element
4256 * @param {Object} o The Dom object spec (and children)
4257 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4258 * @return {HTMLElement/Roo.Element} The new node
4260 insertAfter : function(el, o, returnElement){
4261 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4265 * Creates new Dom element(s) and inserts them as the first child of el
4266 * @param {String/HTMLElement/Element} el The context element
4267 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4268 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4269 * @return {HTMLElement/Roo.Element} The new node
4271 insertFirst : function(el, o, returnElement){
4272 return this.doInsert(el, o, returnElement, "afterBegin");
4276 doInsert : function(el, o, returnElement, pos, sibling){
4277 el = Roo.getDom(el);
4279 if(this.useDom || o.ns){
4280 newNode = createDom(o, null);
4281 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4283 var html = createHtml(o);
4284 newNode = this.insertHtml(pos, el, html);
4286 return returnElement ? Roo.get(newNode, true) : newNode;
4290 * Creates new Dom element(s) and appends them to el
4291 * @param {String/HTMLElement/Element} el The context element
4292 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4293 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4294 * @return {HTMLElement/Roo.Element} The new node
4296 append : function(el, o, returnElement){
4297 el = Roo.getDom(el);
4299 if(this.useDom || o.ns){
4300 newNode = createDom(o, null);
4301 el.appendChild(newNode);
4303 var html = createHtml(o);
4304 newNode = this.insertHtml("beforeEnd", el, html);
4306 return returnElement ? Roo.get(newNode, true) : newNode;
4310 * Creates new Dom element(s) and overwrites the contents of el with them
4311 * @param {String/HTMLElement/Element} el The context element
4312 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4313 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4314 * @return {HTMLElement/Roo.Element} The new node
4316 overwrite : function(el, o, returnElement){
4317 el = Roo.getDom(el);
4320 while (el.childNodes.length) {
4321 el.removeChild(el.firstChild);
4325 el.innerHTML = createHtml(o);
4328 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4332 * Creates a new Roo.DomHelper.Template from the Dom object spec
4333 * @param {Object} o The Dom object spec (and children)
4334 * @return {Roo.DomHelper.Template} The new template
4336 createTemplate : function(o){
4337 var html = createHtml(o);
4338 return new Roo.Template(html);
4344 * Ext JS Library 1.1.1
4345 * Copyright(c) 2006-2007, Ext JS, LLC.
4347 * Originally Released Under LGPL - original licence link has changed is not relivant.
4350 * <script type="text/javascript">
4354 * @class Roo.Template
4355 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4356 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4359 var t = new Roo.Template(
4360 '<div name="{id}">',
4361 '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
4364 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4366 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>.
4368 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4370 Roo.Template = function(html){
4371 if(html instanceof Array){
4372 html = html.join("");
4373 }else if(arguments.length > 1){
4374 html = Array.prototype.join.call(arguments, "");
4380 Roo.Template.prototype = {
4382 * Returns an HTML fragment of this template with the specified values applied.
4383 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4384 * @return {String} The HTML fragment
4386 applyTemplate : function(values){
4388 return this.compiled(values);
4390 var useF = this.disableFormats !== true;
4391 var fm = Roo.util.Format, tpl = this;
4392 var fn = function(m, name, format, args){
4394 if(format.substr(0, 5) == "this."){
4395 return tpl.call(format.substr(5), values[name], values);
4398 // quoted values are required for strings in compiled templates,
4399 // but for non compiled we need to strip them
4400 // quoted reversed for jsmin
4401 var re = /^\s*['"](.*)["']\s*$/;
4402 args = args.split(',');
4403 for(var i = 0, len = args.length; i < len; i++){
4404 args[i] = args[i].replace(re, "$1");
4406 args = [values[name]].concat(args);
4408 args = [values[name]];
4410 return fm[format].apply(fm, args);
4413 return values[name] !== undefined ? values[name] : "";
4416 return this.html.replace(this.re, fn);
4420 * Sets the HTML used as the template and optionally compiles it.
4421 * @param {String} html
4422 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4423 * @return {Roo.Template} this
4425 set : function(html, compile){
4427 this.compiled = null;
4435 * True to disable format functions (defaults to false)
4438 disableFormats : false,
4441 * The regular expression used to match template variables
4445 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4448 * Compiles the template into an internal function, eliminating the RegEx overhead.
4449 * @return {Roo.Template} this
4451 compile : function(){
4452 var fm = Roo.util.Format;
4453 var useF = this.disableFormats !== true;
4454 var sep = Roo.isGecko ? "+" : ",";
4455 var fn = function(m, name, format, args){
4457 args = args ? ',' + args : "";
4458 if(format.substr(0, 5) != "this."){
4459 format = "fm." + format + '(';
4461 format = 'this.call("'+ format.substr(5) + '", ';
4465 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4467 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4470 // branched to use + in gecko and [].join() in others
4472 body = "this.compiled = function(values){ return '" +
4473 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4476 body = ["this.compiled = function(values){ return ['"];
4477 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4478 body.push("'].join('');};");
4479 body = body.join('');
4489 // private function used to call members
4490 call : function(fnName, value, allValues){
4491 return this[fnName](value, allValues);
4495 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4496 * @param {String/HTMLElement/Roo.Element} el The context element
4497 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4498 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4499 * @return {HTMLElement/Roo.Element} The new node or Element
4501 insertFirst: function(el, values, returnElement){
4502 return this.doInsert('afterBegin', el, values, returnElement);
4506 * Applies the supplied values to the template and inserts the new node(s) before el.
4507 * @param {String/HTMLElement/Roo.Element} el The context element
4508 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4509 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4510 * @return {HTMLElement/Roo.Element} The new node or Element
4512 insertBefore: function(el, values, returnElement){
4513 return this.doInsert('beforeBegin', el, values, returnElement);
4517 * Applies the supplied values to the template and inserts the new node(s) after el.
4518 * @param {String/HTMLElement/Roo.Element} el The context element
4519 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4520 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4521 * @return {HTMLElement/Roo.Element} The new node or Element
4523 insertAfter : function(el, values, returnElement){
4524 return this.doInsert('afterEnd', el, values, returnElement);
4528 * Applies the supplied values to the template and appends the new node(s) to el.
4529 * @param {String/HTMLElement/Roo.Element} el The context element
4530 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4531 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4532 * @return {HTMLElement/Roo.Element} The new node or Element
4534 append : function(el, values, returnElement){
4535 return this.doInsert('beforeEnd', el, values, returnElement);
4538 doInsert : function(where, el, values, returnEl){
4539 el = Roo.getDom(el);
4540 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4541 return returnEl ? Roo.get(newNode, true) : newNode;
4545 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4546 * @param {String/HTMLElement/Roo.Element} el The context element
4547 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4548 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4549 * @return {HTMLElement/Roo.Element} The new node or Element
4551 overwrite : function(el, values, returnElement){
4552 el = Roo.getDom(el);
4553 el.innerHTML = this.applyTemplate(values);
4554 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4558 * Alias for {@link #applyTemplate}
4561 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4564 Roo.DomHelper.Template = Roo.Template;
4567 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4568 * @param {String/HTMLElement} el A DOM element or its id
4569 * @returns {Roo.Template} The created template
4572 Roo.Template.from = function(el){
4573 el = Roo.getDom(el);
4574 return new Roo.Template(el.value || el.innerHTML);
4577 * Ext JS Library 1.1.1
4578 * Copyright(c) 2006-2007, Ext JS, LLC.
4580 * Originally Released Under LGPL - original licence link has changed is not relivant.
4583 * <script type="text/javascript">
4588 * This is code is also distributed under MIT license for use
4589 * with jQuery and prototype JavaScript libraries.
4592 * @class Roo.DomQuery
4593 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4595 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4598 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4600 <h4>Element Selectors:</h4>
4602 <li> <b>*</b> any element</li>
4603 <li> <b>E</b> an element with the tag E</li>
4604 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4605 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4606 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4607 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4609 <h4>Attribute Selectors:</h4>
4610 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4612 <li> <b>E[foo]</b> has an attribute "foo"</li>
4613 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4614 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4615 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4616 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4617 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4618 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4620 <h4>Pseudo Classes:</h4>
4622 <li> <b>E:first-child</b> E is the first child of its parent</li>
4623 <li> <b>E:last-child</b> E is the last child of its parent</li>
4624 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4625 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4626 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4627 <li> <b>E:only-child</b> E is the only child of its parent</li>
4628 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4629 <li> <b>E:first</b> the first E in the resultset</li>
4630 <li> <b>E:last</b> the last E in the resultset</li>
4631 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4632 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4633 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4634 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4635 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4636 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4637 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4638 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4639 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4641 <h4>CSS Value Selectors:</h4>
4643 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4644 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4645 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4646 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4647 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4648 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4652 Roo.DomQuery = function(){
4653 var cache = {}, simpleCache = {}, valueCache = {};
4654 var nonSpace = /\S/;
4655 var trimRe = /^\s+|\s+$/g;
4656 var tplRe = /\{(\d+)\}/g;
4657 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4658 var tagTokenRe = /^(#)?([\w-\*]+)/;
4659 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4661 function child(p, index){
4663 var n = p.firstChild;
4665 if(n.nodeType == 1){
4676 while((n = n.nextSibling) && n.nodeType != 1);
4681 while((n = n.previousSibling) && n.nodeType != 1);
4685 function children(d){
4686 var n = d.firstChild, ni = -1;
4688 var nx = n.nextSibling;
4689 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4699 function byClassName(c, a, v){
4703 var r = [], ri = -1, cn;
4704 for(var i = 0, ci; ci = c[i]; i++){
4705 if((' '+ci.className+' ').indexOf(v) != -1){
4712 function attrValue(n, attr){
4713 if(!n.tagName && typeof n.length != "undefined"){
4722 if(attr == "class" || attr == "className"){
4725 return n.getAttribute(attr) || n[attr];
4729 function getNodes(ns, mode, tagName){
4730 var result = [], ri = -1, cs;
4734 tagName = tagName || "*";
4735 if(typeof ns.getElementsByTagName != "undefined"){
4739 for(var i = 0, ni; ni = ns[i]; i++){
4740 cs = ni.getElementsByTagName(tagName);
4741 for(var j = 0, ci; ci = cs[j]; j++){
4745 }else if(mode == "/" || mode == ">"){
4746 var utag = tagName.toUpperCase();
4747 for(var i = 0, ni, cn; ni = ns[i]; i++){
4748 cn = ni.children || ni.childNodes;
4749 for(var j = 0, cj; cj = cn[j]; j++){
4750 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4755 }else if(mode == "+"){
4756 var utag = tagName.toUpperCase();
4757 for(var i = 0, n; n = ns[i]; i++){
4758 while((n = n.nextSibling) && n.nodeType != 1);
4759 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4763 }else if(mode == "~"){
4764 for(var i = 0, n; n = ns[i]; i++){
4765 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
4774 function concat(a, b){
4778 for(var i = 0, l = b.length; i < l; i++){
4784 function byTag(cs, tagName){
4785 if(cs.tagName || cs == document){
4791 var r = [], ri = -1;
4792 tagName = tagName.toLowerCase();
4793 for(var i = 0, ci; ci = cs[i]; i++){
4794 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
4801 function byId(cs, attr, id){
4802 if(cs.tagName || cs == document){
4808 var r = [], ri = -1;
4809 for(var i = 0,ci; ci = cs[i]; i++){
4810 if(ci && ci.id == id){
4818 function byAttribute(cs, attr, value, op, custom){
4819 var r = [], ri = -1, st = custom=="{";
4820 var f = Roo.DomQuery.operators[op];
4821 for(var i = 0, ci; ci = cs[i]; i++){
4824 a = Roo.DomQuery.getStyle(ci, attr);
4826 else if(attr == "class" || attr == "className"){
4828 }else if(attr == "for"){
4830 }else if(attr == "href"){
4831 a = ci.getAttribute("href", 2);
4833 a = ci.getAttribute(attr);
4835 if((f && f(a, value)) || (!f && a)){
4842 function byPseudo(cs, name, value){
4843 return Roo.DomQuery.pseudos[name](cs, value);
4846 // This is for IE MSXML which does not support expandos.
4847 // IE runs the same speed using setAttribute, however FF slows way down
4848 // and Safari completely fails so they need to continue to use expandos.
4849 var isIE = window.ActiveXObject ? true : false;
4851 // this eval is stop the compressor from
4852 // renaming the variable to something shorter
4854 /** eval:var:batch */
4859 function nodupIEXml(cs){
4861 cs[0].setAttribute("_nodup", d);
4863 for(var i = 1, len = cs.length; i < len; i++){
4865 if(!c.getAttribute("_nodup") != d){
4866 c.setAttribute("_nodup", d);
4870 for(var i = 0, len = cs.length; i < len; i++){
4871 cs[i].removeAttribute("_nodup");
4880 var len = cs.length, c, i, r = cs, cj, ri = -1;
4881 if(!len || typeof cs.nodeType != "undefined" || len == 1){
4884 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
4885 return nodupIEXml(cs);
4889 for(i = 1; c = cs[i]; i++){
4894 for(var j = 0; j < i; j++){
4897 for(j = i+1; cj = cs[j]; j++){
4909 function quickDiffIEXml(c1, c2){
4911 for(var i = 0, len = c1.length; i < len; i++){
4912 c1[i].setAttribute("_qdiff", d);
4915 for(var i = 0, len = c2.length; i < len; i++){
4916 if(c2[i].getAttribute("_qdiff") != d){
4917 r[r.length] = c2[i];
4920 for(var i = 0, len = c1.length; i < len; i++){
4921 c1[i].removeAttribute("_qdiff");
4926 function quickDiff(c1, c2){
4927 var len1 = c1.length;
4931 if(isIE && c1[0].selectSingleNode){
4932 return quickDiffIEXml(c1, c2);
4935 for(var i = 0; i < len1; i++){
4939 for(var i = 0, len = c2.length; i < len; i++){
4940 if(c2[i]._qdiff != d){
4941 r[r.length] = c2[i];
4947 function quickId(ns, mode, root, id){
4949 var d = root.ownerDocument || root;
4950 return d.getElementById(id);
4952 ns = getNodes(ns, mode, "*");
4953 return byId(ns, null, id);
4957 getStyle : function(el, name){
4958 return Roo.fly(el).getStyle(name);
4961 * Compiles a selector/xpath query into a reusable function. The returned function
4962 * takes one parameter "root" (optional), which is the context node from where the query should start.
4963 * @param {String} selector The selector/xpath query
4964 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
4965 * @return {Function}
4967 compile : function(path, type){
4968 type = type || "select";
4970 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
4971 var q = path, mode, lq;
4972 var tk = Roo.DomQuery.matchers;
4973 var tklen = tk.length;
4976 // accept leading mode switch
4977 var lmode = q.match(modeRe);
4978 if(lmode && lmode[1]){
4979 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
4980 q = q.replace(lmode[1], "");
4982 // strip leading slashes
4983 while(path.substr(0, 1)=="/"){
4984 path = path.substr(1);
4987 while(q && lq != q){
4989 var tm = q.match(tagTokenRe);
4990 if(type == "select"){
4993 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
4995 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
4997 q = q.replace(tm[0], "");
4998 }else if(q.substr(0, 1) != '@'){
4999 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5004 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5006 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5008 q = q.replace(tm[0], "");
5011 while(!(mm = q.match(modeRe))){
5012 var matched = false;
5013 for(var j = 0; j < tklen; j++){
5015 var m = q.match(t.re);
5017 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5020 q = q.replace(m[0], "");
5025 // prevent infinite loop on bad selector
5027 throw 'Error parsing selector, parsing failed at "' + q + '"';
5031 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5032 q = q.replace(mm[1], "");
5035 fn[fn.length] = "return nodup(n);\n}";
5038 * list of variables that need from compression as they are used by eval.
5048 * eval:var:byClassName
5050 * eval:var:byAttribute
5051 * eval:var:attrValue
5059 * Selects a group of elements.
5060 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5061 * @param {Node} root (optional) The start of the query (defaults to document).
5064 select : function(path, root, type){
5065 if(!root || root == document){
5068 if(typeof root == "string"){
5069 root = document.getElementById(root);
5071 var paths = path.split(",");
5073 for(var i = 0, len = paths.length; i < len; i++){
5074 var p = paths[i].replace(trimRe, "");
5076 cache[p] = Roo.DomQuery.compile(p);
5078 throw p + " is not a valid selector";
5081 var result = cache[p](root);
5082 if(result && result != document){
5083 results = results.concat(result);
5086 if(paths.length > 1){
5087 return nodup(results);
5093 * Selects a single element.
5094 * @param {String} selector The selector/xpath query
5095 * @param {Node} root (optional) The start of the query (defaults to document).
5098 selectNode : function(path, root){
5099 return Roo.DomQuery.select(path, root)[0];
5103 * Selects the value of a node, optionally replacing null with the defaultValue.
5104 * @param {String} selector The selector/xpath query
5105 * @param {Node} root (optional) The start of the query (defaults to document).
5106 * @param {String} defaultValue
5108 selectValue : function(path, root, defaultValue){
5109 path = path.replace(trimRe, "");
5110 if(!valueCache[path]){
5111 valueCache[path] = Roo.DomQuery.compile(path, "select");
5113 var n = valueCache[path](root);
5114 n = n[0] ? n[0] : n;
5115 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5116 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5120 * Selects the value of a node, parsing integers and floats.
5121 * @param {String} selector The selector/xpath query
5122 * @param {Node} root (optional) The start of the query (defaults to document).
5123 * @param {Number} defaultValue
5126 selectNumber : function(path, root, defaultValue){
5127 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5128 return parseFloat(v);
5132 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5133 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5134 * @param {String} selector The simple selector to test
5137 is : function(el, ss){
5138 if(typeof el == "string"){
5139 el = document.getElementById(el);
5141 var isArray = (el instanceof Array);
5142 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5143 return isArray ? (result.length == el.length) : (result.length > 0);
5147 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5148 * @param {Array} el An array of elements to filter
5149 * @param {String} selector The simple selector to test
5150 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5151 * the selector instead of the ones that match
5154 filter : function(els, ss, nonMatches){
5155 ss = ss.replace(trimRe, "");
5156 if(!simpleCache[ss]){
5157 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5159 var result = simpleCache[ss](els);
5160 return nonMatches ? quickDiff(result, els) : result;
5164 * Collection of matching regular expressions and code snippets.
5168 select: 'n = byClassName(n, null, " {1} ");'
5170 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5171 select: 'n = byPseudo(n, "{1}", "{2}");'
5173 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5174 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5177 select: 'n = byId(n, null, "{1}");'
5180 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5185 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5186 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5189 "=" : function(a, v){
5192 "!=" : function(a, v){
5195 "^=" : function(a, v){
5196 return a && a.substr(0, v.length) == v;
5198 "$=" : function(a, v){
5199 return a && a.substr(a.length-v.length) == v;
5201 "*=" : function(a, v){
5202 return a && a.indexOf(v) !== -1;
5204 "%=" : function(a, v){
5205 return (a % v) == 0;
5207 "|=" : function(a, v){
5208 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5210 "~=" : function(a, v){
5211 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5216 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5217 * and the argument (if any) supplied in the selector.
5220 "first-child" : function(c){
5221 var r = [], ri = -1, n;
5222 for(var i = 0, ci; ci = n = c[i]; i++){
5223 while((n = n.previousSibling) && n.nodeType != 1);
5231 "last-child" : function(c){
5232 var r = [], ri = -1, n;
5233 for(var i = 0, ci; ci = n = c[i]; i++){
5234 while((n = n.nextSibling) && n.nodeType != 1);
5242 "nth-child" : function(c, a) {
5243 var r = [], ri = -1;
5244 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5245 var f = (m[1] || 1) - 0, l = m[2] - 0;
5246 for(var i = 0, n; n = c[i]; i++){
5247 var pn = n.parentNode;
5248 if (batch != pn._batch) {
5250 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5251 if(cn.nodeType == 1){
5258 if (l == 0 || n.nodeIndex == l){
5261 } else if ((n.nodeIndex + l) % f == 0){
5269 "only-child" : function(c){
5270 var r = [], ri = -1;;
5271 for(var i = 0, ci; ci = c[i]; i++){
5272 if(!prev(ci) && !next(ci)){
5279 "empty" : function(c){
5280 var r = [], ri = -1;
5281 for(var i = 0, ci; ci = c[i]; i++){
5282 var cns = ci.childNodes, j = 0, cn, empty = true;
5285 if(cn.nodeType == 1 || cn.nodeType == 3){
5297 "contains" : function(c, v){
5298 var r = [], ri = -1;
5299 for(var i = 0, ci; ci = c[i]; i++){
5300 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5307 "nodeValue" : function(c, v){
5308 var r = [], ri = -1;
5309 for(var i = 0, ci; ci = c[i]; i++){
5310 if(ci.firstChild && ci.firstChild.nodeValue == v){
5317 "checked" : function(c){
5318 var r = [], ri = -1;
5319 for(var i = 0, ci; ci = c[i]; i++){
5320 if(ci.checked == true){
5327 "not" : function(c, ss){
5328 return Roo.DomQuery.filter(c, ss, true);
5331 "odd" : function(c){
5332 return this["nth-child"](c, "odd");
5335 "even" : function(c){
5336 return this["nth-child"](c, "even");
5339 "nth" : function(c, a){
5340 return c[a-1] || [];
5343 "first" : function(c){
5347 "last" : function(c){
5348 return c[c.length-1] || [];
5351 "has" : function(c, ss){
5352 var s = Roo.DomQuery.select;
5353 var r = [], ri = -1;
5354 for(var i = 0, ci; ci = c[i]; i++){
5355 if(s(ss, ci).length > 0){
5362 "next" : function(c, ss){
5363 var is = Roo.DomQuery.is;
5364 var r = [], ri = -1;
5365 for(var i = 0, ci; ci = c[i]; i++){
5374 "prev" : function(c, ss){
5375 var is = Roo.DomQuery.is;
5376 var r = [], ri = -1;
5377 for(var i = 0, ci; ci = c[i]; i++){
5390 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5391 * @param {String} path The selector/xpath query
5392 * @param {Node} root (optional) The start of the query (defaults to document).
5397 Roo.query = Roo.DomQuery.select;
5400 * Ext JS Library 1.1.1
5401 * Copyright(c) 2006-2007, Ext JS, LLC.
5403 * Originally Released Under LGPL - original licence link has changed is not relivant.
5406 * <script type="text/javascript">
5410 * @class Roo.util.Observable
5411 * Base class that provides a common interface for publishing events. Subclasses are expected to
5412 * to have a property "events" with all the events defined.<br>
5415 Employee = function(name){
5422 Roo.extend(Employee, Roo.util.Observable);
5424 * @param {Object} config properties to use (incuding events / listeners)
5427 Roo.util.Observable = function(cfg){
5430 this.addEvents(cfg.events || {});
5432 delete cfg.events; // make sure
5435 Roo.apply(this, cfg);
5438 this.on(this.listeners);
5439 delete this.listeners;
5442 Roo.util.Observable.prototype = {
5444 * @cfg {Object} listeners list of events and functions to call for this object,
5448 'click' : function(e) {
5458 * Fires the specified event with the passed parameters (minus the event name).
5459 * @param {String} eventName
5460 * @param {Object...} args Variable number of parameters are passed to handlers
5461 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5463 fireEvent : function(){
5464 var ce = this.events[arguments[0].toLowerCase()];
5465 if(typeof ce == "object"){
5466 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5473 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5476 * Appends an event handler to this component
5477 * @param {String} eventName The type of event to listen for
5478 * @param {Function} handler The method the event invokes
5479 * @param {Object} scope (optional) The scope in which to execute the handler
5480 * function. The handler function's "this" context.
5481 * @param {Object} options (optional) An object containing handler configuration
5482 * properties. This may contain any of the following properties:<ul>
5483 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5484 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5485 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5486 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5487 * by the specified number of milliseconds. If the event fires again within that time, the original
5488 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5491 * <b>Combining Options</b><br>
5492 * Using the options argument, it is possible to combine different types of listeners:<br>
5494 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5496 el.on('click', this.onClick, this, {
5503 * <b>Attaching multiple handlers in 1 call</b><br>
5504 * The method also allows for a single argument to be passed which is a config object containing properties
5505 * which specify multiple handlers.
5514 fn: this.onMouseOver,
5518 fn: this.onMouseOut,
5524 * Or a shorthand syntax which passes the same scope object to all handlers:
5527 'click': this.onClick,
5528 'mouseover': this.onMouseOver,
5529 'mouseout': this.onMouseOut,
5534 addListener : function(eventName, fn, scope, o){
5535 if(typeof eventName == "object"){
5538 if(this.filterOptRe.test(e)){
5541 if(typeof o[e] == "function"){
5543 this.addListener(e, o[e], o.scope, o);
5545 // individual options
5546 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5551 o = (!o || typeof o == "boolean") ? {} : o;
5552 eventName = eventName.toLowerCase();
5553 var ce = this.events[eventName] || true;
5554 if(typeof ce == "boolean"){
5555 ce = new Roo.util.Event(this, eventName);
5556 this.events[eventName] = ce;
5558 ce.addListener(fn, scope, o);
5562 * Removes a listener
5563 * @param {String} eventName The type of event to listen for
5564 * @param {Function} handler The handler to remove
5565 * @param {Object} scope (optional) The scope (this object) for the handler
5567 removeListener : function(eventName, fn, scope){
5568 var ce = this.events[eventName.toLowerCase()];
5569 if(typeof ce == "object"){
5570 ce.removeListener(fn, scope);
5575 * Removes all listeners for this object
5577 purgeListeners : function(){
5578 for(var evt in this.events){
5579 if(typeof this.events[evt] == "object"){
5580 this.events[evt].clearListeners();
5585 relayEvents : function(o, events){
5586 var createHandler = function(ename){
5588 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5591 for(var i = 0, len = events.length; i < len; i++){
5592 var ename = events[i];
5593 if(!this.events[ename]){ this.events[ename] = true; };
5594 o.on(ename, createHandler(ename), this);
5599 * Used to define events on this Observable
5600 * @param {Object} object The object with the events defined
5602 addEvents : function(o){
5606 Roo.applyIf(this.events, o);
5610 * Checks to see if this object has any listeners for a specified event
5611 * @param {String} eventName The name of the event to check for
5612 * @return {Boolean} True if the event is being listened for, else false
5614 hasListener : function(eventName){
5615 var e = this.events[eventName];
5616 return typeof e == "object" && e.listeners.length > 0;
5620 * Appends an event handler to this element (shorthand for addListener)
5621 * @param {String} eventName The type of event to listen for
5622 * @param {Function} handler The method the event invokes
5623 * @param {Object} scope (optional) The scope in which to execute the handler
5624 * function. The handler function's "this" context.
5625 * @param {Object} options (optional)
5628 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5630 * Removes a listener (shorthand for removeListener)
5631 * @param {String} eventName The type of event to listen for
5632 * @param {Function} handler The handler to remove
5633 * @param {Object} scope (optional) The scope (this object) for the handler
5636 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5639 * Starts capture on the specified Observable. All events will be passed
5640 * to the supplied function with the event name + standard signature of the event
5641 * <b>before</b> the event is fired. If the supplied function returns false,
5642 * the event will not fire.
5643 * @param {Observable} o The Observable to capture
5644 * @param {Function} fn The function to call
5645 * @param {Object} scope (optional) The scope (this object) for the fn
5648 Roo.util.Observable.capture = function(o, fn, scope){
5649 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5653 * Removes <b>all</b> added captures from the Observable.
5654 * @param {Observable} o The Observable to release
5657 Roo.util.Observable.releaseCapture = function(o){
5658 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5663 var createBuffered = function(h, o, scope){
5664 var task = new Roo.util.DelayedTask();
5666 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5670 var createSingle = function(h, e, fn, scope){
5672 e.removeListener(fn, scope);
5673 return h.apply(scope, arguments);
5677 var createDelayed = function(h, o, scope){
5679 var args = Array.prototype.slice.call(arguments, 0);
5680 setTimeout(function(){
5681 h.apply(scope, args);
5686 Roo.util.Event = function(obj, name){
5689 this.listeners = [];
5692 Roo.util.Event.prototype = {
5693 addListener : function(fn, scope, options){
5694 var o = options || {};
5695 scope = scope || this.obj;
5696 if(!this.isListening(fn, scope)){
5697 var l = {fn: fn, scope: scope, options: o};
5700 h = createDelayed(h, o, scope);
5703 h = createSingle(h, this, fn, scope);
5706 h = createBuffered(h, o, scope);
5709 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5710 this.listeners.push(l);
5712 this.listeners = this.listeners.slice(0);
5713 this.listeners.push(l);
5718 findListener : function(fn, scope){
5719 scope = scope || this.obj;
5720 var ls = this.listeners;
5721 for(var i = 0, len = ls.length; i < len; i++){
5723 if(l.fn == fn && l.scope == scope){
5730 isListening : function(fn, scope){
5731 return this.findListener(fn, scope) != -1;
5734 removeListener : function(fn, scope){
5736 if((index = this.findListener(fn, scope)) != -1){
5738 this.listeners.splice(index, 1);
5740 this.listeners = this.listeners.slice(0);
5741 this.listeners.splice(index, 1);
5748 clearListeners : function(){
5749 this.listeners = [];
5753 var ls = this.listeners, scope, len = ls.length;
5756 var args = Array.prototype.slice.call(arguments, 0);
5757 for(var i = 0; i < len; i++){
5759 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5760 this.firing = false;
5764 this.firing = false;
5771 * Ext JS Library 1.1.1
5772 * Copyright(c) 2006-2007, Ext JS, LLC.
5774 * Originally Released Under LGPL - original licence link has changed is not relivant.
5777 * <script type="text/javascript">
5781 * @class Roo.EventManager
5782 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
5783 * several useful events directly.
5784 * See {@link Roo.EventObject} for more details on normalized event objects.
5787 Roo.EventManager = function(){
5788 var docReadyEvent, docReadyProcId, docReadyState = false;
5789 var resizeEvent, resizeTask, textEvent, textSize;
5790 var E = Roo.lib.Event;
5791 var D = Roo.lib.Dom;
5794 var fireDocReady = function(){
5796 docReadyState = true;
5799 clearInterval(docReadyProcId);
5801 if(Roo.isGecko || Roo.isOpera) {
5802 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
5805 var defer = document.getElementById("ie-deferred-loader");
5807 defer.onreadystatechange = null;
5808 defer.parentNode.removeChild(defer);
5812 docReadyEvent.fire();
5813 docReadyEvent.clearListeners();
5818 var initDocReady = function(){
5819 docReadyEvent = new Roo.util.Event();
5820 if(Roo.isGecko || Roo.isOpera) {
5821 document.addEventListener("DOMContentLoaded", fireDocReady, false);
5823 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
5824 var defer = document.getElementById("ie-deferred-loader");
5825 defer.onreadystatechange = function(){
5826 if(this.readyState == "complete"){
5830 }else if(Roo.isSafari){
5831 docReadyProcId = setInterval(function(){
5832 var rs = document.readyState;
5833 if(rs == "complete") {
5838 // no matter what, make sure it fires on load
5839 E.on(window, "load", fireDocReady);
5842 var createBuffered = function(h, o){
5843 var task = new Roo.util.DelayedTask(h);
5845 // create new event object impl so new events don't wipe out properties
5846 e = new Roo.EventObjectImpl(e);
5847 task.delay(o.buffer, h, null, [e]);
5851 var createSingle = function(h, el, ename, fn){
5853 Roo.EventManager.removeListener(el, ename, fn);
5858 var createDelayed = function(h, o){
5860 // create new event object impl so new events don't wipe out properties
5861 e = new Roo.EventObjectImpl(e);
5862 setTimeout(function(){
5868 var listen = function(element, ename, opt, fn, scope){
5869 var o = (!opt || typeof opt == "boolean") ? {} : opt;
5870 fn = fn || o.fn; scope = scope || o.scope;
5871 var el = Roo.getDom(element);
5873 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
5875 var h = function(e){
5876 e = Roo.EventObject.setEvent(e);
5879 t = e.getTarget(o.delegate, el);
5886 if(o.stopEvent === true){
5889 if(o.preventDefault === true){
5892 if(o.stopPropagation === true){
5893 e.stopPropagation();
5896 if(o.normalized === false){
5900 fn.call(scope || el, e, t, o);
5903 h = createDelayed(h, o);
5906 h = createSingle(h, el, ename, fn);
5909 h = createBuffered(h, o);
5911 fn._handlers = fn._handlers || [];
5912 fn._handlers.push([Roo.id(el), ename, h]);
5915 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
5916 el.addEventListener("DOMMouseScroll", h, false);
5917 E.on(window, 'unload', function(){
5918 el.removeEventListener("DOMMouseScroll", h, false);
5921 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5922 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
5927 var stopListening = function(el, ename, fn){
5928 var id = Roo.id(el), hds = fn._handlers, hd = fn;
5930 for(var i = 0, len = hds.length; i < len; i++){
5932 if(h[0] == id && h[1] == ename){
5939 E.un(el, ename, hd);
5940 el = Roo.getDom(el);
5941 if(ename == "mousewheel" && el.addEventListener){
5942 el.removeEventListener("DOMMouseScroll", hd, false);
5944 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
5945 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
5949 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
5956 * @scope Roo.EventManager
5961 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
5962 * object with a Roo.EventObject
5963 * @param {Function} fn The method the event invokes
5964 * @param {Object} scope An object that becomes the scope of the handler
5965 * @param {boolean} override If true, the obj passed in becomes
5966 * the execution scope of the listener
5967 * @return {Function} The wrapped function
5970 wrap : function(fn, scope, override){
5972 Roo.EventObject.setEvent(e);
5973 fn.call(override ? scope || window : window, Roo.EventObject, scope);
5978 * Appends an event handler to an element (shorthand for addListener)
5979 * @param {String/HTMLElement} element The html element or id to assign the
5980 * @param {String} eventName The type of event to listen for
5981 * @param {Function} handler The method the event invokes
5982 * @param {Object} scope (optional) The scope in which to execute the handler
5983 * function. The handler function's "this" context.
5984 * @param {Object} options (optional) An object containing handler configuration
5985 * properties. This may contain any of the following properties:<ul>
5986 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5987 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
5988 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
5989 * <li>preventDefault {Boolean} True to prevent the default action</li>
5990 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
5991 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
5992 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5993 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5994 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5995 * by the specified number of milliseconds. If the event fires again within that time, the original
5996 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5999 * <b>Combining Options</b><br>
6000 * Using the options argument, it is possible to combine different types of listeners:<br>
6002 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6004 el.on('click', this.onClick, this, {
6011 * <b>Attaching multiple handlers in 1 call</b><br>
6012 * The method also allows for a single argument to be passed which is a config object containing properties
6013 * which specify multiple handlers.
6023 fn: this.onMouseOver
6032 * Or a shorthand syntax:<br>
6035 'click' : this.onClick,
6036 'mouseover' : this.onMouseOver,
6037 'mouseout' : this.onMouseOut
6041 addListener : function(element, eventName, fn, scope, options){
6042 if(typeof eventName == "object"){
6048 if(typeof o[e] == "function"){
6050 listen(element, e, o, o[e], o.scope);
6052 // individual options
6053 listen(element, e, o[e]);
6058 return listen(element, eventName, options, fn, scope);
6062 * Removes an event handler
6064 * @param {String/HTMLElement} element The id or html element to remove the
6066 * @param {String} eventName The type of event
6067 * @param {Function} fn
6068 * @return {Boolean} True if a listener was actually removed
6070 removeListener : function(element, eventName, fn){
6071 return stopListening(element, eventName, fn);
6075 * Fires when the document is ready (before onload and before images are loaded). Can be
6076 * accessed shorthanded Roo.onReady().
6077 * @param {Function} fn The method the event invokes
6078 * @param {Object} scope An object that becomes the scope of the handler
6079 * @param {boolean} options
6081 onDocumentReady : function(fn, scope, options){
6082 if(docReadyState){ // if it already fired
6083 docReadyEvent.addListener(fn, scope, options);
6084 docReadyEvent.fire();
6085 docReadyEvent.clearListeners();
6091 docReadyEvent.addListener(fn, scope, options);
6095 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6096 * @param {Function} fn The method the event invokes
6097 * @param {Object} scope An object that becomes the scope of the handler
6098 * @param {boolean} options
6100 onWindowResize : function(fn, scope, options){
6102 resizeEvent = new Roo.util.Event();
6103 resizeTask = new Roo.util.DelayedTask(function(){
6104 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6106 E.on(window, "resize", function(){
6108 resizeTask.delay(50);
6110 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6114 resizeEvent.addListener(fn, scope, options);
6118 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6119 * @param {Function} fn The method the event invokes
6120 * @param {Object} scope An object that becomes the scope of the handler
6121 * @param {boolean} options
6123 onTextResize : function(fn, scope, options){
6125 textEvent = new Roo.util.Event();
6126 var textEl = new Roo.Element(document.createElement('div'));
6127 textEl.dom.className = 'x-text-resize';
6128 textEl.dom.innerHTML = 'X';
6129 textEl.appendTo(document.body);
6130 textSize = textEl.dom.offsetHeight;
6131 setInterval(function(){
6132 if(textEl.dom.offsetHeight != textSize){
6133 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6135 }, this.textResizeInterval);
6137 textEvent.addListener(fn, scope, options);
6141 * Removes the passed window resize listener.
6142 * @param {Function} fn The method the event invokes
6143 * @param {Object} scope The scope of handler
6145 removeResizeListener : function(fn, scope){
6147 resizeEvent.removeListener(fn, scope);
6152 fireResize : function(){
6154 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6158 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6162 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6164 textResizeInterval : 50
6169 * @scopeAlias pub=Roo.EventManager
6173 * Appends an event handler to an element (shorthand for addListener)
6174 * @param {String/HTMLElement} element The html element or id to assign the
6175 * @param {String} eventName The type of event to listen for
6176 * @param {Function} handler The method the event invokes
6177 * @param {Object} scope (optional) The scope in which to execute the handler
6178 * function. The handler function's "this" context.
6179 * @param {Object} options (optional) An object containing handler configuration
6180 * properties. This may contain any of the following properties:<ul>
6181 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6182 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6183 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6184 * <li>preventDefault {Boolean} True to prevent the default action</li>
6185 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6186 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6187 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6188 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6189 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6190 * by the specified number of milliseconds. If the event fires again within that time, the original
6191 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6194 * <b>Combining Options</b><br>
6195 * Using the options argument, it is possible to combine different types of listeners:<br>
6197 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6199 el.on('click', this.onClick, this, {
6206 * <b>Attaching multiple handlers in 1 call</b><br>
6207 * The method also allows for a single argument to be passed which is a config object containing properties
6208 * which specify multiple handlers.
6218 fn: this.onMouseOver
6227 * Or a shorthand syntax:<br>
6230 'click' : this.onClick,
6231 'mouseover' : this.onMouseOver,
6232 'mouseout' : this.onMouseOut
6236 pub.on = pub.addListener;
6237 pub.un = pub.removeListener;
6239 pub.stoppedMouseDownEvent = new Roo.util.Event();
6243 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6244 * @param {Function} fn The method the event invokes
6245 * @param {Object} scope An object that becomes the scope of the handler
6246 * @param {boolean} override If true, the obj passed in becomes
6247 * the execution scope of the listener
6251 Roo.onReady = Roo.EventManager.onDocumentReady;
6253 Roo.onReady(function(){
6254 var bd = Roo.get(document.body);
6259 : Roo.isGecko ? "roo-gecko"
6260 : Roo.isOpera ? "roo-opera"
6261 : Roo.isSafari ? "roo-safari" : ""];
6264 cls.push("roo-mac");
6267 cls.push("roo-linux");
6269 if(Roo.isBorderBox){
6270 cls.push('roo-border-box');
6272 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6273 var p = bd.dom.parentNode;
6275 p.className += ' roo-strict';
6278 bd.addClass(cls.join(' '));
6282 * @class Roo.EventObject
6283 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6284 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6287 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6289 var target = e.getTarget();
6292 var myDiv = Roo.get("myDiv");
6293 myDiv.on("click", handleClick);
6295 Roo.EventManager.on("myDiv", 'click', handleClick);
6296 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6300 Roo.EventObject = function(){
6302 var E = Roo.lib.Event;
6304 // safari keypress events for special keys return bad keycodes
6307 63235 : 39, // right
6310 63276 : 33, // page up
6311 63277 : 34, // page down
6312 63272 : 46, // delete
6317 // normalize button clicks
6318 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6319 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6321 Roo.EventObjectImpl = function(e){
6323 this.setEvent(e.browserEvent || e);
6326 Roo.EventObjectImpl.prototype = {
6328 * Used to fix doc tools.
6329 * @scope Roo.EventObject.prototype
6335 /** The normal browser event */
6336 browserEvent : null,
6337 /** The button pressed in a mouse event */
6339 /** True if the shift key was down during the event */
6341 /** True if the control key was down during the event */
6343 /** True if the alt key was down during the event */
6402 setEvent : function(e){
6403 if(e == this || (e && e.browserEvent)){ // already wrapped
6406 this.browserEvent = e;
6408 // normalize buttons
6409 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6410 if(e.type == 'click' && this.button == -1){
6414 this.shiftKey = e.shiftKey;
6415 // mac metaKey behaves like ctrlKey
6416 this.ctrlKey = e.ctrlKey || e.metaKey;
6417 this.altKey = e.altKey;
6418 // in getKey these will be normalized for the mac
6419 this.keyCode = e.keyCode;
6420 // keyup warnings on firefox.
6421 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6422 // cache the target for the delayed and or buffered events
6423 this.target = E.getTarget(e);
6425 this.xy = E.getXY(e);
6428 this.shiftKey = false;
6429 this.ctrlKey = false;
6430 this.altKey = false;
6440 * Stop the event (preventDefault and stopPropagation)
6442 stopEvent : function(){
6443 if(this.browserEvent){
6444 if(this.browserEvent.type == 'mousedown'){
6445 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6447 E.stopEvent(this.browserEvent);
6452 * Prevents the browsers default handling of the event.
6454 preventDefault : function(){
6455 if(this.browserEvent){
6456 E.preventDefault(this.browserEvent);
6461 isNavKeyPress : function(){
6462 var k = this.keyCode;
6463 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6464 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6467 isSpecialKey : function(){
6468 var k = this.keyCode;
6469 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6470 (k == 16) || (k == 17) ||
6471 (k >= 18 && k <= 20) ||
6472 (k >= 33 && k <= 35) ||
6473 (k >= 36 && k <= 39) ||
6474 (k >= 44 && k <= 45);
6477 * Cancels bubbling of the event.
6479 stopPropagation : function(){
6480 if(this.browserEvent){
6481 if(this.type == 'mousedown'){
6482 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6484 E.stopPropagation(this.browserEvent);
6489 * Gets the key code for the event.
6492 getCharCode : function(){
6493 return this.charCode || this.keyCode;
6497 * Returns a normalized keyCode for the event.
6498 * @return {Number} The key code
6500 getKey : function(){
6501 var k = this.keyCode || this.charCode;
6502 return Roo.isSafari ? (safariKeys[k] || k) : k;
6506 * Gets the x coordinate of the event.
6509 getPageX : function(){
6514 * Gets the y coordinate of the event.
6517 getPageY : function(){
6522 * Gets the time of the event.
6525 getTime : function(){
6526 if(this.browserEvent){
6527 return E.getTime(this.browserEvent);
6533 * Gets the page coordinates of the event.
6534 * @return {Array} The xy values like [x, y]
6541 * Gets the target for the event.
6542 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6543 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6544 search as a number or element (defaults to 10 || document.body)
6545 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6546 * @return {HTMLelement}
6548 getTarget : function(selector, maxDepth, returnEl){
6549 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6552 * Gets the related target.
6553 * @return {HTMLElement}
6555 getRelatedTarget : function(){
6556 if(this.browserEvent){
6557 return E.getRelatedTarget(this.browserEvent);
6563 * Normalizes mouse wheel delta across browsers
6564 * @return {Number} The delta
6566 getWheelDelta : function(){
6567 var e = this.browserEvent;
6569 if(e.wheelDelta){ /* IE/Opera. */
6570 delta = e.wheelDelta/120;
6571 }else if(e.detail){ /* Mozilla case. */
6572 delta = -e.detail/3;
6578 * Returns true if the control, meta, shift or alt key was pressed during this event.
6581 hasModifier : function(){
6582 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6586 * Returns true if the target of this event equals el or is a child of el
6587 * @param {String/HTMLElement/Element} el
6588 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6591 within : function(el, related){
6592 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6593 return t && Roo.fly(el).contains(t);
6596 getPoint : function(){
6597 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6601 return new Roo.EventObjectImpl();
6606 * Ext JS Library 1.1.1
6607 * Copyright(c) 2006-2007, Ext JS, LLC.
6609 * Originally Released Under LGPL - original licence link has changed is not relivant.
6612 * <script type="text/javascript">
6616 // was in Composite Element!??!?!
6619 var D = Roo.lib.Dom;
6620 var E = Roo.lib.Event;
6621 var A = Roo.lib.Anim;
6623 // local style camelizing for speed
6625 var camelRe = /(-[a-z])/gi;
6626 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6627 var view = document.defaultView;
6630 * @class Roo.Element
6631 * Represents an Element in the DOM.<br><br>
6634 var el = Roo.get("my-div");
6637 var el = getEl("my-div");
6639 // or with a DOM element
6640 var el = Roo.get(myDivElement);
6642 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6643 * each call instead of constructing a new one.<br><br>
6644 * <b>Animations</b><br />
6645 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6646 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6648 Option Default Description
6649 --------- -------- ---------------------------------------------
6650 duration .35 The duration of the animation in seconds
6651 easing easeOut The YUI easing method
6652 callback none A function to execute when the anim completes
6653 scope this The scope (this) of the callback function
6655 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6656 * manipulate the animation. Here's an example:
6658 var el = Roo.get("my-div");
6663 // default animation
6664 el.setWidth(100, true);
6666 // animation with some options set
6673 // using the "anim" property to get the Anim object
6679 el.setWidth(100, opt);
6681 if(opt.anim.isAnimated()){
6685 * <b> Composite (Collections of) Elements</b><br />
6686 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6687 * @constructor Create a new Element directly.
6688 * @param {String/HTMLElement} element
6689 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6691 Roo.Element = function(element, forceNew){
6692 var dom = typeof element == "string" ?
6693 document.getElementById(element) : element;
6694 if(!dom){ // invalid id/element
6698 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6699 return Roo.Element.cache[id];
6709 * The DOM element ID
6712 this.id = id || Roo.id(dom);
6715 var El = Roo.Element;
6719 * The element's default display mode (defaults to "")
6722 originalDisplay : "",
6726 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6731 * Sets the element's visibility mode. When setVisible() is called it
6732 * will use this to determine whether to set the visibility or the display property.
6733 * @param visMode Element.VISIBILITY or Element.DISPLAY
6734 * @return {Roo.Element} this
6736 setVisibilityMode : function(visMode){
6737 this.visibilityMode = visMode;
6741 * Convenience method for setVisibilityMode(Element.DISPLAY)
6742 * @param {String} display (optional) What to set display to when visible
6743 * @return {Roo.Element} this
6745 enableDisplayMode : function(display){
6746 this.setVisibilityMode(El.DISPLAY);
6747 if(typeof display != "undefined") this.originalDisplay = display;
6752 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6753 * @param {String} selector The simple selector to test
6754 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6755 search as a number or element (defaults to 10 || document.body)
6756 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6757 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6759 findParent : function(simpleSelector, maxDepth, returnEl){
6760 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6761 maxDepth = maxDepth || 50;
6762 if(typeof maxDepth != "number"){
6763 stopEl = Roo.getDom(maxDepth);
6766 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6767 if(dq.is(p, simpleSelector)){
6768 return returnEl ? Roo.get(p) : p;
6778 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6779 * @param {String} selector The simple selector to test
6780 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6781 search as a number or element (defaults to 10 || document.body)
6782 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6783 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6785 findParentNode : function(simpleSelector, maxDepth, returnEl){
6786 var p = Roo.fly(this.dom.parentNode, '_internal');
6787 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
6791 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
6792 * This is a shortcut for findParentNode() that always returns an Roo.Element.
6793 * @param {String} selector The simple selector to test
6794 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6795 search as a number or element (defaults to 10 || document.body)
6796 * @return {Roo.Element} The matching DOM node (or null if no match was found)
6798 up : function(simpleSelector, maxDepth){
6799 return this.findParentNode(simpleSelector, maxDepth, true);
6805 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
6806 * @param {String} selector The simple selector to test
6807 * @return {Boolean} True if this element matches the selector, else false
6809 is : function(simpleSelector){
6810 return Roo.DomQuery.is(this.dom, simpleSelector);
6814 * Perform animation on this element.
6815 * @param {Object} args The YUI animation control args
6816 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
6817 * @param {Function} onComplete (optional) Function to call when animation completes
6818 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
6819 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
6820 * @return {Roo.Element} this
6822 animate : function(args, duration, onComplete, easing, animType){
6823 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
6828 * @private Internal animation call
6830 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
6831 animType = animType || 'run';
6833 var anim = Roo.lib.Anim[animType](
6835 (opt.duration || defaultDur) || .35,
6836 (opt.easing || defaultEase) || 'easeOut',
6838 Roo.callback(cb, this);
6839 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
6847 // private legacy anim prep
6848 preanim : function(a, i){
6849 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
6853 * Removes worthless text nodes
6854 * @param {Boolean} forceReclean (optional) By default the element
6855 * keeps track if it has been cleaned already so
6856 * you can call this over and over. However, if you update the element and
6857 * need to force a reclean, you can pass true.
6859 clean : function(forceReclean){
6860 if(this.isCleaned && forceReclean !== true){
6864 var d = this.dom, n = d.firstChild, ni = -1;
6866 var nx = n.nextSibling;
6867 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
6874 this.isCleaned = true;
6879 calcOffsetsTo : function(el){
6882 var restorePos = false;
6883 if(el.getStyle('position') == 'static'){
6884 el.position('relative');
6889 while(op && op != d && op.tagName != 'HTML'){
6892 op = op.offsetParent;
6895 el.position('static');
6901 * Scrolls this element into view within the passed container.
6902 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
6903 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
6904 * @return {Roo.Element} this
6906 scrollIntoView : function(container, hscroll){
6907 var c = Roo.getDom(container) || document.body;
6910 var o = this.calcOffsetsTo(c),
6913 b = t+el.offsetHeight,
6914 r = l+el.offsetWidth;
6916 var ch = c.clientHeight;
6917 var ct = parseInt(c.scrollTop, 10);
6918 var cl = parseInt(c.scrollLeft, 10);
6920 var cr = cl + c.clientWidth;
6928 if(hscroll !== false){
6932 c.scrollLeft = r-c.clientWidth;
6939 scrollChildIntoView : function(child, hscroll){
6940 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
6944 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
6945 * the new height may not be available immediately.
6946 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
6947 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
6948 * @param {Function} onComplete (optional) Function to call when animation completes
6949 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
6950 * @return {Roo.Element} this
6952 autoHeight : function(animate, duration, onComplete, easing){
6953 var oldHeight = this.getHeight();
6955 this.setHeight(1); // force clipping
6956 setTimeout(function(){
6957 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
6959 this.setHeight(height);
6961 if(typeof onComplete == "function"){
6965 this.setHeight(oldHeight); // restore original height
6966 this.setHeight(height, animate, duration, function(){
6968 if(typeof onComplete == "function") onComplete();
6969 }.createDelegate(this), easing);
6971 }.createDelegate(this), 0);
6976 * Returns true if this element is an ancestor of the passed element
6977 * @param {HTMLElement/String} el The element to check
6978 * @return {Boolean} True if this element is an ancestor of el, else false
6980 contains : function(el){
6981 if(!el){return false;}
6982 return D.isAncestor(this.dom, el.dom ? el.dom : el);
6986 * Checks whether the element is currently visible using both visibility and display properties.
6987 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
6988 * @return {Boolean} True if the element is currently visible, else false
6990 isVisible : function(deep) {
6991 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
6992 if(deep !== true || !vis){
6995 var p = this.dom.parentNode;
6996 while(p && p.tagName.toLowerCase() != "body"){
6997 if(!Roo.fly(p, '_isVisible').isVisible()){
7006 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7007 * @param {String} selector The CSS selector
7008 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7009 * @return {CompositeElement/CompositeElementLite} The composite element
7011 select : function(selector, unique){
7012 return El.select(selector, unique, this.dom);
7016 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7017 * @param {String} selector The CSS selector
7018 * @return {Array} An array of the matched nodes
7020 query : function(selector, unique){
7021 return Roo.DomQuery.select(selector, this.dom);
7025 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7026 * @param {String} selector The CSS selector
7027 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7028 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7030 child : function(selector, returnDom){
7031 var n = Roo.DomQuery.selectNode(selector, this.dom);
7032 return returnDom ? n : Roo.get(n);
7036 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7037 * @param {String} selector The CSS selector
7038 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7039 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7041 down : function(selector, returnDom){
7042 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7043 return returnDom ? n : Roo.get(n);
7047 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7048 * @param {String} group The group the DD object is member of
7049 * @param {Object} config The DD config object
7050 * @param {Object} overrides An object containing methods to override/implement on the DD object
7051 * @return {Roo.dd.DD} The DD object
7053 initDD : function(group, config, overrides){
7054 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7055 return Roo.apply(dd, overrides);
7059 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7060 * @param {String} group The group the DDProxy object is member of
7061 * @param {Object} config The DDProxy config object
7062 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7063 * @return {Roo.dd.DDProxy} The DDProxy object
7065 initDDProxy : function(group, config, overrides){
7066 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7067 return Roo.apply(dd, overrides);
7071 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7072 * @param {String} group The group the DDTarget object is member of
7073 * @param {Object} config The DDTarget config object
7074 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7075 * @return {Roo.dd.DDTarget} The DDTarget object
7077 initDDTarget : function(group, config, overrides){
7078 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7079 return Roo.apply(dd, overrides);
7083 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7084 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7085 * @param {Boolean} visible Whether the element is visible
7086 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7087 * @return {Roo.Element} this
7089 setVisible : function(visible, animate){
7091 if(this.visibilityMode == El.DISPLAY){
7092 this.setDisplayed(visible);
7095 this.dom.style.visibility = visible ? "visible" : "hidden";
7098 // closure for composites
7100 var visMode = this.visibilityMode;
7102 this.setOpacity(.01);
7103 this.setVisible(true);
7105 this.anim({opacity: { to: (visible?1:0) }},
7106 this.preanim(arguments, 1),
7107 null, .35, 'easeIn', function(){
7109 if(visMode == El.DISPLAY){
7110 dom.style.display = "none";
7112 dom.style.visibility = "hidden";
7114 Roo.get(dom).setOpacity(1);
7122 * Returns true if display is not "none"
7125 isDisplayed : function() {
7126 return this.getStyle("display") != "none";
7130 * Toggles the element's visibility or display, depending on visibility mode.
7131 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7132 * @return {Roo.Element} this
7134 toggle : function(animate){
7135 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7140 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7141 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7142 * @return {Roo.Element} this
7144 setDisplayed : function(value) {
7145 if(typeof value == "boolean"){
7146 value = value ? this.originalDisplay : "none";
7148 this.setStyle("display", value);
7153 * Tries to focus the element. Any exceptions are caught and ignored.
7154 * @return {Roo.Element} this
7156 focus : function() {
7164 * Tries to blur the element. Any exceptions are caught and ignored.
7165 * @return {Roo.Element} this
7175 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7176 * @param {String/Array} className The CSS class to add, or an array of classes
7177 * @return {Roo.Element} this
7179 addClass : function(className){
7180 if(className instanceof Array){
7181 for(var i = 0, len = className.length; i < len; i++) {
7182 this.addClass(className[i]);
7185 if(className && !this.hasClass(className)){
7186 this.dom.className = this.dom.className + " " + className;
7193 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7194 * @param {String/Array} className The CSS class to add, or an array of classes
7195 * @return {Roo.Element} this
7197 radioClass : function(className){
7198 var siblings = this.dom.parentNode.childNodes;
7199 for(var i = 0; i < siblings.length; i++) {
7200 var s = siblings[i];
7201 if(s.nodeType == 1){
7202 Roo.get(s).removeClass(className);
7205 this.addClass(className);
7210 * Removes one or more CSS classes from the element.
7211 * @param {String/Array} className The CSS class to remove, or an array of classes
7212 * @return {Roo.Element} this
7214 removeClass : function(className){
7215 if(!className || !this.dom.className){
7218 if(className instanceof Array){
7219 for(var i = 0, len = className.length; i < len; i++) {
7220 this.removeClass(className[i]);
7223 if(this.hasClass(className)){
7224 var re = this.classReCache[className];
7226 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7227 this.classReCache[className] = re;
7229 this.dom.className =
7230 this.dom.className.replace(re, " ");
7240 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7241 * @param {String} className The CSS class to toggle
7242 * @return {Roo.Element} this
7244 toggleClass : function(className){
7245 if(this.hasClass(className)){
7246 this.removeClass(className);
7248 this.addClass(className);
7254 * Checks if the specified CSS class exists on this element's DOM node.
7255 * @param {String} className The CSS class to check for
7256 * @return {Boolean} True if the class exists, else false
7258 hasClass : function(className){
7259 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7263 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7264 * @param {String} oldClassName The CSS class to replace
7265 * @param {String} newClassName The replacement CSS class
7266 * @return {Roo.Element} this
7268 replaceClass : function(oldClassName, newClassName){
7269 this.removeClass(oldClassName);
7270 this.addClass(newClassName);
7275 * Returns an object with properties matching the styles requested.
7276 * For example, el.getStyles('color', 'font-size', 'width') might return
7277 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7278 * @param {String} style1 A style name
7279 * @param {String} style2 A style name
7280 * @param {String} etc.
7281 * @return {Object} The style object
7283 getStyles : function(){
7284 var a = arguments, len = a.length, r = {};
7285 for(var i = 0; i < len; i++){
7286 r[a[i]] = this.getStyle(a[i]);
7292 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7293 * @param {String} property The style property whose value is returned.
7294 * @return {String} The current value of the style property for this element.
7296 getStyle : function(){
7297 return view && view.getComputedStyle ?
7299 var el = this.dom, v, cs, camel;
7300 if(prop == 'float'){
7303 if(el.style && (v = el.style[prop])){
7306 if(cs = view.getComputedStyle(el, "")){
7307 if(!(camel = propCache[prop])){
7308 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7315 var el = this.dom, v, cs, camel;
7316 if(prop == 'opacity'){
7317 if(typeof el.style.filter == 'string'){
7318 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7320 var fv = parseFloat(m[1]);
7322 return fv ? fv / 100 : 0;
7327 }else if(prop == 'float'){
7328 prop = "styleFloat";
7330 if(!(camel = propCache[prop])){
7331 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7333 if(v = el.style[camel]){
7336 if(cs = el.currentStyle){
7344 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7345 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7346 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7347 * @return {Roo.Element} this
7349 setStyle : function(prop, value){
7350 if(typeof prop == "string"){
7352 if(!(camel = propCache[prop])){
7353 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7355 if(camel == 'opacity') {
7356 this.setOpacity(value);
7358 this.dom.style[camel] = value;
7361 for(var style in prop){
7362 if(typeof prop[style] != "function"){
7363 this.setStyle(style, prop[style]);
7371 * More flexible version of {@link #setStyle} for setting style properties.
7372 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7373 * a function which returns such a specification.
7374 * @return {Roo.Element} this
7376 applyStyles : function(style){
7377 Roo.DomHelper.applyStyles(this.dom, style);
7382 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7383 * @return {Number} The X position of the element
7386 return D.getX(this.dom);
7390 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7391 * @return {Number} The Y position of the element
7394 return D.getY(this.dom);
7398 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7399 * @return {Array} The XY position of the element
7402 return D.getXY(this.dom);
7406 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7407 * @param {Number} The X position of the element
7408 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7409 * @return {Roo.Element} this
7411 setX : function(x, animate){
7413 D.setX(this.dom, x);
7415 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7421 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7422 * @param {Number} The Y position of the element
7423 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7424 * @return {Roo.Element} this
7426 setY : function(y, animate){
7428 D.setY(this.dom, y);
7430 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7436 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7437 * @param {String} left The left CSS property value
7438 * @return {Roo.Element} this
7440 setLeft : function(left){
7441 this.setStyle("left", this.addUnits(left));
7446 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7447 * @param {String} top The top CSS property value
7448 * @return {Roo.Element} this
7450 setTop : function(top){
7451 this.setStyle("top", this.addUnits(top));
7456 * Sets the element's CSS right style.
7457 * @param {String} right The right CSS property value
7458 * @return {Roo.Element} this
7460 setRight : function(right){
7461 this.setStyle("right", this.addUnits(right));
7466 * Sets the element's CSS bottom style.
7467 * @param {String} bottom The bottom CSS property value
7468 * @return {Roo.Element} this
7470 setBottom : function(bottom){
7471 this.setStyle("bottom", this.addUnits(bottom));
7476 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7477 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7478 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7479 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7480 * @return {Roo.Element} this
7482 setXY : function(pos, animate){
7484 D.setXY(this.dom, pos);
7486 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7492 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7493 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7494 * @param {Number} x X value for new position (coordinates are page-based)
7495 * @param {Number} y Y value for new position (coordinates are page-based)
7496 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7497 * @return {Roo.Element} this
7499 setLocation : function(x, y, animate){
7500 this.setXY([x, y], this.preanim(arguments, 2));
7505 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7506 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7507 * @param {Number} x X value for new position (coordinates are page-based)
7508 * @param {Number} y Y value for new position (coordinates are page-based)
7509 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7510 * @return {Roo.Element} this
7512 moveTo : function(x, y, animate){
7513 this.setXY([x, y], this.preanim(arguments, 2));
7518 * Returns the region of the given element.
7519 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7520 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7522 getRegion : function(){
7523 return D.getRegion(this.dom);
7527 * Returns the offset height of the element
7528 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7529 * @return {Number} The element's height
7531 getHeight : function(contentHeight){
7532 var h = this.dom.offsetHeight || 0;
7533 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7537 * Returns the offset width of the element
7538 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7539 * @return {Number} The element's width
7541 getWidth : function(contentWidth){
7542 var w = this.dom.offsetWidth || 0;
7543 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7547 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7548 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7549 * if a height has not been set using CSS.
7552 getComputedHeight : function(){
7553 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7555 h = parseInt(this.getStyle('height'), 10) || 0;
7556 if(!this.isBorderBox()){
7557 h += this.getFrameWidth('tb');
7564 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7565 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7566 * if a width has not been set using CSS.
7569 getComputedWidth : function(){
7570 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7572 w = parseInt(this.getStyle('width'), 10) || 0;
7573 if(!this.isBorderBox()){
7574 w += this.getFrameWidth('lr');
7581 * Returns the size of the element.
7582 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7583 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7585 getSize : function(contentSize){
7586 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7590 * Returns the width and height of the viewport.
7591 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7593 getViewSize : function(){
7594 var d = this.dom, doc = document, aw = 0, ah = 0;
7595 if(d == doc || d == doc.body){
7596 return {width : D.getViewWidth(), height: D.getViewHeight()};
7599 width : d.clientWidth,
7600 height: d.clientHeight
7606 * Returns the value of the "value" attribute
7607 * @param {Boolean} asNumber true to parse the value as a number
7608 * @return {String/Number}
7610 getValue : function(asNumber){
7611 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7615 adjustWidth : function(width){
7616 if(typeof width == "number"){
7617 if(this.autoBoxAdjust && !this.isBorderBox()){
7618 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7628 adjustHeight : function(height){
7629 if(typeof height == "number"){
7630 if(this.autoBoxAdjust && !this.isBorderBox()){
7631 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7641 * Set the width of the element
7642 * @param {Number} width The new width
7643 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7644 * @return {Roo.Element} this
7646 setWidth : function(width, animate){
7647 width = this.adjustWidth(width);
7649 this.dom.style.width = this.addUnits(width);
7651 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7657 * Set the height of the element
7658 * @param {Number} height The new height
7659 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7660 * @return {Roo.Element} this
7662 setHeight : function(height, animate){
7663 height = this.adjustHeight(height);
7665 this.dom.style.height = this.addUnits(height);
7667 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7673 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7674 * @param {Number} width The new width
7675 * @param {Number} height The new height
7676 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7677 * @return {Roo.Element} this
7679 setSize : function(width, height, animate){
7680 if(typeof width == "object"){ // in case of object from getSize()
7681 height = width.height; width = width.width;
7683 width = this.adjustWidth(width); height = this.adjustHeight(height);
7685 this.dom.style.width = this.addUnits(width);
7686 this.dom.style.height = this.addUnits(height);
7688 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7694 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7695 * @param {Number} x X value for new position (coordinates are page-based)
7696 * @param {Number} y Y value for new position (coordinates are page-based)
7697 * @param {Number} width The new width
7698 * @param {Number} height The new height
7699 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7700 * @return {Roo.Element} this
7702 setBounds : function(x, y, width, height, animate){
7704 this.setSize(width, height);
7705 this.setLocation(x, y);
7707 width = this.adjustWidth(width); height = this.adjustHeight(height);
7708 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7709 this.preanim(arguments, 4), 'motion');
7715 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7716 * @param {Roo.lib.Region} region The region to fill
7717 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7718 * @return {Roo.Element} this
7720 setRegion : function(region, animate){
7721 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7726 * Appends an event handler
7728 * @param {String} eventName The type of event to append
7729 * @param {Function} fn The method the event invokes
7730 * @param {Object} scope (optional) The scope (this object) of the fn
7731 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7733 addListener : function(eventName, fn, scope, options){
7734 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7738 * Removes an event handler from this element
7739 * @param {String} eventName the type of event to remove
7740 * @param {Function} fn the method the event invokes
7741 * @return {Roo.Element} this
7743 removeListener : function(eventName, fn){
7744 Roo.EventManager.removeListener(this.dom, eventName, fn);
7749 * Removes all previous added listeners from this element
7750 * @return {Roo.Element} this
7752 removeAllListeners : function(){
7753 E.purgeElement(this.dom);
7757 relayEvent : function(eventName, observable){
7758 this.on(eventName, function(e){
7759 observable.fireEvent(eventName, e);
7764 * Set the opacity of the element
7765 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
7766 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7767 * @return {Roo.Element} this
7769 setOpacity : function(opacity, animate){
7771 var s = this.dom.style;
7774 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
7775 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
7777 s.opacity = opacity;
7780 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
7786 * Gets the left X coordinate
7787 * @param {Boolean} local True to get the local css position instead of page coordinate
7790 getLeft : function(local){
7794 return parseInt(this.getStyle("left"), 10) || 0;
7799 * Gets the right X coordinate of the element (element X position + element width)
7800 * @param {Boolean} local True to get the local css position instead of page coordinate
7803 getRight : function(local){
7805 return this.getX() + this.getWidth();
7807 return (this.getLeft(true) + this.getWidth()) || 0;
7812 * Gets the top Y coordinate
7813 * @param {Boolean} local True to get the local css position instead of page coordinate
7816 getTop : function(local) {
7820 return parseInt(this.getStyle("top"), 10) || 0;
7825 * Gets the bottom Y coordinate of the element (element Y position + element height)
7826 * @param {Boolean} local True to get the local css position instead of page coordinate
7829 getBottom : function(local){
7831 return this.getY() + this.getHeight();
7833 return (this.getTop(true) + this.getHeight()) || 0;
7838 * Initializes positioning on this element. If a desired position is not passed, it will make the
7839 * the element positioned relative IF it is not already positioned.
7840 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
7841 * @param {Number} zIndex (optional) The zIndex to apply
7842 * @param {Number} x (optional) Set the page X position
7843 * @param {Number} y (optional) Set the page Y position
7845 position : function(pos, zIndex, x, y){
7847 if(this.getStyle('position') == 'static'){
7848 this.setStyle('position', 'relative');
7851 this.setStyle("position", pos);
7854 this.setStyle("z-index", zIndex);
7856 if(x !== undefined && y !== undefined){
7858 }else if(x !== undefined){
7860 }else if(y !== undefined){
7866 * Clear positioning back to the default when the document was loaded
7867 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
7868 * @return {Roo.Element} this
7870 clearPositioning : function(value){
7878 "position" : "static"
7884 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
7885 * snapshot before performing an update and then restoring the element.
7888 getPositioning : function(){
7889 var l = this.getStyle("left");
7890 var t = this.getStyle("top");
7892 "position" : this.getStyle("position"),
7894 "right" : l ? "" : this.getStyle("right"),
7896 "bottom" : t ? "" : this.getStyle("bottom"),
7897 "z-index" : this.getStyle("z-index")
7902 * Gets the width of the border(s) for the specified side(s)
7903 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7904 * passing lr would get the border (l)eft width + the border (r)ight width.
7905 * @return {Number} The width of the sides passed added together
7907 getBorderWidth : function(side){
7908 return this.addStyles(side, El.borders);
7912 * Gets the width of the padding(s) for the specified side(s)
7913 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
7914 * passing lr would get the padding (l)eft + the padding (r)ight.
7915 * @return {Number} The padding of the sides passed added together
7917 getPadding : function(side){
7918 return this.addStyles(side, El.paddings);
7922 * Set positioning with an object returned by getPositioning().
7923 * @param {Object} posCfg
7924 * @return {Roo.Element} this
7926 setPositioning : function(pc){
7927 this.applyStyles(pc);
7928 if(pc.right == "auto"){
7929 this.dom.style.right = "";
7931 if(pc.bottom == "auto"){
7932 this.dom.style.bottom = "";
7938 fixDisplay : function(){
7939 if(this.getStyle("display") == "none"){
7940 this.setStyle("visibility", "hidden");
7941 this.setStyle("display", this.originalDisplay); // first try reverting to default
7942 if(this.getStyle("display") == "none"){ // if that fails, default to block
7943 this.setStyle("display", "block");
7949 * Quick set left and top adding default units
7950 * @param {String} left The left CSS property value
7951 * @param {String} top The top CSS property value
7952 * @return {Roo.Element} this
7954 setLeftTop : function(left, top){
7955 this.dom.style.left = this.addUnits(left);
7956 this.dom.style.top = this.addUnits(top);
7961 * Move this element relative to its current position.
7962 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
7963 * @param {Number} distance How far to move the element in pixels
7964 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7965 * @return {Roo.Element} this
7967 move : function(direction, distance, animate){
7968 var xy = this.getXY();
7969 direction = direction.toLowerCase();
7973 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
7977 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
7982 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
7987 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
7994 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
7995 * @return {Roo.Element} this
7998 if(!this.isClipped){
7999 this.isClipped = true;
8000 this.originalClip = {
8001 "o": this.getStyle("overflow"),
8002 "x": this.getStyle("overflow-x"),
8003 "y": this.getStyle("overflow-y")
8005 this.setStyle("overflow", "hidden");
8006 this.setStyle("overflow-x", "hidden");
8007 this.setStyle("overflow-y", "hidden");
8013 * Return clipping (overflow) to original clipping before clip() was called
8014 * @return {Roo.Element} this
8016 unclip : function(){
8018 this.isClipped = false;
8019 var o = this.originalClip;
8020 if(o.o){this.setStyle("overflow", o.o);}
8021 if(o.x){this.setStyle("overflow-x", o.x);}
8022 if(o.y){this.setStyle("overflow-y", o.y);}
8029 * Gets the x,y coordinates specified by the anchor position on the element.
8030 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8031 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8032 * {width: (target width), height: (target height)} (defaults to the element's current size)
8033 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8034 * @return {Array} [x, y] An array containing the element's x and y coordinates
8036 getAnchorXY : function(anchor, local, s){
8037 //Passing a different size is useful for pre-calculating anchors,
8038 //especially for anchored animations that change the el size.
8040 var w, h, vp = false;
8043 if(d == document.body || d == document){
8045 w = D.getViewWidth(); h = D.getViewHeight();
8047 w = this.getWidth(); h = this.getHeight();
8050 w = s.width; h = s.height;
8052 var x = 0, y = 0, r = Math.round;
8053 switch((anchor || "tl").toLowerCase()){
8095 var sc = this.getScroll();
8096 return [x + sc.left, y + sc.top];
8098 //Add the element's offset xy
8099 var o = this.getXY();
8100 return [x+o[0], y+o[1]];
8104 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8105 * supported position values.
8106 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8107 * @param {String} position The position to align to.
8108 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8109 * @return {Array} [x, y]
8111 getAlignToXY : function(el, p, o){
8115 throw "Element.alignTo with an element that doesn't exist";
8117 var c = false; //constrain to viewport
8118 var p1 = "", p2 = "";
8125 }else if(p.indexOf("-") == -1){
8128 p = p.toLowerCase();
8129 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8131 throw "Element.alignTo with an invalid alignment " + p;
8133 p1 = m[1]; p2 = m[2]; c = !!m[3];
8135 //Subtract the aligned el's internal xy from the target's offset xy
8136 //plus custom offset to get the aligned el's new offset xy
8137 var a1 = this.getAnchorXY(p1, true);
8138 var a2 = el.getAnchorXY(p2, false);
8139 var x = a2[0] - a1[0] + o[0];
8140 var y = a2[1] - a1[1] + o[1];
8142 //constrain the aligned el to viewport if necessary
8143 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8144 // 5px of margin for ie
8145 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8147 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8148 //perpendicular to the vp border, allow the aligned el to slide on that border,
8149 //otherwise swap the aligned el to the opposite border of the target.
8150 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8151 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8152 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8153 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8156 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8157 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8159 if((x+w) > dw + scrollX){
8160 x = swapX ? r.left-w : dw+scrollX-w;
8163 x = swapX ? r.right : scrollX;
8165 if((y+h) > dh + scrollY){
8166 y = swapY ? r.top-h : dh+scrollY-h;
8169 y = swapY ? r.bottom : scrollY;
8176 getConstrainToXY : function(){
8177 var os = {top:0, left:0, bottom:0, right: 0};
8179 return function(el, local, offsets, proposedXY){
8181 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8183 var vw, vh, vx = 0, vy = 0;
8184 if(el.dom == document.body || el.dom == document){
8185 vw = Roo.lib.Dom.getViewWidth();
8186 vh = Roo.lib.Dom.getViewHeight();
8188 vw = el.dom.clientWidth;
8189 vh = el.dom.clientHeight;
8191 var vxy = el.getXY();
8197 var s = el.getScroll();
8199 vx += offsets.left + s.left;
8200 vy += offsets.top + s.top;
8202 vw -= offsets.right;
8203 vh -= offsets.bottom;
8208 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8209 var x = xy[0], y = xy[1];
8210 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8212 // only move it if it needs it
8215 // first validate right/bottom
8224 // then make sure top/left isn't negative
8233 return moved ? [x, y] : false;
8238 adjustForConstraints : function(xy, parent, offsets){
8239 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8243 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8244 * document it aligns it to the viewport.
8245 * The position parameter is optional, and can be specified in any one of the following formats:
8247 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8248 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8249 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8250 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8251 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8252 * element's anchor point, and the second value is used as the target's anchor point.</li>
8254 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8255 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8256 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8257 * that specified in order to enforce the viewport constraints.
8258 * Following are all of the supported anchor positions:
8261 ----- -----------------------------
8262 tl The top left corner (default)
8263 t The center of the top edge
8264 tr The top right corner
8265 l The center of the left edge
8266 c In the center of the element
8267 r The center of the right edge
8268 bl The bottom left corner
8269 b The center of the bottom edge
8270 br The bottom right corner
8274 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8275 el.alignTo("other-el");
8277 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8278 el.alignTo("other-el", "tr?");
8280 // align the bottom right corner of el with the center left edge of other-el
8281 el.alignTo("other-el", "br-l?");
8283 // align the center of el with the bottom left corner of other-el and
8284 // adjust the x position by -6 pixels (and the y position by 0)
8285 el.alignTo("other-el", "c-bl", [-6, 0]);
8287 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8288 * @param {String} position The position to align to.
8289 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8290 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8291 * @return {Roo.Element} this
8293 alignTo : function(element, position, offsets, animate){
8294 var xy = this.getAlignToXY(element, position, offsets);
8295 this.setXY(xy, this.preanim(arguments, 3));
8300 * Anchors an element to another element and realigns it when the window is resized.
8301 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8302 * @param {String} position The position to align to.
8303 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8304 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8305 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8306 * is a number, it is used as the buffer delay (defaults to 50ms).
8307 * @param {Function} callback The function to call after the animation finishes
8308 * @return {Roo.Element} this
8310 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8311 var action = function(){
8312 this.alignTo(el, alignment, offsets, animate);
8313 Roo.callback(callback, this);
8315 Roo.EventManager.onWindowResize(action, this);
8316 var tm = typeof monitorScroll;
8317 if(tm != 'undefined'){
8318 Roo.EventManager.on(window, 'scroll', action, this,
8319 {buffer: tm == 'number' ? monitorScroll : 50});
8321 action.call(this); // align immediately
8325 * Clears any opacity settings from this element. Required in some cases for IE.
8326 * @return {Roo.Element} this
8328 clearOpacity : function(){
8329 if (window.ActiveXObject) {
8330 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8331 this.dom.style.filter = "";
8334 this.dom.style.opacity = "";
8335 this.dom.style["-moz-opacity"] = "";
8336 this.dom.style["-khtml-opacity"] = "";
8342 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8343 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8344 * @return {Roo.Element} this
8346 hide : function(animate){
8347 this.setVisible(false, this.preanim(arguments, 0));
8352 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8353 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8354 * @return {Roo.Element} this
8356 show : function(animate){
8357 this.setVisible(true, this.preanim(arguments, 0));
8362 * @private Test if size has a unit, otherwise appends the default
8364 addUnits : function(size){
8365 return Roo.Element.addUnits(size, this.defaultUnit);
8369 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8370 * @return {Roo.Element} this
8372 beginMeasure : function(){
8374 if(el.offsetWidth || el.offsetHeight){
8375 return this; // offsets work already
8378 var p = this.dom, b = document.body; // start with this element
8379 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8380 var pe = Roo.get(p);
8381 if(pe.getStyle('display') == 'none'){
8382 changed.push({el: p, visibility: pe.getStyle("visibility")});
8383 p.style.visibility = "hidden";
8384 p.style.display = "block";
8388 this._measureChanged = changed;
8394 * Restores displays to before beginMeasure was called
8395 * @return {Roo.Element} this
8397 endMeasure : function(){
8398 var changed = this._measureChanged;
8400 for(var i = 0, len = changed.length; i < len; i++) {
8402 r.el.style.visibility = r.visibility;
8403 r.el.style.display = "none";
8405 this._measureChanged = null;
8411 * Update the innerHTML of this element, optionally searching for and processing scripts
8412 * @param {String} html The new HTML
8413 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8414 * @param {Function} callback For async script loading you can be noticed when the update completes
8415 * @return {Roo.Element} this
8417 update : function(html, loadScripts, callback){
8418 if(typeof html == "undefined"){
8421 if(loadScripts !== true){
8422 this.dom.innerHTML = html;
8423 if(typeof callback == "function"){
8431 html += '<span id="' + id + '"></span>';
8433 E.onAvailable(id, function(){
8434 var hd = document.getElementsByTagName("head")[0];
8435 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8436 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8437 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8440 while(match = re.exec(html)){
8441 var attrs = match[1];
8442 var srcMatch = attrs ? attrs.match(srcRe) : false;
8443 if(srcMatch && srcMatch[2]){
8444 var s = document.createElement("script");
8445 s.src = srcMatch[2];
8446 var typeMatch = attrs.match(typeRe);
8447 if(typeMatch && typeMatch[2]){
8448 s.type = typeMatch[2];
8451 }else if(match[2] && match[2].length > 0){
8452 if(window.execScript) {
8453 window.execScript(match[2]);
8461 window.eval(match[2]);
8465 var el = document.getElementById(id);
8466 if(el){el.parentNode.removeChild(el);}
8467 if(typeof callback == "function"){
8471 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8476 * Direct access to the UpdateManager update() method (takes the same parameters).
8477 * @param {String/Function} url The url for this request or a function to call to get the url
8478 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8479 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8480 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8481 * @return {Roo.Element} this
8484 var um = this.getUpdateManager();
8485 um.update.apply(um, arguments);
8490 * Gets this element's UpdateManager
8491 * @return {Roo.UpdateManager} The UpdateManager
8493 getUpdateManager : function(){
8494 if(!this.updateManager){
8495 this.updateManager = new Roo.UpdateManager(this);
8497 return this.updateManager;
8501 * Disables text selection for this element (normalized across browsers)
8502 * @return {Roo.Element} this
8504 unselectable : function(){
8505 this.dom.unselectable = "on";
8506 this.swallowEvent("selectstart", true);
8507 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8508 this.addClass("x-unselectable");
8513 * Calculates the x, y to center this element on the screen
8514 * @return {Array} The x, y values [x, y]
8516 getCenterXY : function(){
8517 return this.getAlignToXY(document, 'c-c');
8521 * Centers the Element in either the viewport, or another Element.
8522 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8524 center : function(centerIn){
8525 this.alignTo(centerIn || document, 'c-c');
8530 * Tests various css rules/browsers to determine if this element uses a border box
8533 isBorderBox : function(){
8534 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8538 * Return a box {x, y, width, height} that can be used to set another elements
8539 * size/location to match this element.
8540 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8541 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8542 * @return {Object} box An object in the format {x, y, width, height}
8544 getBox : function(contentBox, local){
8549 var left = parseInt(this.getStyle("left"), 10) || 0;
8550 var top = parseInt(this.getStyle("top"), 10) || 0;
8553 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8555 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8557 var l = this.getBorderWidth("l")+this.getPadding("l");
8558 var r = this.getBorderWidth("r")+this.getPadding("r");
8559 var t = this.getBorderWidth("t")+this.getPadding("t");
8560 var b = this.getBorderWidth("b")+this.getPadding("b");
8561 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8563 bx.right = bx.x + bx.width;
8564 bx.bottom = bx.y + bx.height;
8569 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8570 for more information about the sides.
8571 * @param {String} sides
8574 getFrameWidth : function(sides, onlyContentBox){
8575 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8579 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8580 * @param {Object} box The box to fill {x, y, width, height}
8581 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8582 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8583 * @return {Roo.Element} this
8585 setBox : function(box, adjust, animate){
8586 var w = box.width, h = box.height;
8587 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8588 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8589 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8591 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8596 * Forces the browser to repaint this element
8597 * @return {Roo.Element} this
8599 repaint : function(){
8601 this.addClass("x-repaint");
8602 setTimeout(function(){
8603 Roo.get(dom).removeClass("x-repaint");
8609 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8610 * then it returns the calculated width of the sides (see getPadding)
8611 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8612 * @return {Object/Number}
8614 getMargins : function(side){
8617 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8618 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8619 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8620 right: parseInt(this.getStyle("margin-right"), 10) || 0
8623 return this.addStyles(side, El.margins);
8628 addStyles : function(sides, styles){
8630 for(var i = 0, len = sides.length; i < len; i++){
8631 v = this.getStyle(styles[sides.charAt(i)]);
8633 w = parseInt(v, 10);
8641 * Creates a proxy element of this element
8642 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8643 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8644 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8645 * @return {Roo.Element} The new proxy element
8647 createProxy : function(config, renderTo, matchBox){
8649 renderTo = Roo.getDom(renderTo);
8651 renderTo = document.body;
8653 config = typeof config == "object" ?
8654 config : {tag : "div", cls: config};
8655 var proxy = Roo.DomHelper.append(renderTo, config, true);
8657 proxy.setBox(this.getBox());
8663 * Puts a mask over this element to disable user interaction. Requires core.css.
8664 * This method can only be applied to elements which accept child nodes.
8665 * @param {String} msg (optional) A message to display in the mask
8666 * @param {String} msgCls (optional) A css class to apply to the msg element
8667 * @return {Element} The mask element
8669 mask : function(msg, msgCls){
8670 if(this.getStyle("position") == "static"){
8671 this.setStyle("position", "relative");
8674 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8676 this.addClass("x-masked");
8677 this._mask.setDisplayed(true);
8678 if(typeof msg == 'string'){
8680 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8682 var mm = this._maskMsg;
8683 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8684 mm.dom.firstChild.innerHTML = msg;
8685 mm.setDisplayed(true);
8688 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8689 this._mask.setHeight(this.getHeight());
8695 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8696 * it is cached for reuse.
8698 unmask : function(removeEl){
8700 if(removeEl === true){
8701 this._mask.remove();
8704 this._maskMsg.remove();
8705 delete this._maskMsg;
8708 this._mask.setDisplayed(false);
8710 this._maskMsg.setDisplayed(false);
8714 this.removeClass("x-masked");
8718 * Returns true if this element is masked
8721 isMasked : function(){
8722 return this._mask && this._mask.isVisible();
8726 * Creates an iframe shim for this element to keep selects and other windowed objects from
8728 * @return {Roo.Element} The new shim element
8730 createShim : function(){
8731 var el = document.createElement('iframe');
8732 el.frameBorder = 'no';
8733 el.className = 'roo-shim';
8734 if(Roo.isIE && Roo.isSecure){
8735 el.src = Roo.SSL_SECURE_URL;
8737 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8738 shim.autoBoxAdjust = false;
8743 * Removes this element from the DOM and deletes it from the cache
8745 remove : function(){
8746 if(this.dom.parentNode){
8747 this.dom.parentNode.removeChild(this.dom);
8749 delete El.cache[this.dom.id];
8753 * Sets up event handlers to add and remove a css class when the mouse is over this element
8754 * @param {String} className
8755 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
8756 * mouseout events for children elements
8757 * @return {Roo.Element} this
8759 addClassOnOver : function(className, preventFlicker){
8760 this.on("mouseover", function(){
8761 Roo.fly(this, '_internal').addClass(className);
8763 var removeFn = function(e){
8764 if(preventFlicker !== true || !e.within(this, true)){
8765 Roo.fly(this, '_internal').removeClass(className);
8768 this.on("mouseout", removeFn, this.dom);
8773 * Sets up event handlers to add and remove a css class when this element has the focus
8774 * @param {String} className
8775 * @return {Roo.Element} this
8777 addClassOnFocus : function(className){
8778 this.on("focus", function(){
8779 Roo.fly(this, '_internal').addClass(className);
8781 this.on("blur", function(){
8782 Roo.fly(this, '_internal').removeClass(className);
8787 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
8788 * @param {String} className
8789 * @return {Roo.Element} this
8791 addClassOnClick : function(className){
8793 this.on("mousedown", function(){
8794 Roo.fly(dom, '_internal').addClass(className);
8795 var d = Roo.get(document);
8796 var fn = function(){
8797 Roo.fly(dom, '_internal').removeClass(className);
8798 d.removeListener("mouseup", fn);
8800 d.on("mouseup", fn);
8806 * Stops the specified event from bubbling and optionally prevents the default action
8807 * @param {String} eventName
8808 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8809 * @return {Roo.Element} this
8811 swallowEvent : function(eventName, preventDefault){
8812 var fn = function(e){
8813 e.stopPropagation();
8818 if(eventName instanceof Array){
8819 for(var i = 0, len = eventName.length; i < len; i++){
8820 this.on(eventName[i], fn);
8824 this.on(eventName, fn);
8831 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
8834 * Sizes this element to its parent element's dimensions performing
8835 * neccessary box adjustments.
8836 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
8837 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
8838 * @return {Roo.Element} this
8840 fitToParent : function(monitorResize, targetParent) {
8841 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
8842 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
8843 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
8846 var p = Roo.get(targetParent || this.dom.parentNode);
8847 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
8848 if (monitorResize === true) {
8849 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
8850 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
8856 * Gets the next sibling, skipping text nodes
8857 * @return {HTMLElement} The next sibling or null
8859 getNextSibling : function(){
8860 var n = this.dom.nextSibling;
8861 while(n && n.nodeType != 1){
8868 * Gets the previous sibling, skipping text nodes
8869 * @return {HTMLElement} The previous sibling or null
8871 getPrevSibling : function(){
8872 var n = this.dom.previousSibling;
8873 while(n && n.nodeType != 1){
8874 n = n.previousSibling;
8881 * Appends the passed element(s) to this element
8882 * @param {String/HTMLElement/Array/Element/CompositeElement} el
8883 * @return {Roo.Element} this
8885 appendChild: function(el){
8892 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
8893 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
8894 * automatically generated with the specified attributes.
8895 * @param {HTMLElement} insertBefore (optional) a child element of this element
8896 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
8897 * @return {Roo.Element} The new child element
8899 createChild: function(config, insertBefore, returnDom){
8900 config = config || {tag:'div'};
8902 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
8904 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
8908 * Appends this element to the passed element
8909 * @param {String/HTMLElement/Element} el The new parent element
8910 * @return {Roo.Element} this
8912 appendTo: function(el){
8913 el = Roo.getDom(el);
8914 el.appendChild(this.dom);
8919 * Inserts this element before the passed element in the DOM
8920 * @param {String/HTMLElement/Element} el The element to insert before
8921 * @return {Roo.Element} this
8923 insertBefore: function(el){
8924 el = Roo.getDom(el);
8925 el.parentNode.insertBefore(this.dom, el);
8930 * Inserts this element after the passed element in the DOM
8931 * @param {String/HTMLElement/Element} el The element to insert after
8932 * @return {Roo.Element} this
8934 insertAfter: function(el){
8935 el = Roo.getDom(el);
8936 el.parentNode.insertBefore(this.dom, el.nextSibling);
8941 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
8942 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8943 * @return {Roo.Element} The new child
8945 insertFirst: function(el, returnDom){
8947 if(typeof el == 'object' && !el.nodeType){ // dh config
8948 return this.createChild(el, this.dom.firstChild, returnDom);
8950 el = Roo.getDom(el);
8951 this.dom.insertBefore(el, this.dom.firstChild);
8952 return !returnDom ? Roo.get(el) : el;
8957 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
8958 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
8959 * @param {String} where (optional) 'before' or 'after' defaults to before
8960 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8961 * @return {Roo.Element} the inserted Element
8963 insertSibling: function(el, where, returnDom){
8964 where = where ? where.toLowerCase() : 'before';
8966 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
8968 if(typeof el == 'object' && !el.nodeType){ // dh config
8969 if(where == 'after' && !this.dom.nextSibling){
8970 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
8972 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
8976 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
8977 where == 'before' ? this.dom : this.dom.nextSibling);
8986 * Creates and wraps this element with another element
8987 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
8988 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
8989 * @return {HTMLElement/Element} The newly created wrapper element
8991 wrap: function(config, returnDom){
8993 config = {tag: "div"};
8995 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
8996 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9001 * Replaces the passed element with this element
9002 * @param {String/HTMLElement/Element} el The element to replace
9003 * @return {Roo.Element} this
9005 replace: function(el){
9007 this.insertBefore(el);
9013 * Inserts an html fragment into this element
9014 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9015 * @param {String} html The HTML fragment
9016 * @param {Boolean} returnEl True to return an Roo.Element
9017 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9019 insertHtml : function(where, html, returnEl){
9020 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9021 return returnEl ? Roo.get(el) : el;
9025 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9026 * @param {Object} o The object with the attributes
9027 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9028 * @return {Roo.Element} this
9030 set : function(o, useSet){
9032 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9034 if(attr == "style" || typeof o[attr] == "function") continue;
9036 el.className = o["cls"];
9038 if(useSet) el.setAttribute(attr, o[attr]);
9039 else el[attr] = o[attr];
9043 Roo.DomHelper.applyStyles(el, o.style);
9049 * Convenience method for constructing a KeyMap
9050 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9051 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9052 * @param {Function} fn The function to call
9053 * @param {Object} scope (optional) The scope of the function
9054 * @return {Roo.KeyMap} The KeyMap created
9056 addKeyListener : function(key, fn, scope){
9058 if(typeof key != "object" || key instanceof Array){
9074 return new Roo.KeyMap(this, config);
9078 * Creates a KeyMap for this element
9079 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9080 * @return {Roo.KeyMap} The KeyMap created
9082 addKeyMap : function(config){
9083 return new Roo.KeyMap(this, config);
9087 * Returns true if this element is scrollable.
9090 isScrollable : function(){
9092 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9096 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9097 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9098 * @param {Number} value The new scroll value
9099 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9100 * @return {Element} this
9103 scrollTo : function(side, value, animate){
9104 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9106 this.dom[prop] = value;
9108 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9109 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9115 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9116 * within this element's scrollable range.
9117 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9118 * @param {Number} distance How far to scroll the element in pixels
9119 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9120 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9121 * was scrolled as far as it could go.
9123 scroll : function(direction, distance, animate){
9124 if(!this.isScrollable()){
9128 var l = el.scrollLeft, t = el.scrollTop;
9129 var w = el.scrollWidth, h = el.scrollHeight;
9130 var cw = el.clientWidth, ch = el.clientHeight;
9131 direction = direction.toLowerCase();
9132 var scrolled = false;
9133 var a = this.preanim(arguments, 2);
9138 var v = Math.min(l + distance, w-cw);
9139 this.scrollTo("left", v, a);
9146 var v = Math.max(l - distance, 0);
9147 this.scrollTo("left", v, a);
9155 var v = Math.max(t - distance, 0);
9156 this.scrollTo("top", v, a);
9164 var v = Math.min(t + distance, h-ch);
9165 this.scrollTo("top", v, a);
9174 * Translates the passed page coordinates into left/top css values for this element
9175 * @param {Number/Array} x The page x or an array containing [x, y]
9176 * @param {Number} y The page y
9177 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9179 translatePoints : function(x, y){
9180 if(typeof x == 'object' || x instanceof Array){
9183 var p = this.getStyle('position');
9184 var o = this.getXY();
9186 var l = parseInt(this.getStyle('left'), 10);
9187 var t = parseInt(this.getStyle('top'), 10);
9190 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9193 t = (p == "relative") ? 0 : this.dom.offsetTop;
9196 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9200 * Returns the current scroll position of the element.
9201 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9203 getScroll : function(){
9204 var d = this.dom, doc = document;
9205 if(d == doc || d == doc.body){
9206 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9207 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9208 return {left: l, top: t};
9210 return {left: d.scrollLeft, top: d.scrollTop};
9215 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9216 * are convert to standard 6 digit hex color.
9217 * @param {String} attr The css attribute
9218 * @param {String} defaultValue The default value to use when a valid color isn't found
9219 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9222 getColor : function(attr, defaultValue, prefix){
9223 var v = this.getStyle(attr);
9224 if(!v || v == "transparent" || v == "inherit") {
9225 return defaultValue;
9227 var color = typeof prefix == "undefined" ? "#" : prefix;
9228 if(v.substr(0, 4) == "rgb("){
9229 var rvs = v.slice(4, v.length -1).split(",");
9230 for(var i = 0; i < 3; i++){
9231 var h = parseInt(rvs[i]).toString(16);
9238 if(v.substr(0, 1) == "#"){
9240 for(var i = 1; i < 4; i++){
9241 var c = v.charAt(i);
9244 }else if(v.length == 7){
9245 color += v.substr(1);
9249 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9253 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9254 * gradient background, rounded corners and a 4-way shadow.
9255 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9256 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9257 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9258 * @return {Roo.Element} this
9260 boxWrap : function(cls){
9261 cls = cls || 'x-box';
9262 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9263 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9268 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9269 * @param {String} namespace The namespace in which to look for the attribute
9270 * @param {String} name The attribute name
9271 * @return {String} The attribute value
9273 getAttributeNS : Roo.isIE ? function(ns, name){
9275 var type = typeof d[ns+":"+name];
9276 if(type != 'undefined' && type != 'unknown'){
9277 return d[ns+":"+name];
9280 } : function(ns, name){
9282 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9286 var ep = El.prototype;
9289 * Appends an event handler (Shorthand for addListener)
9290 * @param {String} eventName The type of event to append
9291 * @param {Function} fn The method the event invokes
9292 * @param {Object} scope (optional) The scope (this object) of the fn
9293 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9296 ep.on = ep.addListener;
9298 ep.mon = ep.addListener;
9301 * Removes an event handler from this element (shorthand for removeListener)
9302 * @param {String} eventName the type of event to remove
9303 * @param {Function} fn the method the event invokes
9304 * @return {Roo.Element} this
9307 ep.un = ep.removeListener;
9310 * true to automatically adjust width and height settings for box-model issues (default to true)
9312 ep.autoBoxAdjust = true;
9315 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9318 El.addUnits = function(v, defaultUnit){
9319 if(v === "" || v == "auto"){
9322 if(v === undefined){
9325 if(typeof v == "number" || !El.unitPattern.test(v)){
9326 return v + (defaultUnit || 'px');
9331 // special markup used throughout Roo when box wrapping elements
9332 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9334 * Visibility mode constant - Use visibility to hide element
9340 * Visibility mode constant - Use display to hide element
9346 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9347 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9348 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9360 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9361 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9362 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9363 * @return {Element} The Element object
9366 El.get = function(el){
9368 if(!el){ return null; }
9369 if(typeof el == "string"){ // element id
9370 if(!(elm = document.getElementById(el))){
9373 if(ex = El.cache[el]){
9376 ex = El.cache[el] = new El(elm);
9379 }else if(el.tagName){ // dom element
9383 if(ex = El.cache[id]){
9386 ex = El.cache[id] = new El(el);
9389 }else if(el instanceof El){
9391 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9392 // catch case where it hasn't been appended
9393 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9396 }else if(el.isComposite){
9398 }else if(el instanceof Array){
9399 return El.select(el);
9400 }else if(el == document){
9401 // create a bogus element object representing the document object
9403 var f = function(){};
9404 f.prototype = El.prototype;
9406 docEl.dom = document;
9414 El.uncache = function(el){
9415 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9417 delete El.cache[a[i].id || a[i]];
9423 // Garbage collection - uncache elements/purge listeners on orphaned elements
9424 // so we don't hold a reference and cause the browser to retain them
9425 El.garbageCollect = function(){
9426 if(!Roo.enableGarbageCollector){
9427 clearInterval(El.collectorThread);
9430 for(var eid in El.cache){
9431 var el = El.cache[eid], d = el.dom;
9432 // -------------------------------------------------------
9433 // Determining what is garbage:
9434 // -------------------------------------------------------
9436 // dom node is null, definitely garbage
9437 // -------------------------------------------------------
9439 // no parentNode == direct orphan, definitely garbage
9440 // -------------------------------------------------------
9441 // !d.offsetParent && !document.getElementById(eid)
9442 // display none elements have no offsetParent so we will
9443 // also try to look it up by it's id. However, check
9444 // offsetParent first so we don't do unneeded lookups.
9445 // This enables collection of elements that are not orphans
9446 // directly, but somewhere up the line they have an orphan
9448 // -------------------------------------------------------
9449 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9450 delete El.cache[eid];
9451 if(d && Roo.enableListenerCollection){
9457 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9461 El.Flyweight = function(dom){
9464 El.Flyweight.prototype = El.prototype;
9466 El._flyweights = {};
9468 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9469 * the dom node can be overwritten by other code.
9470 * @param {String/HTMLElement} el The dom node or id
9471 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9472 * prevent conflicts (e.g. internally Roo uses "_internal")
9474 * @return {Element} The shared Element object
9476 El.fly = function(el, named){
9477 named = named || '_global';
9478 el = Roo.getDom(el);
9482 if(!El._flyweights[named]){
9483 El._flyweights[named] = new El.Flyweight();
9485 El._flyweights[named].dom = el;
9486 return El._flyweights[named];
9490 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9491 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9492 * Shorthand of {@link Roo.Element#get}
9493 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9494 * @return {Element} The Element object
9500 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9501 * the dom node can be overwritten by other code.
9502 * Shorthand of {@link Roo.Element#fly}
9503 * @param {String/HTMLElement} el The dom node or id
9504 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9505 * prevent conflicts (e.g. internally Roo uses "_internal")
9507 * @return {Element} The shared Element object
9513 // speedy lookup for elements never to box adjust
9514 var noBoxAdjust = Roo.isStrict ? {
9517 input:1, select:1, textarea:1
9519 if(Roo.isIE || Roo.isGecko){
9520 noBoxAdjust['button'] = 1;
9524 Roo.EventManager.on(window, 'unload', function(){
9526 delete El._flyweights;
9534 Roo.Element.selectorFunction = Roo.DomQuery.select;
9537 Roo.Element.select = function(selector, unique, root){
9539 if(typeof selector == "string"){
9540 els = Roo.Element.selectorFunction(selector, root);
9541 }else if(selector.length !== undefined){
9544 throw "Invalid selector";
9546 if(unique === true){
9547 return new Roo.CompositeElement(els);
9549 return new Roo.CompositeElementLite(els);
9553 * Selects elements based on the passed CSS selector to enable working on them as 1.
9554 * @param {String/Array} selector The CSS selector or an array of elements
9555 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9556 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9557 * @return {CompositeElementLite/CompositeElement}
9561 Roo.select = Roo.Element.select;
9578 * Ext JS Library 1.1.1
9579 * Copyright(c) 2006-2007, Ext JS, LLC.
9581 * Originally Released Under LGPL - original licence link has changed is not relivant.
9584 * <script type="text/javascript">
9589 //Notifies Element that fx methods are available
9590 Roo.enableFx = true;
9594 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9595 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9596 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9597 * Element effects to work.</p><br/>
9599 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9600 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9601 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9602 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9603 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9604 * expected results and should be done with care.</p><br/>
9606 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9607 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9610 ----- -----------------------------
9611 tl The top left corner
9612 t The center of the top edge
9613 tr The top right corner
9614 l The center of the left edge
9615 r The center of the right edge
9616 bl The bottom left corner
9617 b The center of the bottom edge
9618 br The bottom right corner
9620 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9621 * below are common options that can be passed to any Fx method.</b>
9622 * @cfg {Function} callback A function called when the effect is finished
9623 * @cfg {Object} scope The scope of the effect function
9624 * @cfg {String} easing A valid Easing value for the effect
9625 * @cfg {String} afterCls A css class to apply after the effect
9626 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9627 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9628 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9629 * effects that end with the element being visually hidden, ignored otherwise)
9630 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9631 * a function which returns such a specification that will be applied to the Element after the effect finishes
9632 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9633 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
9634 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9638 * Slides the element into view. An anchor point can be optionally passed to set the point of
9639 * origin for the slide effect. This function automatically handles wrapping the element with
9640 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9643 // default: slide the element in from the top
9646 // custom: slide the element in from the right with a 2-second duration
9647 el.slideIn('r', { duration: 2 });
9649 // common config options shown with default values
9655 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9656 * @param {Object} options (optional) Object literal with any of the Fx config options
9657 * @return {Roo.Element} The Element
9659 slideIn : function(anchor, o){
9660 var el = this.getFxEl();
9663 el.queueFx(o, function(){
9665 anchor = anchor || "t";
9667 // fix display to visibility
9670 // restore values after effect
9671 var r = this.getFxRestore();
9672 var b = this.getBox();
9673 // fixed size for slide
9677 var wrap = this.fxWrap(r.pos, o, "hidden");
9679 var st = this.dom.style;
9680 st.visibility = "visible";
9681 st.position = "absolute";
9683 // clear out temp styles after slide and unwrap
9684 var after = function(){
9685 el.fxUnwrap(wrap, r.pos, o);
9687 st.height = r.height;
9690 // time to calc the positions
9691 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9693 switch(anchor.toLowerCase()){
9695 wrap.setSize(b.width, 0);
9696 st.left = st.bottom = "0";
9700 wrap.setSize(0, b.height);
9701 st.right = st.top = "0";
9705 wrap.setSize(0, b.height);
9707 st.left = st.top = "0";
9708 a = {width: bw, points: pt};
9711 wrap.setSize(b.width, 0);
9712 wrap.setY(b.bottom);
9713 st.left = st.top = "0";
9714 a = {height: bh, points: pt};
9718 st.right = st.bottom = "0";
9719 a = {width: bw, height: bh};
9723 wrap.setY(b.y+b.height);
9724 st.right = st.top = "0";
9725 a = {width: bw, height: bh, points: pt};
9729 wrap.setXY([b.right, b.bottom]);
9730 st.left = st.top = "0";
9731 a = {width: bw, height: bh, points: pt};
9735 wrap.setX(b.x+b.width);
9736 st.left = st.bottom = "0";
9737 a = {width: bw, height: bh, points: pt};
9740 this.dom.style.visibility = "visible";
9743 arguments.callee.anim = wrap.fxanim(a,
9753 * Slides the element out of view. An anchor point can be optionally passed to set the end point
9754 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
9755 * 'hidden') but block elements will still take up space in the document. The element must be removed
9756 * from the DOM using the 'remove' config option if desired. This function automatically handles
9757 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9760 // default: slide the element out to the top
9763 // custom: slide the element out to the right with a 2-second duration
9764 el.slideOut('r', { duration: 2 });
9766 // common config options shown with default values
9774 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9775 * @param {Object} options (optional) Object literal with any of the Fx config options
9776 * @return {Roo.Element} The Element
9778 slideOut : function(anchor, o){
9779 var el = this.getFxEl();
9782 el.queueFx(o, function(){
9784 anchor = anchor || "t";
9786 // restore values after effect
9787 var r = this.getFxRestore();
9789 var b = this.getBox();
9790 // fixed size for slide
9794 var wrap = this.fxWrap(r.pos, o, "visible");
9796 var st = this.dom.style;
9797 st.visibility = "visible";
9798 st.position = "absolute";
9802 var after = function(){
9804 el.setDisplayed(false);
9809 el.fxUnwrap(wrap, r.pos, o);
9812 st.height = r.height;
9817 var a, zero = {to: 0};
9818 switch(anchor.toLowerCase()){
9820 st.left = st.bottom = "0";
9824 st.right = st.top = "0";
9828 st.left = st.top = "0";
9829 a = {width: zero, points: {to:[b.right, b.y]}};
9832 st.left = st.top = "0";
9833 a = {height: zero, points: {to:[b.x, b.bottom]}};
9836 st.right = st.bottom = "0";
9837 a = {width: zero, height: zero};
9840 st.right = st.top = "0";
9841 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
9844 st.left = st.top = "0";
9845 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
9848 st.left = st.bottom = "0";
9849 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
9853 arguments.callee.anim = wrap.fxanim(a,
9863 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
9864 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
9865 * The element must be removed from the DOM using the 'remove' config option if desired.
9871 // common config options shown with default values
9879 * @param {Object} options (optional) Object literal with any of the Fx config options
9880 * @return {Roo.Element} The Element
9883 var el = this.getFxEl();
9886 el.queueFx(o, function(){
9887 this.clearOpacity();
9890 // restore values after effect
9891 var r = this.getFxRestore();
9892 var st = this.dom.style;
9894 var after = function(){
9896 el.setDisplayed(false);
9903 el.setPositioning(r.pos);
9905 st.height = r.height;
9910 var width = this.getWidth();
9911 var height = this.getHeight();
9913 arguments.callee.anim = this.fxanim({
9914 width : {to: this.adjustWidth(width * 2)},
9915 height : {to: this.adjustHeight(height * 2)},
9916 points : {by: [-(width * .5), -(height * .5)]},
9918 fontSize: {to:200, unit: "%"}
9929 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
9930 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
9931 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
9937 // all config options shown with default values
9945 * @param {Object} options (optional) Object literal with any of the Fx config options
9946 * @return {Roo.Element} The Element
9948 switchOff : function(o){
9949 var el = this.getFxEl();
9952 el.queueFx(o, function(){
9953 this.clearOpacity();
9956 // restore values after effect
9957 var r = this.getFxRestore();
9958 var st = this.dom.style;
9960 var after = function(){
9962 el.setDisplayed(false);
9968 el.setPositioning(r.pos);
9970 st.height = r.height;
9975 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
9976 this.clearOpacity();
9980 points:{by:[0, this.getHeight() * .5]}
9981 }, o, 'motion', 0.3, 'easeIn', after);
9982 }).defer(100, this);
9989 * Highlights the Element by setting a color (applies to the background-color by default, but can be
9990 * changed using the "attr" config option) and then fading back to the original color. If no original
9991 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
9994 // default: highlight background to yellow
9997 // custom: highlight foreground text to blue for 2 seconds
9998 el.highlight("0000ff", { attr: 'color', duration: 2 });
10000 // common config options shown with default values
10001 el.highlight("ffff9c", {
10002 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10003 endColor: (current color) or "ffffff",
10008 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10009 * @param {Object} options (optional) Object literal with any of the Fx config options
10010 * @return {Roo.Element} The Element
10012 highlight : function(color, o){
10013 var el = this.getFxEl();
10016 el.queueFx(o, function(){
10017 color = color || "ffff9c";
10018 attr = o.attr || "backgroundColor";
10020 this.clearOpacity();
10023 var origColor = this.getColor(attr);
10024 var restoreColor = this.dom.style[attr];
10025 endColor = (o.endColor || origColor) || "ffffff";
10027 var after = function(){
10028 el.dom.style[attr] = restoreColor;
10033 a[attr] = {from: color, to: endColor};
10034 arguments.callee.anim = this.fxanim(a,
10044 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10047 // default: a single light blue ripple
10050 // custom: 3 red ripples lasting 3 seconds total
10051 el.frame("ff0000", 3, { duration: 3 });
10053 // common config options shown with default values
10054 el.frame("C3DAF9", 1, {
10055 duration: 1 //duration of entire animation (not each individual ripple)
10056 // Note: Easing is not configurable and will be ignored if included
10059 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10060 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10061 * @param {Object} options (optional) Object literal with any of the Fx config options
10062 * @return {Roo.Element} The Element
10064 frame : function(color, count, o){
10065 var el = this.getFxEl();
10068 el.queueFx(o, function(){
10069 color = color || "#C3DAF9";
10070 if(color.length == 6){
10071 color = "#" + color;
10073 count = count || 1;
10074 duration = o.duration || 1;
10077 var b = this.getBox();
10078 var animFn = function(){
10079 var proxy = this.createProxy({
10082 visbility:"hidden",
10083 position:"absolute",
10084 "z-index":"35000", // yee haw
10085 border:"0px solid " + color
10088 var scale = Roo.isBorderBox ? 2 : 1;
10090 top:{from:b.y, to:b.y - 20},
10091 left:{from:b.x, to:b.x - 20},
10092 borderWidth:{from:0, to:10},
10093 opacity:{from:1, to:0},
10094 height:{from:b.height, to:(b.height + (20*scale))},
10095 width:{from:b.width, to:(b.width + (20*scale))}
10096 }, duration, function(){
10100 animFn.defer((duration/2)*1000, this);
10111 * Creates a pause before any subsequent queued effects begin. If there are
10112 * no effects queued after the pause it will have no effect.
10117 * @param {Number} seconds The length of time to pause (in seconds)
10118 * @return {Roo.Element} The Element
10120 pause : function(seconds){
10121 var el = this.getFxEl();
10124 el.queueFx(o, function(){
10125 setTimeout(function(){
10127 }, seconds * 1000);
10133 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10134 * using the "endOpacity" config option.
10137 // default: fade in from opacity 0 to 100%
10140 // custom: fade in from opacity 0 to 75% over 2 seconds
10141 el.fadeIn({ endOpacity: .75, duration: 2});
10143 // common config options shown with default values
10145 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10150 * @param {Object} options (optional) Object literal with any of the Fx config options
10151 * @return {Roo.Element} The Element
10153 fadeIn : function(o){
10154 var el = this.getFxEl();
10156 el.queueFx(o, function(){
10157 this.setOpacity(0);
10159 this.dom.style.visibility = 'visible';
10160 var to = o.endOpacity || 1;
10161 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10162 o, null, .5, "easeOut", function(){
10164 this.clearOpacity();
10173 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10174 * using the "endOpacity" config option.
10177 // default: fade out from the element's current opacity to 0
10180 // custom: fade out from the element's current opacity to 25% over 2 seconds
10181 el.fadeOut({ endOpacity: .25, duration: 2});
10183 // common config options shown with default values
10185 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10192 * @param {Object} options (optional) Object literal with any of the Fx config options
10193 * @return {Roo.Element} The Element
10195 fadeOut : function(o){
10196 var el = this.getFxEl();
10198 el.queueFx(o, function(){
10199 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10200 o, null, .5, "easeOut", function(){
10201 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10202 this.dom.style.display = "none";
10204 this.dom.style.visibility = "hidden";
10206 this.clearOpacity();
10214 * Animates the transition of an element's dimensions from a starting height/width
10215 * to an ending height/width.
10218 // change height and width to 100x100 pixels
10219 el.scale(100, 100);
10221 // common config options shown with default values. The height and width will default to
10222 // the element's existing values if passed as null.
10225 [element's height], {
10230 * @param {Number} width The new width (pass undefined to keep the original width)
10231 * @param {Number} height The new height (pass undefined to keep the original height)
10232 * @param {Object} options (optional) Object literal with any of the Fx config options
10233 * @return {Roo.Element} The Element
10235 scale : function(w, h, o){
10236 this.shift(Roo.apply({}, o, {
10244 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10245 * Any of these properties not specified in the config object will not be changed. This effect
10246 * requires that at least one new dimension, position or opacity setting must be passed in on
10247 * the config object in order for the function to have any effect.
10250 // slide the element horizontally to x position 200 while changing the height and opacity
10251 el.shift({ x: 200, height: 50, opacity: .8 });
10253 // common config options shown with default values.
10255 width: [element's width],
10256 height: [element's height],
10257 x: [element's x position],
10258 y: [element's y position],
10259 opacity: [element's opacity],
10264 * @param {Object} options Object literal with any of the Fx config options
10265 * @return {Roo.Element} The Element
10267 shift : function(o){
10268 var el = this.getFxEl();
10270 el.queueFx(o, function(){
10271 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10272 if(w !== undefined){
10273 a.width = {to: this.adjustWidth(w)};
10275 if(h !== undefined){
10276 a.height = {to: this.adjustHeight(h)};
10278 if(x !== undefined || y !== undefined){
10280 x !== undefined ? x : this.getX(),
10281 y !== undefined ? y : this.getY()
10284 if(op !== undefined){
10285 a.opacity = {to: op};
10287 if(o.xy !== undefined){
10288 a.points = {to: o.xy};
10290 arguments.callee.anim = this.fxanim(a,
10291 o, 'motion', .35, "easeOut", function(){
10299 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10300 * ending point of the effect.
10303 // default: slide the element downward while fading out
10306 // custom: slide the element out to the right with a 2-second duration
10307 el.ghost('r', { duration: 2 });
10309 // common config options shown with default values
10317 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10318 * @param {Object} options (optional) Object literal with any of the Fx config options
10319 * @return {Roo.Element} The Element
10321 ghost : function(anchor, o){
10322 var el = this.getFxEl();
10325 el.queueFx(o, function(){
10326 anchor = anchor || "b";
10328 // restore values after effect
10329 var r = this.getFxRestore();
10330 var w = this.getWidth(),
10331 h = this.getHeight();
10333 var st = this.dom.style;
10335 var after = function(){
10337 el.setDisplayed(false);
10343 el.setPositioning(r.pos);
10344 st.width = r.width;
10345 st.height = r.height;
10350 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10351 switch(anchor.toLowerCase()){
10378 arguments.callee.anim = this.fxanim(a,
10388 * Ensures that all effects queued after syncFx is called on the element are
10389 * run concurrently. This is the opposite of {@link #sequenceFx}.
10390 * @return {Roo.Element} The Element
10392 syncFx : function(){
10393 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10402 * Ensures that all effects queued after sequenceFx is called on the element are
10403 * run in sequence. This is the opposite of {@link #syncFx}.
10404 * @return {Roo.Element} The Element
10406 sequenceFx : function(){
10407 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10409 concurrent : false,
10416 nextFx : function(){
10417 var ef = this.fxQueue[0];
10424 * Returns true if the element has any effects actively running or queued, else returns false.
10425 * @return {Boolean} True if element has active effects, else false
10427 hasActiveFx : function(){
10428 return this.fxQueue && this.fxQueue[0];
10432 * Stops any running effects and clears the element's internal effects queue if it contains
10433 * any additional effects that haven't started yet.
10434 * @return {Roo.Element} The Element
10436 stopFx : function(){
10437 if(this.hasActiveFx()){
10438 var cur = this.fxQueue[0];
10439 if(cur && cur.anim && cur.anim.isAnimated()){
10440 this.fxQueue = [cur]; // clear out others
10441 cur.anim.stop(true);
10448 beforeFx : function(o){
10449 if(this.hasActiveFx() && !o.concurrent){
10460 * Returns true if the element is currently blocking so that no other effect can be queued
10461 * until this effect is finished, else returns false if blocking is not set. This is commonly
10462 * used to ensure that an effect initiated by a user action runs to completion prior to the
10463 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10464 * @return {Boolean} True if blocking, else false
10466 hasFxBlock : function(){
10467 var q = this.fxQueue;
10468 return q && q[0] && q[0].block;
10472 queueFx : function(o, fn){
10476 if(!this.hasFxBlock()){
10477 Roo.applyIf(o, this.fxDefaults);
10479 var run = this.beforeFx(o);
10480 fn.block = o.block;
10481 this.fxQueue.push(fn);
10493 fxWrap : function(pos, o, vis){
10495 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10498 wrapXY = this.getXY();
10500 var div = document.createElement("div");
10501 div.style.visibility = vis;
10502 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10503 wrap.setPositioning(pos);
10504 if(wrap.getStyle("position") == "static"){
10505 wrap.position("relative");
10507 this.clearPositioning('auto');
10509 wrap.dom.appendChild(this.dom);
10511 wrap.setXY(wrapXY);
10518 fxUnwrap : function(wrap, pos, o){
10519 this.clearPositioning();
10520 this.setPositioning(pos);
10522 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10528 getFxRestore : function(){
10529 var st = this.dom.style;
10530 return {pos: this.getPositioning(), width: st.width, height : st.height};
10534 afterFx : function(o){
10536 this.applyStyles(o.afterStyle);
10539 this.addClass(o.afterCls);
10541 if(o.remove === true){
10544 Roo.callback(o.callback, o.scope, [this]);
10546 this.fxQueue.shift();
10552 getFxEl : function(){ // support for composite element fx
10553 return Roo.get(this.dom);
10557 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10558 animType = animType || 'run';
10560 var anim = Roo.lib.Anim[animType](
10562 (opt.duration || defaultDur) || .35,
10563 (opt.easing || defaultEase) || 'easeOut',
10565 Roo.callback(cb, this);
10574 // backwords compat
10575 Roo.Fx.resize = Roo.Fx.scale;
10577 //When included, Roo.Fx is automatically applied to Element so that all basic
10578 //effects are available directly via the Element API
10579 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10581 * Ext JS Library 1.1.1
10582 * Copyright(c) 2006-2007, Ext JS, LLC.
10584 * Originally Released Under LGPL - original licence link has changed is not relivant.
10587 * <script type="text/javascript">
10592 * @class Roo.CompositeElement
10593 * Standard composite class. Creates a Roo.Element for every element in the collection.
10595 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10596 * actions will be performed on all the elements in this collection.</b>
10598 * All methods return <i>this</i> and can be chained.
10600 var els = Roo.select("#some-el div.some-class", true);
10601 // or select directly from an existing element
10602 var el = Roo.get('some-el');
10603 el.select('div.some-class', true);
10605 els.setWidth(100); // all elements become 100 width
10606 els.hide(true); // all elements fade out and hide
10608 els.setWidth(100).hide(true);
10611 Roo.CompositeElement = function(els){
10612 this.elements = [];
10613 this.addElements(els);
10615 Roo.CompositeElement.prototype = {
10617 addElements : function(els){
10618 if(!els) return this;
10619 if(typeof els == "string"){
10620 els = Roo.Element.selectorFunction(els);
10622 var yels = this.elements;
10623 var index = yels.length-1;
10624 for(var i = 0, len = els.length; i < len; i++) {
10625 yels[++index] = Roo.get(els[i]);
10631 * Clears this composite and adds the elements returned by the passed selector.
10632 * @param {String/Array} els A string CSS selector, an array of elements or an element
10633 * @return {CompositeElement} this
10635 fill : function(els){
10636 this.elements = [];
10642 * Filters this composite to only elements that match the passed selector.
10643 * @param {String} selector A string CSS selector
10644 * @return {CompositeElement} this
10646 filter : function(selector){
10648 this.each(function(el){
10649 if(el.is(selector)){
10650 els[els.length] = el.dom;
10657 invoke : function(fn, args){
10658 var els = this.elements;
10659 for(var i = 0, len = els.length; i < len; i++) {
10660 Roo.Element.prototype[fn].apply(els[i], args);
10665 * Adds elements to this composite.
10666 * @param {String/Array} els A string CSS selector, an array of elements or an element
10667 * @return {CompositeElement} this
10669 add : function(els){
10670 if(typeof els == "string"){
10671 this.addElements(Roo.Element.selectorFunction(els));
10672 }else if(els.length !== undefined){
10673 this.addElements(els);
10675 this.addElements([els]);
10680 * Calls the passed function passing (el, this, index) for each element in this composite.
10681 * @param {Function} fn The function to call
10682 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10683 * @return {CompositeElement} this
10685 each : function(fn, scope){
10686 var els = this.elements;
10687 for(var i = 0, len = els.length; i < len; i++){
10688 if(fn.call(scope || els[i], els[i], this, i) === false) {
10696 * Returns the Element object at the specified index
10697 * @param {Number} index
10698 * @return {Roo.Element}
10700 item : function(index){
10701 return this.elements[index] || null;
10705 * Returns the first Element
10706 * @return {Roo.Element}
10708 first : function(){
10709 return this.item(0);
10713 * Returns the last Element
10714 * @return {Roo.Element}
10717 return this.item(this.elements.length-1);
10721 * Returns the number of elements in this composite
10724 getCount : function(){
10725 return this.elements.length;
10729 * Returns true if this composite contains the passed element
10732 contains : function(el){
10733 return this.indexOf(el) !== -1;
10737 * Returns true if this composite contains the passed element
10740 indexOf : function(el){
10741 return this.elements.indexOf(Roo.get(el));
10746 * Removes the specified element(s).
10747 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
10748 * or an array of any of those.
10749 * @param {Boolean} removeDom (optional) True to also remove the element from the document
10750 * @return {CompositeElement} this
10752 removeElement : function(el, removeDom){
10753 if(el instanceof Array){
10754 for(var i = 0, len = el.length; i < len; i++){
10755 this.removeElement(el[i]);
10759 var index = typeof el == 'number' ? el : this.indexOf(el);
10762 var d = this.elements[index];
10766 d.parentNode.removeChild(d);
10769 this.elements.splice(index, 1);
10775 * Replaces the specified element with the passed element.
10776 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
10778 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
10779 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
10780 * @return {CompositeElement} this
10782 replaceElement : function(el, replacement, domReplace){
10783 var index = typeof el == 'number' ? el : this.indexOf(el);
10786 this.elements[index].replaceWith(replacement);
10788 this.elements.splice(index, 1, Roo.get(replacement))
10795 * Removes all elements.
10797 clear : function(){
10798 this.elements = [];
10802 Roo.CompositeElement.createCall = function(proto, fnName){
10803 if(!proto[fnName]){
10804 proto[fnName] = function(){
10805 return this.invoke(fnName, arguments);
10809 for(var fnName in Roo.Element.prototype){
10810 if(typeof Roo.Element.prototype[fnName] == "function"){
10811 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
10817 * Ext JS Library 1.1.1
10818 * Copyright(c) 2006-2007, Ext JS, LLC.
10820 * Originally Released Under LGPL - original licence link has changed is not relivant.
10823 * <script type="text/javascript">
10827 * @class Roo.CompositeElementLite
10828 * @extends Roo.CompositeElement
10829 * Flyweight composite class. Reuses the same Roo.Element for element operations.
10831 var els = Roo.select("#some-el div.some-class");
10832 // or select directly from an existing element
10833 var el = Roo.get('some-el');
10834 el.select('div.some-class');
10836 els.setWidth(100); // all elements become 100 width
10837 els.hide(true); // all elements fade out and hide
10839 els.setWidth(100).hide(true);
10840 </code></pre><br><br>
10841 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10842 * actions will be performed on all the elements in this collection.</b>
10844 Roo.CompositeElementLite = function(els){
10845 Roo.CompositeElementLite.superclass.constructor.call(this, els);
10846 this.el = new Roo.Element.Flyweight();
10848 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
10849 addElements : function(els){
10851 if(els instanceof Array){
10852 this.elements = this.elements.concat(els);
10854 var yels = this.elements;
10855 var index = yels.length-1;
10856 for(var i = 0, len = els.length; i < len; i++) {
10857 yels[++index] = els[i];
10863 invoke : function(fn, args){
10864 var els = this.elements;
10866 for(var i = 0, len = els.length; i < len; i++) {
10868 Roo.Element.prototype[fn].apply(el, args);
10873 * Returns a flyweight Element of the dom element object at the specified index
10874 * @param {Number} index
10875 * @return {Roo.Element}
10877 item : function(index){
10878 if(!this.elements[index]){
10881 this.el.dom = this.elements[index];
10885 // fixes scope with flyweight
10886 addListener : function(eventName, handler, scope, opt){
10887 var els = this.elements;
10888 for(var i = 0, len = els.length; i < len; i++) {
10889 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
10895 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
10896 * passed is the flyweight (shared) Roo.Element instance, so if you require a
10897 * a reference to the dom node, use el.dom.</b>
10898 * @param {Function} fn The function to call
10899 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10900 * @return {CompositeElement} this
10902 each : function(fn, scope){
10903 var els = this.elements;
10905 for(var i = 0, len = els.length; i < len; i++){
10907 if(fn.call(scope || el, el, this, i) === false){
10914 indexOf : function(el){
10915 return this.elements.indexOf(Roo.getDom(el));
10918 replaceElement : function(el, replacement, domReplace){
10919 var index = typeof el == 'number' ? el : this.indexOf(el);
10921 replacement = Roo.getDom(replacement);
10923 var d = this.elements[index];
10924 d.parentNode.insertBefore(replacement, d);
10925 d.parentNode.removeChild(d);
10927 this.elements.splice(index, 1, replacement);
10932 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
10936 * Ext JS Library 1.1.1
10937 * Copyright(c) 2006-2007, Ext JS, LLC.
10939 * Originally Released Under LGPL - original licence link has changed is not relivant.
10942 * <script type="text/javascript">
10948 * @class Roo.data.Connection
10949 * @extends Roo.util.Observable
10950 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
10951 * either to a configured URL, or to a URL specified at request time.<br><br>
10953 * Requests made by this class are asynchronous, and will return immediately. No data from
10954 * the server will be available to the statement immediately following the {@link #request} call.
10955 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
10957 * Note: If you are doing a file upload, you will not get a normal response object sent back to
10958 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
10959 * The response object is created using the innerHTML of the IFRAME's document as the responseText
10960 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
10961 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
10962 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
10963 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
10964 * standard DOM methods.
10966 * @param {Object} config a configuration object.
10968 Roo.data.Connection = function(config){
10969 Roo.apply(this, config);
10972 * @event beforerequest
10973 * Fires before a network request is made to retrieve a data object.
10974 * @param {Connection} conn This Connection object.
10975 * @param {Object} options The options config object passed to the {@link #request} method.
10977 "beforerequest" : true,
10979 * @event requestcomplete
10980 * Fires if the request was successfully completed.
10981 * @param {Connection} conn This Connection object.
10982 * @param {Object} response The XHR object containing the response data.
10983 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
10984 * @param {Object} options The options config object passed to the {@link #request} method.
10986 "requestcomplete" : true,
10988 * @event requestexception
10989 * Fires if an error HTTP status was returned from the server.
10990 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
10991 * @param {Connection} conn This Connection object.
10992 * @param {Object} response The XHR object containing the response data.
10993 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
10994 * @param {Object} options The options config object passed to the {@link #request} method.
10996 "requestexception" : true
10998 Roo.data.Connection.superclass.constructor.call(this);
11001 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11003 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11006 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11007 * extra parameters to each request made by this object. (defaults to undefined)
11010 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11011 * to each request made by this object. (defaults to undefined)
11014 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11017 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11021 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11027 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11030 disableCaching: true,
11033 * Sends an HTTP request to a remote server.
11034 * @param {Object} options An object which may contain the following properties:<ul>
11035 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11036 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11037 * request, a url encoded string or a function to call to get either.</li>
11038 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11039 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11040 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11041 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11042 * <li>options {Object} The parameter to the request call.</li>
11043 * <li>success {Boolean} True if the request succeeded.</li>
11044 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11046 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11047 * The callback is passed the following parameters:<ul>
11048 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11049 * <li>options {Object} The parameter to the request call.</li>
11051 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11052 * The callback is passed the following parameters:<ul>
11053 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11054 * <li>options {Object} The parameter to the request call.</li>
11056 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11057 * for the callback function. Defaults to the browser window.</li>
11058 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11059 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11060 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11061 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11062 * params for the post data. Any params will be appended to the URL.</li>
11063 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11065 * @return {Number} transactionId
11067 request : function(o){
11068 if(this.fireEvent("beforerequest", this, o) !== false){
11071 if(typeof p == "function"){
11072 p = p.call(o.scope||window, o);
11074 if(typeof p == "object"){
11075 p = Roo.urlEncode(o.params);
11077 if(this.extraParams){
11078 var extras = Roo.urlEncode(this.extraParams);
11079 p = p ? (p + '&' + extras) : extras;
11082 var url = o.url || this.url;
11083 if(typeof url == 'function'){
11084 url = url.call(o.scope||window, o);
11088 var form = Roo.getDom(o.form);
11089 url = url || form.action;
11091 var enctype = form.getAttribute("enctype");
11092 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11093 return this.doFormUpload(o, p, url);
11095 var f = Roo.lib.Ajax.serializeForm(form);
11096 p = p ? (p + '&' + f) : f;
11099 var hs = o.headers;
11100 if(this.defaultHeaders){
11101 hs = Roo.apply(hs || {}, this.defaultHeaders);
11108 success: this.handleResponse,
11109 failure: this.handleFailure,
11111 argument: {options: o},
11112 timeout : this.timeout
11115 var method = o.method||this.method||(p ? "POST" : "GET");
11117 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11118 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11121 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11125 }else if(this.autoAbort !== false){
11129 if((method == 'GET' && p) || o.xmlData){
11130 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11133 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11134 return this.transId;
11136 Roo.callback(o.callback, o.scope, [o, null, null]);
11142 * Determine whether this object has a request outstanding.
11143 * @param {Number} transactionId (Optional) defaults to the last transaction
11144 * @return {Boolean} True if there is an outstanding request.
11146 isLoading : function(transId){
11148 return Roo.lib.Ajax.isCallInProgress(transId);
11150 return this.transId ? true : false;
11155 * Aborts any outstanding request.
11156 * @param {Number} transactionId (Optional) defaults to the last transaction
11158 abort : function(transId){
11159 if(transId || this.isLoading()){
11160 Roo.lib.Ajax.abort(transId || this.transId);
11165 handleResponse : function(response){
11166 this.transId = false;
11167 var options = response.argument.options;
11168 response.argument = options ? options.argument : null;
11169 this.fireEvent("requestcomplete", this, response, options);
11170 Roo.callback(options.success, options.scope, [response, options]);
11171 Roo.callback(options.callback, options.scope, [options, true, response]);
11175 handleFailure : function(response, e){
11176 this.transId = false;
11177 var options = response.argument.options;
11178 response.argument = options ? options.argument : null;
11179 this.fireEvent("requestexception", this, response, options, e);
11180 Roo.callback(options.failure, options.scope, [response, options]);
11181 Roo.callback(options.callback, options.scope, [options, false, response]);
11185 doFormUpload : function(o, ps, url){
11187 var frame = document.createElement('iframe');
11190 frame.className = 'x-hidden';
11192 frame.src = Roo.SSL_SECURE_URL;
11194 document.body.appendChild(frame);
11197 document.frames[id].name = id;
11200 var form = Roo.getDom(o.form);
11202 form.method = 'POST';
11203 form.enctype = form.encoding = 'multipart/form-data';
11209 if(ps){ // add dynamic params
11211 ps = Roo.urlDecode(ps, false);
11213 if(ps.hasOwnProperty(k)){
11214 hd = document.createElement('input');
11215 hd.type = 'hidden';
11218 form.appendChild(hd);
11225 var r = { // bogus response object
11230 r.argument = o ? o.argument : null;
11235 doc = frame.contentWindow.document;
11237 doc = (frame.contentDocument || window.frames[id].document);
11239 if(doc && doc.body){
11240 r.responseText = doc.body.innerHTML;
11242 if(doc && doc.XMLDocument){
11243 r.responseXML = doc.XMLDocument;
11245 r.responseXML = doc;
11252 Roo.EventManager.removeListener(frame, 'load', cb, this);
11254 this.fireEvent("requestcomplete", this, r, o);
11255 Roo.callback(o.success, o.scope, [r, o]);
11256 Roo.callback(o.callback, o.scope, [o, true, r]);
11258 setTimeout(function(){document.body.removeChild(frame);}, 100);
11261 Roo.EventManager.on(frame, 'load', cb, this);
11264 if(hiddens){ // remove dynamic params
11265 for(var i = 0, len = hiddens.length; i < len; i++){
11266 form.removeChild(hiddens[i]);
11274 * @extends Roo.data.Connection
11275 * Global Ajax request class.
11279 Roo.Ajax = new Roo.data.Connection({
11282 * @cfg {String} url @hide
11285 * @cfg {Object} extraParams @hide
11288 * @cfg {Object} defaultHeaders @hide
11291 * @cfg {String} method (Optional) @hide
11294 * @cfg {Number} timeout (Optional) @hide
11297 * @cfg {Boolean} autoAbort (Optional) @hide
11301 * @cfg {Boolean} disableCaching (Optional) @hide
11305 * @property disableCaching
11306 * True to add a unique cache-buster param to GET requests. (defaults to true)
11311 * The default URL to be used for requests to the server. (defaults to undefined)
11315 * @property extraParams
11316 * An object containing properties which are used as
11317 * extra parameters to each request made by this object. (defaults to undefined)
11321 * @property defaultHeaders
11322 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11327 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11331 * @property timeout
11332 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11337 * @property autoAbort
11338 * Whether a new request should abort any pending requests. (defaults to false)
11344 * Serialize the passed form into a url encoded string
11345 * @param {String/HTMLElement} form
11348 serializeForm : function(form){
11349 return Roo.lib.Ajax.serializeForm(form);
11353 * Ext JS Library 1.1.1
11354 * Copyright(c) 2006-2007, Ext JS, LLC.
11356 * Originally Released Under LGPL - original licence link has changed is not relivant.
11359 * <script type="text/javascript">
11364 * @extends Roo.data.Connection
11365 * Global Ajax request class.
11367 * @instanceOf Roo.data.Connection
11369 Roo.Ajax = new Roo.data.Connection({
11378 * @cfg {String} url @hide
11381 * @cfg {Object} extraParams @hide
11384 * @cfg {Object} defaultHeaders @hide
11387 * @cfg {String} method (Optional) @hide
11390 * @cfg {Number} timeout (Optional) @hide
11393 * @cfg {Boolean} autoAbort (Optional) @hide
11397 * @cfg {Boolean} disableCaching (Optional) @hide
11401 * @property disableCaching
11402 * True to add a unique cache-buster param to GET requests. (defaults to true)
11407 * The default URL to be used for requests to the server. (defaults to undefined)
11411 * @property extraParams
11412 * An object containing properties which are used as
11413 * extra parameters to each request made by this object. (defaults to undefined)
11417 * @property defaultHeaders
11418 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11423 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11427 * @property timeout
11428 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11433 * @property autoAbort
11434 * Whether a new request should abort any pending requests. (defaults to false)
11440 * Serialize the passed form into a url encoded string
11441 * @param {String/HTMLElement} form
11444 serializeForm : function(form){
11445 return Roo.lib.Ajax.serializeForm(form);
11449 * Ext JS Library 1.1.1
11450 * Copyright(c) 2006-2007, Ext JS, LLC.
11452 * Originally Released Under LGPL - original licence link has changed is not relivant.
11455 * <script type="text/javascript">
11460 * @class Roo.UpdateManager
11461 * @extends Roo.util.Observable
11462 * Provides AJAX-style update for Element object.<br><br>
11465 * // Get it from a Roo.Element object
11466 * var el = Roo.get("foo");
11467 * var mgr = el.getUpdateManager();
11468 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11470 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11472 * // or directly (returns the same UpdateManager instance)
11473 * var mgr = new Roo.UpdateManager("myElementId");
11474 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11475 * mgr.on("update", myFcnNeedsToKnow);
11477 // short handed call directly from the element object
11478 Roo.get("foo").load({
11482 text: "Loading Foo..."
11486 * Create new UpdateManager directly.
11487 * @param {String/HTMLElement/Roo.Element} el The element to update
11488 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11490 Roo.UpdateManager = function(el, forceNew){
11492 if(!forceNew && el.updateManager){
11493 return el.updateManager;
11496 * The Element object
11497 * @type Roo.Element
11501 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11504 this.defaultUrl = null;
11508 * @event beforeupdate
11509 * Fired before an update is made, return false from your handler and the update is cancelled.
11510 * @param {Roo.Element} el
11511 * @param {String/Object/Function} url
11512 * @param {String/Object} params
11514 "beforeupdate": true,
11517 * Fired after successful update is made.
11518 * @param {Roo.Element} el
11519 * @param {Object} oResponseObject The response Object
11524 * Fired on update failure.
11525 * @param {Roo.Element} el
11526 * @param {Object} oResponseObject The response Object
11530 var d = Roo.UpdateManager.defaults;
11532 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11535 this.sslBlankUrl = d.sslBlankUrl;
11537 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11540 this.disableCaching = d.disableCaching;
11542 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11545 this.indicatorText = d.indicatorText;
11547 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11550 this.showLoadIndicator = d.showLoadIndicator;
11552 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11555 this.timeout = d.timeout;
11558 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11561 this.loadScripts = d.loadScripts;
11564 * Transaction object of current executing transaction
11566 this.transaction = null;
11571 this.autoRefreshProcId = null;
11573 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11576 this.refreshDelegate = this.refresh.createDelegate(this);
11578 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11581 this.updateDelegate = this.update.createDelegate(this);
11583 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11586 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11590 this.successDelegate = this.processSuccess.createDelegate(this);
11594 this.failureDelegate = this.processFailure.createDelegate(this);
11596 if(!this.renderer){
11598 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11600 this.renderer = new Roo.UpdateManager.BasicRenderer();
11603 Roo.UpdateManager.superclass.constructor.call(this);
11606 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11608 * Get the Element this UpdateManager is bound to
11609 * @return {Roo.Element} The element
11611 getEl : function(){
11615 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11616 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11619 url: "your-url.php",<br/>
11620 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11621 callback: yourFunction,<br/>
11622 scope: yourObject, //(optional scope) <br/>
11623 discardUrl: false, <br/>
11624 nocache: false,<br/>
11625 text: "Loading...",<br/>
11627 scripts: false<br/>
11630 * The only required property is url. The optional properties nocache, text and scripts
11631 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11632 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11633 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11634 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11636 update : function(url, params, callback, discardUrl){
11637 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11638 var method = this.method, cfg;
11639 if(typeof url == "object"){ // must be config object
11642 params = params || cfg.params;
11643 callback = callback || cfg.callback;
11644 discardUrl = discardUrl || cfg.discardUrl;
11645 if(callback && cfg.scope){
11646 callback = callback.createDelegate(cfg.scope);
11648 if(typeof cfg.method != "undefined"){method = cfg.method;};
11649 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11650 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11651 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11652 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11654 this.showLoading();
11656 this.defaultUrl = url;
11658 if(typeof url == "function"){
11659 url = url.call(this);
11662 method = method || (params ? "POST" : "GET");
11663 if(method == "GET"){
11664 url = this.prepareUrl(url);
11667 var o = Roo.apply(cfg ||{}, {
11670 success: this.successDelegate,
11671 failure: this.failureDelegate,
11672 callback: undefined,
11673 timeout: (this.timeout*1000),
11674 argument: {"url": url, "form": null, "callback": callback, "params": params}
11677 this.transaction = Roo.Ajax.request(o);
11682 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11683 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11684 * @param {String/HTMLElement} form The form Id or form element
11685 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11686 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11687 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11689 formUpdate : function(form, url, reset, callback){
11690 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11691 if(typeof url == "function"){
11692 url = url.call(this);
11694 form = Roo.getDom(form);
11695 this.transaction = Roo.Ajax.request({
11698 success: this.successDelegate,
11699 failure: this.failureDelegate,
11700 timeout: (this.timeout*1000),
11701 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11703 this.showLoading.defer(1, this);
11708 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11709 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11711 refresh : function(callback){
11712 if(this.defaultUrl == null){
11715 this.update(this.defaultUrl, null, callback, true);
11719 * Set this element to auto refresh.
11720 * @param {Number} interval How often to update (in seconds).
11721 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11722 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11723 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11724 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11726 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11728 this.update(url || this.defaultUrl, params, callback, true);
11730 if(this.autoRefreshProcId){
11731 clearInterval(this.autoRefreshProcId);
11733 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11737 * Stop auto refresh on this element.
11739 stopAutoRefresh : function(){
11740 if(this.autoRefreshProcId){
11741 clearInterval(this.autoRefreshProcId);
11742 delete this.autoRefreshProcId;
11746 isAutoRefreshing : function(){
11747 return this.autoRefreshProcId ? true : false;
11750 * Called to update the element to "Loading" state. Override to perform custom action.
11752 showLoading : function(){
11753 if(this.showLoadIndicator){
11754 this.el.update(this.indicatorText);
11759 * Adds unique parameter to query string if disableCaching = true
11762 prepareUrl : function(url){
11763 if(this.disableCaching){
11764 var append = "_dc=" + (new Date().getTime());
11765 if(url.indexOf("?") !== -1){
11766 url += "&" + append;
11768 url += "?" + append;
11777 processSuccess : function(response){
11778 this.transaction = null;
11779 if(response.argument.form && response.argument.reset){
11780 try{ // put in try/catch since some older FF releases had problems with this
11781 response.argument.form.reset();
11784 if(this.loadScripts){
11785 this.renderer.render(this.el, response, this,
11786 this.updateComplete.createDelegate(this, [response]));
11788 this.renderer.render(this.el, response, this);
11789 this.updateComplete(response);
11793 updateComplete : function(response){
11794 this.fireEvent("update", this.el, response);
11795 if(typeof response.argument.callback == "function"){
11796 response.argument.callback(this.el, true, response);
11803 processFailure : function(response){
11804 this.transaction = null;
11805 this.fireEvent("failure", this.el, response);
11806 if(typeof response.argument.callback == "function"){
11807 response.argument.callback(this.el, false, response);
11812 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11813 * @param {Object} renderer The object implementing the render() method
11815 setRenderer : function(renderer){
11816 this.renderer = renderer;
11819 getRenderer : function(){
11820 return this.renderer;
11824 * Set the defaultUrl used for updates
11825 * @param {String/Function} defaultUrl The url or a function to call to get the url
11827 setDefaultUrl : function(defaultUrl){
11828 this.defaultUrl = defaultUrl;
11832 * Aborts the executing transaction
11834 abort : function(){
11835 if(this.transaction){
11836 Roo.Ajax.abort(this.transaction);
11841 * Returns true if an update is in progress
11842 * @return {Boolean}
11844 isUpdating : function(){
11845 if(this.transaction){
11846 return Roo.Ajax.isLoading(this.transaction);
11853 * @class Roo.UpdateManager.defaults
11854 * @static (not really - but it helps the doc tool)
11855 * The defaults collection enables customizing the default properties of UpdateManager
11857 Roo.UpdateManager.defaults = {
11859 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
11865 * True to process scripts by default (Defaults to false).
11868 loadScripts : false,
11871 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
11874 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
11876 * Whether to append unique parameter on get request to disable caching (Defaults to false).
11879 disableCaching : false,
11881 * Whether to show indicatorText when loading (Defaults to true).
11884 showLoadIndicator : true,
11886 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
11889 indicatorText : '<div class="loading-indicator">Loading...</div>'
11893 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
11895 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
11896 * @param {String/HTMLElement/Roo.Element} el The element to update
11897 * @param {String} url The url
11898 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
11899 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
11902 * @member Roo.UpdateManager
11904 Roo.UpdateManager.updateElement = function(el, url, params, options){
11905 var um = Roo.get(el, true).getUpdateManager();
11906 Roo.apply(um, options);
11907 um.update(url, params, options ? options.callback : null);
11909 // alias for backwards compat
11910 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
11912 * @class Roo.UpdateManager.BasicRenderer
11913 * Default Content renderer. Updates the elements innerHTML with the responseText.
11915 Roo.UpdateManager.BasicRenderer = function(){};
11917 Roo.UpdateManager.BasicRenderer.prototype = {
11919 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
11920 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
11921 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
11922 * @param {Roo.Element} el The element being rendered
11923 * @param {Object} response The YUI Connect response object
11924 * @param {UpdateManager} updateManager The calling update manager
11925 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
11927 render : function(el, response, updateManager, callback){
11928 el.update(response.responseText, updateManager.loadScripts, callback);
11933 * Ext JS Library 1.1.1
11934 * Copyright(c) 2006-2007, Ext JS, LLC.
11936 * Originally Released Under LGPL - original licence link has changed is not relivant.
11939 * <script type="text/javascript">
11943 * @class Roo.util.DelayedTask
11944 * Provides a convenient method of performing setTimeout where a new
11945 * timeout cancels the old timeout. An example would be performing validation on a keypress.
11946 * You can use this class to buffer
11947 * the keypress events for a certain number of milliseconds, and perform only if they stop
11948 * for that amount of time.
11949 * @constructor The parameters to this constructor serve as defaults and are not required.
11950 * @param {Function} fn (optional) The default function to timeout
11951 * @param {Object} scope (optional) The default scope of that timeout
11952 * @param {Array} args (optional) The default Array of arguments
11954 Roo.util.DelayedTask = function(fn, scope, args){
11955 var id = null, d, t;
11957 var call = function(){
11958 var now = new Date().getTime();
11962 fn.apply(scope, args || []);
11966 * Cancels any pending timeout and queues a new one
11967 * @param {Number} delay The milliseconds to delay
11968 * @param {Function} newFn (optional) Overrides function passed to constructor
11969 * @param {Object} newScope (optional) Overrides scope passed to constructor
11970 * @param {Array} newArgs (optional) Overrides args passed to constructor
11972 this.delay = function(delay, newFn, newScope, newArgs){
11973 if(id && delay != d){
11977 t = new Date().getTime();
11979 scope = newScope || scope;
11980 args = newArgs || args;
11982 id = setInterval(call, d);
11987 * Cancel the last queued timeout
11989 this.cancel = function(){
11997 * Ext JS Library 1.1.1
11998 * Copyright(c) 2006-2007, Ext JS, LLC.
12000 * Originally Released Under LGPL - original licence link has changed is not relivant.
12003 * <script type="text/javascript">
12007 Roo.util.TaskRunner = function(interval){
12008 interval = interval || 10;
12009 var tasks = [], removeQueue = [];
12011 var running = false;
12013 var stopThread = function(){
12019 var startThread = function(){
12022 id = setInterval(runTasks, interval);
12026 var removeTask = function(task){
12027 removeQueue.push(task);
12033 var runTasks = function(){
12034 if(removeQueue.length > 0){
12035 for(var i = 0, len = removeQueue.length; i < len; i++){
12036 tasks.remove(removeQueue[i]);
12039 if(tasks.length < 1){
12044 var now = new Date().getTime();
12045 for(var i = 0, len = tasks.length; i < len; ++i){
12047 var itime = now - t.taskRunTime;
12048 if(t.interval <= itime){
12049 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12050 t.taskRunTime = now;
12051 if(rt === false || t.taskRunCount === t.repeat){
12056 if(t.duration && t.duration <= (now - t.taskStartTime)){
12063 * Queues a new task.
12064 * @param {Object} task
12066 this.start = function(task){
12068 task.taskStartTime = new Date().getTime();
12069 task.taskRunTime = 0;
12070 task.taskRunCount = 0;
12075 this.stop = function(task){
12080 this.stopAll = function(){
12082 for(var i = 0, len = tasks.length; i < len; i++){
12083 if(tasks[i].onStop){
12092 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12094 * Ext JS Library 1.1.1
12095 * Copyright(c) 2006-2007, Ext JS, LLC.
12097 * Originally Released Under LGPL - original licence link has changed is not relivant.
12100 * <script type="text/javascript">
12105 * @class Roo.util.MixedCollection
12106 * @extends Roo.util.Observable
12107 * A Collection class that maintains both numeric indexes and keys and exposes events.
12109 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12110 * collection (defaults to false)
12111 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12112 * and return the key value for that item. This is used when available to look up the key on items that
12113 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12114 * equivalent to providing an implementation for the {@link #getKey} method.
12116 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12124 * Fires when the collection is cleared.
12129 * Fires when an item is added to the collection.
12130 * @param {Number} index The index at which the item was added.
12131 * @param {Object} o The item added.
12132 * @param {String} key The key associated with the added item.
12137 * Fires when an item is replaced in the collection.
12138 * @param {String} key he key associated with the new added.
12139 * @param {Object} old The item being replaced.
12140 * @param {Object} new The new item.
12145 * Fires when an item is removed from the collection.
12146 * @param {Object} o The item being removed.
12147 * @param {String} key (optional) The key associated with the removed item.
12152 this.allowFunctions = allowFunctions === true;
12154 this.getKey = keyFn;
12156 Roo.util.MixedCollection.superclass.constructor.call(this);
12159 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12160 allowFunctions : false,
12163 * Adds an item to the collection.
12164 * @param {String} key The key to associate with the item
12165 * @param {Object} o The item to add.
12166 * @return {Object} The item added.
12168 add : function(key, o){
12169 if(arguments.length == 1){
12171 key = this.getKey(o);
12173 if(typeof key == "undefined" || key === null){
12175 this.items.push(o);
12176 this.keys.push(null);
12178 var old = this.map[key];
12180 return this.replace(key, o);
12183 this.items.push(o);
12185 this.keys.push(key);
12187 this.fireEvent("add", this.length-1, o, key);
12192 * MixedCollection has a generic way to fetch keys if you implement getKey.
12195 var mc = new Roo.util.MixedCollection();
12196 mc.add(someEl.dom.id, someEl);
12197 mc.add(otherEl.dom.id, otherEl);
12201 var mc = new Roo.util.MixedCollection();
12202 mc.getKey = function(el){
12208 // or via the constructor
12209 var mc = new Roo.util.MixedCollection(false, function(el){
12215 * @param o {Object} The item for which to find the key.
12216 * @return {Object} The key for the passed item.
12218 getKey : function(o){
12223 * Replaces an item in the collection.
12224 * @param {String} key The key associated with the item to replace, or the item to replace.
12225 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12226 * @return {Object} The new item.
12228 replace : function(key, o){
12229 if(arguments.length == 1){
12231 key = this.getKey(o);
12233 var old = this.item(key);
12234 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12235 return this.add(key, o);
12237 var index = this.indexOfKey(key);
12238 this.items[index] = o;
12240 this.fireEvent("replace", key, old, o);
12245 * Adds all elements of an Array or an Object to the collection.
12246 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12247 * an Array of values, each of which are added to the collection.
12249 addAll : function(objs){
12250 if(arguments.length > 1 || objs instanceof Array){
12251 var args = arguments.length > 1 ? arguments : objs;
12252 for(var i = 0, len = args.length; i < len; i++){
12256 for(var key in objs){
12257 if(this.allowFunctions || typeof objs[key] != "function"){
12258 this.add(key, objs[key]);
12265 * Executes the specified function once for every item in the collection, passing each
12266 * item as the first and only parameter. returning false from the function will stop the iteration.
12267 * @param {Function} fn The function to execute for each item.
12268 * @param {Object} scope (optional) The scope in which to execute the function.
12270 each : function(fn, scope){
12271 var items = [].concat(this.items); // each safe for removal
12272 for(var i = 0, len = items.length; i < len; i++){
12273 if(fn.call(scope || items[i], items[i], i, len) === false){
12280 * Executes the specified function once for every key in the collection, passing each
12281 * key, and its associated item as the first two parameters.
12282 * @param {Function} fn The function to execute for each item.
12283 * @param {Object} scope (optional) The scope in which to execute the function.
12285 eachKey : function(fn, scope){
12286 for(var i = 0, len = this.keys.length; i < len; i++){
12287 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12292 * Returns the first item in the collection which elicits a true return value from the
12293 * passed selection function.
12294 * @param {Function} fn The selection function to execute for each item.
12295 * @param {Object} scope (optional) The scope in which to execute the function.
12296 * @return {Object} The first item in the collection which returned true from the selection function.
12298 find : function(fn, scope){
12299 for(var i = 0, len = this.items.length; i < len; i++){
12300 if(fn.call(scope || window, this.items[i], this.keys[i])){
12301 return this.items[i];
12308 * Inserts an item at the specified index in the collection.
12309 * @param {Number} index The index to insert the item at.
12310 * @param {String} key The key to associate with the new item, or the item itself.
12311 * @param {Object} o (optional) If the second parameter was a key, the new item.
12312 * @return {Object} The item inserted.
12314 insert : function(index, key, o){
12315 if(arguments.length == 2){
12317 key = this.getKey(o);
12319 if(index >= this.length){
12320 return this.add(key, o);
12323 this.items.splice(index, 0, o);
12324 if(typeof key != "undefined" && key != null){
12327 this.keys.splice(index, 0, key);
12328 this.fireEvent("add", index, o, key);
12333 * Removed an item from the collection.
12334 * @param {Object} o The item to remove.
12335 * @return {Object} The item removed.
12337 remove : function(o){
12338 return this.removeAt(this.indexOf(o));
12342 * Remove an item from a specified index in the collection.
12343 * @param {Number} index The index within the collection of the item to remove.
12345 removeAt : function(index){
12346 if(index < this.length && index >= 0){
12348 var o = this.items[index];
12349 this.items.splice(index, 1);
12350 var key = this.keys[index];
12351 if(typeof key != "undefined"){
12352 delete this.map[key];
12354 this.keys.splice(index, 1);
12355 this.fireEvent("remove", o, key);
12360 * Removed an item associated with the passed key fom the collection.
12361 * @param {String} key The key of the item to remove.
12363 removeKey : function(key){
12364 return this.removeAt(this.indexOfKey(key));
12368 * Returns the number of items in the collection.
12369 * @return {Number} the number of items in the collection.
12371 getCount : function(){
12372 return this.length;
12376 * Returns index within the collection of the passed Object.
12377 * @param {Object} o The item to find the index of.
12378 * @return {Number} index of the item.
12380 indexOf : function(o){
12381 if(!this.items.indexOf){
12382 for(var i = 0, len = this.items.length; i < len; i++){
12383 if(this.items[i] == o) return i;
12387 return this.items.indexOf(o);
12392 * Returns index within the collection of the passed key.
12393 * @param {String} key The key to find the index of.
12394 * @return {Number} index of the key.
12396 indexOfKey : function(key){
12397 if(!this.keys.indexOf){
12398 for(var i = 0, len = this.keys.length; i < len; i++){
12399 if(this.keys[i] == key) return i;
12403 return this.keys.indexOf(key);
12408 * Returns the item associated with the passed key OR index. Key has priority over index.
12409 * @param {String/Number} key The key or index of the item.
12410 * @return {Object} The item associated with the passed key.
12412 item : function(key){
12413 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12414 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12418 * Returns the item at the specified index.
12419 * @param {Number} index The index of the item.
12422 itemAt : function(index){
12423 return this.items[index];
12427 * Returns the item associated with the passed key.
12428 * @param {String/Number} key The key of the item.
12429 * @return {Object} The item associated with the passed key.
12431 key : function(key){
12432 return this.map[key];
12436 * Returns true if the collection contains the passed Object as an item.
12437 * @param {Object} o The Object to look for in the collection.
12438 * @return {Boolean} True if the collection contains the Object as an item.
12440 contains : function(o){
12441 return this.indexOf(o) != -1;
12445 * Returns true if the collection contains the passed Object as a key.
12446 * @param {String} key The key to look for in the collection.
12447 * @return {Boolean} True if the collection contains the Object as a key.
12449 containsKey : function(key){
12450 return typeof this.map[key] != "undefined";
12454 * Removes all items from the collection.
12456 clear : function(){
12461 this.fireEvent("clear");
12465 * Returns the first item in the collection.
12466 * @return {Object} the first item in the collection..
12468 first : function(){
12469 return this.items[0];
12473 * Returns the last item in the collection.
12474 * @return {Object} the last item in the collection..
12477 return this.items[this.length-1];
12480 _sort : function(property, dir, fn){
12481 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12482 fn = fn || function(a, b){
12485 var c = [], k = this.keys, items = this.items;
12486 for(var i = 0, len = items.length; i < len; i++){
12487 c[c.length] = {key: k[i], value: items[i], index: i};
12489 c.sort(function(a, b){
12490 var v = fn(a[property], b[property]) * dsc;
12492 v = (a.index < b.index ? -1 : 1);
12496 for(var i = 0, len = c.length; i < len; i++){
12497 items[i] = c[i].value;
12500 this.fireEvent("sort", this);
12504 * Sorts this collection with the passed comparison function
12505 * @param {String} direction (optional) "ASC" or "DESC"
12506 * @param {Function} fn (optional) comparison function
12508 sort : function(dir, fn){
12509 this._sort("value", dir, fn);
12513 * Sorts this collection by keys
12514 * @param {String} direction (optional) "ASC" or "DESC"
12515 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12517 keySort : function(dir, fn){
12518 this._sort("key", dir, fn || function(a, b){
12519 return String(a).toUpperCase()-String(b).toUpperCase();
12524 * Returns a range of items in this collection
12525 * @param {Number} startIndex (optional) defaults to 0
12526 * @param {Number} endIndex (optional) default to the last item
12527 * @return {Array} An array of items
12529 getRange : function(start, end){
12530 var items = this.items;
12531 if(items.length < 1){
12534 start = start || 0;
12535 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12538 for(var i = start; i <= end; i++) {
12539 r[r.length] = items[i];
12542 for(var i = start; i >= end; i--) {
12543 r[r.length] = items[i];
12550 * Filter the <i>objects</i> in this collection by a specific property.
12551 * Returns a new collection that has been filtered.
12552 * @param {String} property A property on your objects
12553 * @param {String/RegExp} value Either string that the property values
12554 * should start with or a RegExp to test against the property
12555 * @return {MixedCollection} The new filtered collection
12557 filter : function(property, value){
12558 if(!value.exec){ // not a regex
12559 value = String(value);
12560 if(value.length == 0){
12561 return this.clone();
12563 value = new RegExp("^" + Roo.escapeRe(value), "i");
12565 return this.filterBy(function(o){
12566 return o && value.test(o[property]);
12571 * Filter by a function. * Returns a new collection that has been filtered.
12572 * The passed function will be called with each
12573 * object in the collection. If the function returns true, the value is included
12574 * otherwise it is filtered.
12575 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12576 * @param {Object} scope (optional) The scope of the function (defaults to this)
12577 * @return {MixedCollection} The new filtered collection
12579 filterBy : function(fn, scope){
12580 var r = new Roo.util.MixedCollection();
12581 r.getKey = this.getKey;
12582 var k = this.keys, it = this.items;
12583 for(var i = 0, len = it.length; i < len; i++){
12584 if(fn.call(scope||this, it[i], k[i])){
12585 r.add(k[i], it[i]);
12592 * Creates a duplicate of this collection
12593 * @return {MixedCollection}
12595 clone : function(){
12596 var r = new Roo.util.MixedCollection();
12597 var k = this.keys, it = this.items;
12598 for(var i = 0, len = it.length; i < len; i++){
12599 r.add(k[i], it[i]);
12601 r.getKey = this.getKey;
12606 * Returns the item associated with the passed key or index.
12608 * @param {String/Number} key The key or index of the item.
12609 * @return {Object} The item associated with the passed key.
12611 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12613 * Ext JS Library 1.1.1
12614 * Copyright(c) 2006-2007, Ext JS, LLC.
12616 * Originally Released Under LGPL - original licence link has changed is not relivant.
12619 * <script type="text/javascript">
12622 * @class Roo.util.JSON
12623 * Modified version of Douglas Crockford"s json.js that doesn"t
12624 * mess with the Object prototype
12625 * http://www.json.org/js.html
12628 Roo.util.JSON = new (function(){
12629 var useHasOwn = {}.hasOwnProperty ? true : false;
12631 // crashes Safari in some instances
12632 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12634 var pad = function(n) {
12635 return n < 10 ? "0" + n : n;
12648 var encodeString = function(s){
12649 if (/["\\\x00-\x1f]/.test(s)) {
12650 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12655 c = b.charCodeAt();
12657 Math.floor(c / 16).toString(16) +
12658 (c % 16).toString(16);
12661 return '"' + s + '"';
12664 var encodeArray = function(o){
12665 var a = ["["], b, i, l = o.length, v;
12666 for (i = 0; i < l; i += 1) {
12668 switch (typeof v) {
12677 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12685 var encodeDate = function(o){
12686 return '"' + o.getFullYear() + "-" +
12687 pad(o.getMonth() + 1) + "-" +
12688 pad(o.getDate()) + "T" +
12689 pad(o.getHours()) + ":" +
12690 pad(o.getMinutes()) + ":" +
12691 pad(o.getSeconds()) + '"';
12695 * Encodes an Object, Array or other value
12696 * @param {Mixed} o The variable to encode
12697 * @return {String} The JSON string
12699 this.encode = function(o){
12700 if(typeof o == "undefined" || o === null){
12702 }else if(o instanceof Array){
12703 return encodeArray(o);
12704 }else if(o instanceof Date){
12705 return encodeDate(o);
12706 }else if(typeof o == "string"){
12707 return encodeString(o);
12708 }else if(typeof o == "number"){
12709 return isFinite(o) ? String(o) : "null";
12710 }else if(typeof o == "boolean"){
12713 var a = ["{"], b, i, v;
12715 if(!useHasOwn || o.hasOwnProperty(i)) {
12717 switch (typeof v) {
12726 a.push(this.encode(i), ":",
12727 v === null ? "null" : this.encode(v));
12738 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12739 * @param {String} json The JSON string
12740 * @return {Object} The resulting object
12742 this.decode = function(json){
12746 return eval("(" + json + ')');
12750 * Shorthand for {@link Roo.util.JSON#encode}
12751 * @member Roo encode
12753 Roo.encode = Roo.util.JSON.encode;
12755 * Shorthand for {@link Roo.util.JSON#decode}
12756 * @member Roo decode
12758 Roo.decode = Roo.util.JSON.decode;
12761 * Ext JS Library 1.1.1
12762 * Copyright(c) 2006-2007, Ext JS, LLC.
12764 * Originally Released Under LGPL - original licence link has changed is not relivant.
12767 * <script type="text/javascript">
12771 * @class Roo.util.Format
12772 * Reusable data formatting functions
12775 Roo.util.Format = function(){
12776 var trimRe = /^\s+|\s+$/g;
12779 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12780 * @param {String} value The string to truncate
12781 * @param {Number} length The maximum length to allow before truncating
12782 * @return {String} The converted text
12784 ellipsis : function(value, len){
12785 if(value && value.length > len){
12786 return value.substr(0, len-3)+"...";
12792 * Checks a reference and converts it to empty string if it is undefined
12793 * @param {Mixed} value Reference to check
12794 * @return {Mixed} Empty string if converted, otherwise the original value
12796 undef : function(value){
12797 return typeof value != "undefined" ? value : "";
12801 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12802 * @param {String} value The string to encode
12803 * @return {String} The encoded text
12805 htmlEncode : function(value){
12806 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
12810 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12811 * @param {String} value The string to decode
12812 * @return {String} The decoded text
12814 htmlDecode : function(value){
12815 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
12819 * Trims any whitespace from either side of a string
12820 * @param {String} value The text to trim
12821 * @return {String} The trimmed text
12823 trim : function(value){
12824 return String(value).replace(trimRe, "");
12828 * Returns a substring from within an original string
12829 * @param {String} value The original text
12830 * @param {Number} start The start index of the substring
12831 * @param {Number} length The length of the substring
12832 * @return {String} The substring
12834 substr : function(value, start, length){
12835 return String(value).substr(start, length);
12839 * Converts a string to all lower case letters
12840 * @param {String} value The text to convert
12841 * @return {String} The converted text
12843 lowercase : function(value){
12844 return String(value).toLowerCase();
12848 * Converts a string to all upper case letters
12849 * @param {String} value The text to convert
12850 * @return {String} The converted text
12852 uppercase : function(value){
12853 return String(value).toUpperCase();
12857 * Converts the first character only of a string to upper case
12858 * @param {String} value The text to convert
12859 * @return {String} The converted text
12861 capitalize : function(value){
12862 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12866 call : function(value, fn){
12867 if(arguments.length > 2){
12868 var args = Array.prototype.slice.call(arguments, 2);
12869 args.unshift(value);
12871 return /** eval:var:value */ eval(fn).apply(window, args);
12873 /** eval:var:value */
12874 return /** eval:var:value */ eval(fn).call(window, value);
12879 * Format a number as US currency
12880 * @param {Number/String} value The numeric value to format
12881 * @return {String} The formatted currency string
12883 usMoney : function(v){
12884 v = (Math.round((v-0)*100))/100;
12885 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12887 var ps = v.split('.');
12889 var sub = ps[1] ? '.'+ ps[1] : '.00';
12890 var r = /(\d+)(\d{3})/;
12891 while (r.test(whole)) {
12892 whole = whole.replace(r, '$1' + ',' + '$2');
12894 return "$" + whole + sub ;
12898 * Parse a value into a formatted date using the specified format pattern.
12899 * @param {Mixed} value The value to format
12900 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12901 * @return {String} The formatted date string
12903 date : function(v, format){
12907 if(!(v instanceof Date)){
12908 v = new Date(Date.parse(v));
12910 return v.dateFormat(format || "m/d/Y");
12914 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12915 * @param {String} format Any valid date format string
12916 * @return {Function} The date formatting function
12918 dateRenderer : function(format){
12919 return function(v){
12920 return Roo.util.Format.date(v, format);
12925 stripTagsRE : /<\/?[^>]+>/gi,
12928 * Strips all HTML tags
12929 * @param {Mixed} value The text from which to strip tags
12930 * @return {String} The stripped text
12932 stripTags : function(v){
12933 return !v ? v : String(v).replace(this.stripTagsRE, "");
12938 * Ext JS Library 1.1.1
12939 * Copyright(c) 2006-2007, Ext JS, LLC.
12941 * Originally Released Under LGPL - original licence link has changed is not relivant.
12944 * <script type="text/javascript">
12951 * @class Roo.MasterTemplate
12952 * @extends Roo.Template
12953 * Provides a template that can have child templates. The syntax is:
12955 var t = new Roo.MasterTemplate(
12956 '<select name="{name}">',
12957 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
12960 t.add('options', {value: 'foo', text: 'bar'});
12961 // or you can add multiple child elements in one shot
12962 t.addAll('options', [
12963 {value: 'foo', text: 'bar'},
12964 {value: 'foo2', text: 'bar2'},
12965 {value: 'foo3', text: 'bar3'}
12967 // then append, applying the master template values
12968 t.append('my-form', {name: 'my-select'});
12970 * A name attribute for the child template is not required if you have only one child
12971 * template or you want to refer to them by index.
12973 Roo.MasterTemplate = function(){
12974 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
12975 this.originalHtml = this.html;
12977 var m, re = this.subTemplateRe;
12980 while(m = re.exec(this.html)){
12981 var name = m[1], content = m[2];
12986 tpl : new Roo.Template(content)
12989 st[name] = st[subIndex];
12991 st[subIndex].tpl.compile();
12992 st[subIndex].tpl.call = this.call.createDelegate(this);
12995 this.subCount = subIndex;
12998 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13000 * The regular expression used to match sub templates
13004 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13007 * Applies the passed values to a child template.
13008 * @param {String/Number} name (optional) The name or index of the child template
13009 * @param {Array/Object} values The values to be applied to the template
13010 * @return {MasterTemplate} this
13012 add : function(name, values){
13013 if(arguments.length == 1){
13014 values = arguments[0];
13017 var s = this.subs[name];
13018 s.buffer[s.buffer.length] = s.tpl.apply(values);
13023 * Applies all the passed values to a child template.
13024 * @param {String/Number} name (optional) The name or index of the child template
13025 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13026 * @param {Boolean} reset (optional) True to reset the template first
13027 * @return {MasterTemplate} this
13029 fill : function(name, values, reset){
13031 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13039 for(var i = 0, len = values.length; i < len; i++){
13040 this.add(name, values[i]);
13046 * Resets the template for reuse
13047 * @return {MasterTemplate} this
13049 reset : function(){
13051 for(var i = 0; i < this.subCount; i++){
13057 applyTemplate : function(values){
13059 var replaceIndex = -1;
13060 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13061 return s[++replaceIndex].buffer.join("");
13063 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13066 apply : function(){
13067 return this.applyTemplate.apply(this, arguments);
13070 compile : function(){return this;}
13074 * Alias for fill().
13077 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13079 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13080 * var tpl = Roo.MasterTemplate.from('element-id');
13081 * @param {String/HTMLElement} el
13082 * @param {Object} config
13085 Roo.MasterTemplate.from = function(el, config){
13086 el = Roo.getDom(el);
13087 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13090 * Ext JS Library 1.1.1
13091 * Copyright(c) 2006-2007, Ext JS, LLC.
13093 * Originally Released Under LGPL - original licence link has changed is not relivant.
13096 * <script type="text/javascript">
13101 * @class Roo.util.CSS
13102 * Utility class for manipulating CSS rules
13105 Roo.util.CSS = function(){
13107 var doc = document;
13109 var camelRe = /(-[a-z])/gi;
13110 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13114 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13115 * tag and appended to the HEAD of the document.
13116 * @param {String} cssText The text containing the css rules
13117 * @param {String} id An id to add to the stylesheet for later removal
13118 * @return {StyleSheet}
13120 createStyleSheet : function(cssText, id){
13122 var head = doc.getElementsByTagName("head")[0];
13123 var rules = doc.createElement("style");
13124 rules.setAttribute("type", "text/css");
13126 rules.setAttribute("id", id);
13129 head.appendChild(rules);
13130 ss = rules.styleSheet;
13131 ss.cssText = cssText;
13134 rules.appendChild(doc.createTextNode(cssText));
13136 rules.cssText = cssText;
13138 head.appendChild(rules);
13139 ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13141 this.cacheStyleSheet(ss);
13146 * Removes a style or link tag by id
13147 * @param {String} id The id of the tag
13149 removeStyleSheet : function(id){
13150 var existing = doc.getElementById(id);
13152 existing.parentNode.removeChild(existing);
13157 * Dynamically swaps an existing stylesheet reference for a new one
13158 * @param {String} id The id of an existing link tag to remove
13159 * @param {String} url The href of the new stylesheet to include
13161 swapStyleSheet : function(id, url){
13162 this.removeStyleSheet(id);
13163 var ss = doc.createElement("link");
13164 ss.setAttribute("rel", "stylesheet");
13165 ss.setAttribute("type", "text/css");
13166 ss.setAttribute("id", id);
13167 ss.setAttribute("href", url);
13168 doc.getElementsByTagName("head")[0].appendChild(ss);
13172 * Refresh the rule cache if you have dynamically added stylesheets
13173 * @return {Object} An object (hash) of rules indexed by selector
13175 refreshCache : function(){
13176 return this.getRules(true);
13180 cacheStyleSheet : function(ss){
13184 try{// try catch for cross domain access issue
13185 var ssRules = ss.cssRules || ss.rules;
13186 for(var j = ssRules.length-1; j >= 0; --j){
13187 rules[ssRules[j].selectorText] = ssRules[j];
13193 * Gets all css rules for the document
13194 * @param {Boolean} refreshCache true to refresh the internal cache
13195 * @return {Object} An object (hash) of rules indexed by selector
13197 getRules : function(refreshCache){
13198 if(rules == null || refreshCache){
13200 var ds = doc.styleSheets;
13201 for(var i =0, len = ds.length; i < len; i++){
13203 this.cacheStyleSheet(ds[i]);
13211 * Gets an an individual CSS rule by selector(s)
13212 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13213 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13214 * @return {CSSRule} The CSS rule or null if one is not found
13216 getRule : function(selector, refreshCache){
13217 var rs = this.getRules(refreshCache);
13218 if(!(selector instanceof Array)){
13219 return rs[selector];
13221 for(var i = 0; i < selector.length; i++){
13222 if(rs[selector[i]]){
13223 return rs[selector[i]];
13231 * Updates a rule property
13232 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13233 * @param {String} property The css property
13234 * @param {String} value The new value for the property
13235 * @return {Boolean} true If a rule was found and updated
13237 updateRule : function(selector, property, value){
13238 if(!(selector instanceof Array)){
13239 var rule = this.getRule(selector);
13241 rule.style[property.replace(camelRe, camelFn)] = value;
13245 for(var i = 0; i < selector.length; i++){
13246 if(this.updateRule(selector[i], property, value)){
13256 * Ext JS Library 1.1.1
13257 * Copyright(c) 2006-2007, Ext JS, LLC.
13259 * Originally Released Under LGPL - original licence link has changed is not relivant.
13262 * <script type="text/javascript">
13268 * @class Roo.util.ClickRepeater
13269 * @extends Roo.util.Observable
13271 * A wrapper class which can be applied to any element. Fires a "click" event while the
13272 * mouse is pressed. The interval between firings may be specified in the config but
13273 * defaults to 10 milliseconds.
13275 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13277 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13278 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13279 * Similar to an autorepeat key delay.
13280 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13281 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13282 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13283 * "interval" and "delay" are ignored. "immediate" is honored.
13284 * @cfg {Boolean} preventDefault True to prevent the default click event
13285 * @cfg {Boolean} stopDefault True to stop the default click event
13288 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13289 * 2007-02-02 jvs Renamed to ClickRepeater
13290 * 2007-02-03 jvs Modifications for FF Mac and Safari
13293 * @param {String/HTMLElement/Element} el The element to listen on
13294 * @param {Object} config
13296 Roo.util.ClickRepeater = function(el, config)
13298 this.el = Roo.get(el);
13299 this.el.unselectable();
13301 Roo.apply(this, config);
13306 * Fires when the mouse button is depressed.
13307 * @param {Roo.util.ClickRepeater} this
13309 "mousedown" : true,
13312 * Fires on a specified interval during the time the element is pressed.
13313 * @param {Roo.util.ClickRepeater} this
13318 * Fires when the mouse key is released.
13319 * @param {Roo.util.ClickRepeater} this
13324 this.el.on("mousedown", this.handleMouseDown, this);
13325 if(this.preventDefault || this.stopDefault){
13326 this.el.on("click", function(e){
13327 if(this.preventDefault){
13328 e.preventDefault();
13330 if(this.stopDefault){
13336 // allow inline handler
13338 this.on("click", this.handler, this.scope || this);
13341 Roo.util.ClickRepeater.superclass.constructor.call(this);
13344 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13347 preventDefault : true,
13348 stopDefault : false,
13352 handleMouseDown : function(){
13353 clearTimeout(this.timer);
13355 if(this.pressClass){
13356 this.el.addClass(this.pressClass);
13358 this.mousedownTime = new Date();
13360 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13361 this.el.on("mouseout", this.handleMouseOut, this);
13363 this.fireEvent("mousedown", this);
13364 this.fireEvent("click", this);
13366 this.timer = this.click.defer(this.delay || this.interval, this);
13370 click : function(){
13371 this.fireEvent("click", this);
13372 this.timer = this.click.defer(this.getInterval(), this);
13376 getInterval: function(){
13377 if(!this.accelerate){
13378 return this.interval;
13380 var pressTime = this.mousedownTime.getElapsed();
13381 if(pressTime < 500){
13383 }else if(pressTime < 1700){
13385 }else if(pressTime < 2600){
13387 }else if(pressTime < 3500){
13389 }else if(pressTime < 4400){
13391 }else if(pressTime < 5300){
13393 }else if(pressTime < 6200){
13401 handleMouseOut : function(){
13402 clearTimeout(this.timer);
13403 if(this.pressClass){
13404 this.el.removeClass(this.pressClass);
13406 this.el.on("mouseover", this.handleMouseReturn, this);
13410 handleMouseReturn : function(){
13411 this.el.un("mouseover", this.handleMouseReturn);
13412 if(this.pressClass){
13413 this.el.addClass(this.pressClass);
13419 handleMouseUp : function(){
13420 clearTimeout(this.timer);
13421 this.el.un("mouseover", this.handleMouseReturn);
13422 this.el.un("mouseout", this.handleMouseOut);
13423 Roo.get(document).un("mouseup", this.handleMouseUp);
13424 this.el.removeClass(this.pressClass);
13425 this.fireEvent("mouseup", this);
13429 * Ext JS Library 1.1.1
13430 * Copyright(c) 2006-2007, Ext JS, LLC.
13432 * Originally Released Under LGPL - original licence link has changed is not relivant.
13435 * <script type="text/javascript">
13440 * @class Roo.KeyNav
13441 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13442 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13443 * way to implement custom navigation schemes for any UI component.</p>
13444 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13445 * pageUp, pageDown, del, home, end. Usage:</p>
13447 var nav = new Roo.KeyNav("my-element", {
13448 "left" : function(e){
13449 this.moveLeft(e.ctrlKey);
13451 "right" : function(e){
13452 this.moveRight(e.ctrlKey);
13454 "enter" : function(e){
13461 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13462 * @param {Object} config The config
13464 Roo.KeyNav = function(el, config){
13465 this.el = Roo.get(el);
13466 Roo.apply(this, config);
13467 if(!this.disabled){
13468 this.disabled = true;
13473 Roo.KeyNav.prototype = {
13475 * @cfg {Boolean} disabled
13476 * True to disable this KeyNav instance (defaults to false)
13480 * @cfg {String} defaultEventAction
13481 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13482 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13483 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13485 defaultEventAction: "stopEvent",
13487 * @cfg {Boolean} forceKeyDown
13488 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13489 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13490 * handle keydown instead of keypress.
13492 forceKeyDown : false,
13495 prepareEvent : function(e){
13496 var k = e.getKey();
13497 var h = this.keyToHandler[k];
13498 //if(h && this[h]){
13499 // e.stopPropagation();
13501 if(Roo.isSafari && h && k >= 37 && k <= 40){
13507 relay : function(e){
13508 var k = e.getKey();
13509 var h = this.keyToHandler[k];
13511 if(this.doRelay(e, this[h], h) !== true){
13512 e[this.defaultEventAction]();
13518 doRelay : function(e, h, hname){
13519 return h.call(this.scope || this, e);
13522 // possible handlers
13536 // quick lookup hash
13553 * Enable this KeyNav
13555 enable: function(){
13557 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13558 // the EventObject will normalize Safari automatically
13559 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13560 this.el.on("keydown", this.relay, this);
13562 this.el.on("keydown", this.prepareEvent, this);
13563 this.el.on("keypress", this.relay, this);
13565 this.disabled = false;
13570 * Disable this KeyNav
13572 disable: function(){
13573 if(!this.disabled){
13574 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13575 this.el.un("keydown", this.relay);
13577 this.el.un("keydown", this.prepareEvent);
13578 this.el.un("keypress", this.relay);
13580 this.disabled = true;
13585 * Ext JS Library 1.1.1
13586 * Copyright(c) 2006-2007, Ext JS, LLC.
13588 * Originally Released Under LGPL - original licence link has changed is not relivant.
13591 * <script type="text/javascript">
13596 * @class Roo.KeyMap
13597 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13598 * The constructor accepts the same config object as defined by {@link #addBinding}.
13599 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13600 * combination it will call the function with this signature (if the match is a multi-key
13601 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13602 * A KeyMap can also handle a string representation of keys.<br />
13605 // map one key by key code
13606 var map = new Roo.KeyMap("my-element", {
13607 key: 13, // or Roo.EventObject.ENTER
13612 // map multiple keys to one action by string
13613 var map = new Roo.KeyMap("my-element", {
13619 // map multiple keys to multiple actions by strings and array of codes
13620 var map = new Roo.KeyMap("my-element", [
13623 fn: function(){ alert("Return was pressed"); }
13626 fn: function(){ alert('a, b or c was pressed'); }
13631 fn: function(){ alert('Control + shift + tab was pressed.'); }
13635 * <b>Note: A KeyMap starts enabled</b>
13637 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13638 * @param {Object} config The config (see {@link #addBinding})
13639 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13641 Roo.KeyMap = function(el, config, eventName){
13642 this.el = Roo.get(el);
13643 this.eventName = eventName || "keydown";
13644 this.bindings = [];
13646 this.addBinding(config);
13651 Roo.KeyMap.prototype = {
13653 * True to stop the event from bubbling and prevent the default browser action if the
13654 * key was handled by the KeyMap (defaults to false)
13660 * Add a new binding to this KeyMap. The following config object properties are supported:
13662 Property Type Description
13663 ---------- --------------- ----------------------------------------------------------------------
13664 key String/Array A single keycode or an array of keycodes to handle
13665 shift Boolean True to handle key only when shift is pressed (defaults to false)
13666 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13667 alt Boolean True to handle key only when alt is pressed (defaults to false)
13668 fn Function The function to call when KeyMap finds the expected key combination
13669 scope Object The scope of the callback function
13675 var map = new Roo.KeyMap(document, {
13676 key: Roo.EventObject.ENTER,
13681 //Add a new binding to the existing KeyMap later
13689 * @param {Object/Array} config A single KeyMap config or an array of configs
13691 addBinding : function(config){
13692 if(config instanceof Array){
13693 for(var i = 0, len = config.length; i < len; i++){
13694 this.addBinding(config[i]);
13698 var keyCode = config.key,
13699 shift = config.shift,
13700 ctrl = config.ctrl,
13703 scope = config.scope;
13704 if(typeof keyCode == "string"){
13706 var keyString = keyCode.toUpperCase();
13707 for(var j = 0, len = keyString.length; j < len; j++){
13708 ks.push(keyString.charCodeAt(j));
13712 var keyArray = keyCode instanceof Array;
13713 var handler = function(e){
13714 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13715 var k = e.getKey();
13717 for(var i = 0, len = keyCode.length; i < len; i++){
13718 if(keyCode[i] == k){
13719 if(this.stopEvent){
13722 fn.call(scope || window, k, e);
13728 if(this.stopEvent){
13731 fn.call(scope || window, k, e);
13736 this.bindings.push(handler);
13740 * Shorthand for adding a single key listener
13741 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
13742 * following options:
13743 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
13744 * @param {Function} fn The function to call
13745 * @param {Object} scope (optional) The scope of the function
13747 on : function(key, fn, scope){
13748 var keyCode, shift, ctrl, alt;
13749 if(typeof key == "object" && !(key instanceof Array)){
13768 handleKeyDown : function(e){
13769 if(this.enabled){ //just in case
13770 var b = this.bindings;
13771 for(var i = 0, len = b.length; i < len; i++){
13772 b[i].call(this, e);
13778 * Returns true if this KeyMap is enabled
13779 * @return {Boolean}
13781 isEnabled : function(){
13782 return this.enabled;
13786 * Enables this KeyMap
13788 enable: function(){
13790 this.el.on(this.eventName, this.handleKeyDown, this);
13791 this.enabled = true;
13796 * Disable this KeyMap
13798 disable: function(){
13800 this.el.removeListener(this.eventName, this.handleKeyDown, this);
13801 this.enabled = false;
13806 * Ext JS Library 1.1.1
13807 * Copyright(c) 2006-2007, Ext JS, LLC.
13809 * Originally Released Under LGPL - original licence link has changed is not relivant.
13812 * <script type="text/javascript">
13817 * @class Roo.util.TextMetrics
13818 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13819 * wide, in pixels, a given block of text will be.
13822 Roo.util.TextMetrics = function(){
13826 * Measures the size of the specified text
13827 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13828 * that can affect the size of the rendered text
13829 * @param {String} text The text to measure
13830 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13831 * in order to accurately measure the text height
13832 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13834 measure : function(el, text, fixedWidth){
13836 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
13839 shared.setFixedWidth(fixedWidth || 'auto');
13840 return shared.getSize(text);
13844 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13845 * the overhead of multiple calls to initialize the style properties on each measurement.
13846 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13847 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13848 * in order to accurately measure the text height
13849 * @return {Roo.util.TextMetrics.Instance} instance The new instance
13851 createInstance : function(el, fixedWidth){
13852 return Roo.util.TextMetrics.Instance(el, fixedWidth);
13857 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13858 var ml = new Roo.Element(document.createElement('div'));
13859 document.body.appendChild(ml.dom);
13860 ml.position('absolute');
13861 ml.setLeftTop(-1000, -1000);
13865 ml.setWidth(fixedWidth);
13870 * Returns the size of the specified text based on the internal element's style and width properties
13871 * @param {String} text The text to measure
13872 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13874 getSize : function(text){
13876 var s = ml.getSize();
13882 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13883 * that can affect the size of the rendered text
13884 * @param {String/HTMLElement} el The element, dom node or id
13886 bind : function(el){
13888 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
13893 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
13894 * to set a fixed width in order to accurately measure the text height.
13895 * @param {Number} width The width to set on the element
13897 setFixedWidth : function(width){
13898 ml.setWidth(width);
13902 * Returns the measured width of the specified text
13903 * @param {String} text The text to measure
13904 * @return {Number} width The width in pixels
13906 getWidth : function(text){
13907 ml.dom.style.width = 'auto';
13908 return this.getSize(text).width;
13912 * Returns the measured height of the specified text. For multiline text, be sure to call
13913 * {@link #setFixedWidth} if necessary.
13914 * @param {String} text The text to measure
13915 * @return {Number} height The height in pixels
13917 getHeight : function(text){
13918 return this.getSize(text).height;
13922 instance.bind(bindTo);
13927 // backwards compat
13928 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
13930 * Ext JS Library 1.1.1
13931 * Copyright(c) 2006-2007, Ext JS, LLC.
13933 * Originally Released Under LGPL - original licence link has changed is not relivant.
13936 * <script type="text/javascript">
13940 * @class Roo.state.Provider
13941 * Abstract base class for state provider implementations. This class provides methods
13942 * for encoding and decoding <b>typed</b> variables including dates and defines the
13943 * Provider interface.
13945 Roo.state.Provider = function(){
13947 * @event statechange
13948 * Fires when a state change occurs.
13949 * @param {Provider} this This state provider
13950 * @param {String} key The state key which was changed
13951 * @param {String} value The encoded value for the state
13954 "statechange": true
13957 Roo.state.Provider.superclass.constructor.call(this);
13959 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
13961 * Returns the current value for a key
13962 * @param {String} name The key name
13963 * @param {Mixed} defaultValue A default value to return if the key's value is not found
13964 * @return {Mixed} The state data
13966 get : function(name, defaultValue){
13967 return typeof this.state[name] == "undefined" ?
13968 defaultValue : this.state[name];
13972 * Clears a value from the state
13973 * @param {String} name The key name
13975 clear : function(name){
13976 delete this.state[name];
13977 this.fireEvent("statechange", this, name, null);
13981 * Sets the value for a key
13982 * @param {String} name The key name
13983 * @param {Mixed} value The value to set
13985 set : function(name, value){
13986 this.state[name] = value;
13987 this.fireEvent("statechange", this, name, value);
13991 * Decodes a string previously encoded with {@link #encodeValue}.
13992 * @param {String} value The value to decode
13993 * @return {Mixed} The decoded value
13995 decodeValue : function(cookie){
13996 var re = /^(a|n|d|b|s|o)\:(.*)$/;
13997 var matches = re.exec(unescape(cookie));
13998 if(!matches || !matches[1]) return; // non state cookie
13999 var type = matches[1];
14000 var v = matches[2];
14003 return parseFloat(v);
14005 return new Date(Date.parse(v));
14010 var values = v.split("^");
14011 for(var i = 0, len = values.length; i < len; i++){
14012 all.push(this.decodeValue(values[i]));
14017 var values = v.split("^");
14018 for(var i = 0, len = values.length; i < len; i++){
14019 var kv = values[i].split("=");
14020 all[kv[0]] = this.decodeValue(kv[1]);
14029 * Encodes a value including type information. Decode with {@link #decodeValue}.
14030 * @param {Mixed} value The value to encode
14031 * @return {String} The encoded value
14033 encodeValue : function(v){
14035 if(typeof v == "number"){
14037 }else if(typeof v == "boolean"){
14038 enc = "b:" + (v ? "1" : "0");
14039 }else if(v instanceof Date){
14040 enc = "d:" + v.toGMTString();
14041 }else if(v instanceof Array){
14043 for(var i = 0, len = v.length; i < len; i++){
14044 flat += this.encodeValue(v[i]);
14045 if(i != len-1) flat += "^";
14048 }else if(typeof v == "object"){
14051 if(typeof v[key] != "function"){
14052 flat += key + "=" + this.encodeValue(v[key]) + "^";
14055 enc = "o:" + flat.substring(0, flat.length-1);
14059 return escape(enc);
14065 * Ext JS Library 1.1.1
14066 * Copyright(c) 2006-2007, Ext JS, LLC.
14068 * Originally Released Under LGPL - original licence link has changed is not relivant.
14071 * <script type="text/javascript">
14074 * @class Roo.state.Manager
14075 * This is the global state manager. By default all components that are "state aware" check this class
14076 * for state information if you don't pass them a custom state provider. In order for this class
14077 * to be useful, it must be initialized with a provider when your application initializes.
14079 // in your initialization function
14081 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14083 // supposed you have a {@link Roo.BorderLayout}
14084 var layout = new Roo.BorderLayout(...);
14085 layout.restoreState();
14086 // or a {Roo.BasicDialog}
14087 var dialog = new Roo.BasicDialog(...);
14088 dialog.restoreState();
14092 Roo.state.Manager = function(){
14093 var provider = new Roo.state.Provider();
14097 * Configures the default state provider for your application
14098 * @param {Provider} stateProvider The state provider to set
14100 setProvider : function(stateProvider){
14101 provider = stateProvider;
14105 * Returns the current value for a key
14106 * @param {String} name The key name
14107 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14108 * @return {Mixed} The state data
14110 get : function(key, defaultValue){
14111 return provider.get(key, defaultValue);
14115 * Sets the value for a key
14116 * @param {String} name The key name
14117 * @param {Mixed} value The state data
14119 set : function(key, value){
14120 provider.set(key, value);
14124 * Clears a value from the state
14125 * @param {String} name The key name
14127 clear : function(key){
14128 provider.clear(key);
14132 * Gets the currently configured state provider
14133 * @return {Provider} The state provider
14135 getProvider : function(){
14142 * Ext JS Library 1.1.1
14143 * Copyright(c) 2006-2007, Ext JS, LLC.
14145 * Originally Released Under LGPL - original licence link has changed is not relivant.
14148 * <script type="text/javascript">
14151 * @class Roo.state.CookieProvider
14152 * @extends Roo.state.Provider
14153 * The default Provider implementation which saves state via cookies.
14156 var cp = new Roo.state.CookieProvider({
14158 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14159 domain: "roojs.com"
14161 Roo.state.Manager.setProvider(cp);
14163 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14164 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14165 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14166 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14167 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14168 * domain the page is running on including the 'www' like 'www.roojs.com')
14169 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14171 * Create a new CookieProvider
14172 * @param {Object} config The configuration object
14174 Roo.state.CookieProvider = function(config){
14175 Roo.state.CookieProvider.superclass.constructor.call(this);
14177 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14178 this.domain = null;
14179 this.secure = false;
14180 Roo.apply(this, config);
14181 this.state = this.readCookies();
14184 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14186 set : function(name, value){
14187 if(typeof value == "undefined" || value === null){
14191 this.setCookie(name, value);
14192 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14196 clear : function(name){
14197 this.clearCookie(name);
14198 Roo.state.CookieProvider.superclass.clear.call(this, name);
14202 readCookies : function(){
14204 var c = document.cookie + ";";
14205 var re = /\s?(.*?)=(.*?);/g;
14207 while((matches = re.exec(c)) != null){
14208 var name = matches[1];
14209 var value = matches[2];
14210 if(name && name.substring(0,3) == "ys-"){
14211 cookies[name.substr(3)] = this.decodeValue(value);
14218 setCookie : function(name, value){
14219 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14220 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14221 ((this.path == null) ? "" : ("; path=" + this.path)) +
14222 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14223 ((this.secure == true) ? "; secure" : "");
14227 clearCookie : function(name){
14228 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14229 ((this.path == null) ? "" : ("; path=" + this.path)) +
14230 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14231 ((this.secure == true) ? "; secure" : "");
14235 * Ext JS Library 1.1.1
14236 * Copyright(c) 2006-2007, Ext JS, LLC.
14238 * Originally Released Under LGPL - original licence link has changed is not relivant.
14241 * <script type="text/javascript">
14247 * These classes are derivatives of the similarly named classes in the YUI Library.
14248 * The original license:
14249 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14250 * Code licensed under the BSD License:
14251 * http://developer.yahoo.net/yui/license.txt
14256 var Event=Roo.EventManager;
14257 var Dom=Roo.lib.Dom;
14260 * @class Roo.dd.DragDrop
14261 * Defines the interface and base operation of items that that can be
14262 * dragged or can be drop targets. It was designed to be extended, overriding
14263 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14264 * Up to three html elements can be associated with a DragDrop instance:
14266 * <li>linked element: the element that is passed into the constructor.
14267 * This is the element which defines the boundaries for interaction with
14268 * other DragDrop objects.</li>
14269 * <li>handle element(s): The drag operation only occurs if the element that
14270 * was clicked matches a handle element. By default this is the linked
14271 * element, but there are times that you will want only a portion of the
14272 * linked element to initiate the drag operation, and the setHandleElId()
14273 * method provides a way to define this.</li>
14274 * <li>drag element: this represents the element that would be moved along
14275 * with the cursor during a drag operation. By default, this is the linked
14276 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14277 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14280 * This class should not be instantiated until the onload event to ensure that
14281 * the associated elements are available.
14282 * The following would define a DragDrop obj that would interact with any
14283 * other DragDrop obj in the "group1" group:
14285 * dd = new Roo.dd.DragDrop("div1", "group1");
14287 * Since none of the event handlers have been implemented, nothing would
14288 * actually happen if you were to run the code above. Normally you would
14289 * override this class or one of the default implementations, but you can
14290 * also override the methods you want on an instance of the class...
14292 * dd.onDragDrop = function(e, id) {
14293 * alert("dd was dropped on " + id);
14297 * @param {String} id of the element that is linked to this instance
14298 * @param {String} sGroup the group of related DragDrop objects
14299 * @param {object} config an object containing configurable attributes
14300 * Valid properties for DragDrop:
14301 * padding, isTarget, maintainOffset, primaryButtonOnly
14303 Roo.dd.DragDrop = function(id, sGroup, config) {
14305 this.init(id, sGroup, config);
14309 Roo.dd.DragDrop.prototype = {
14312 * The id of the element associated with this object. This is what we
14313 * refer to as the "linked element" because the size and position of
14314 * this element is used to determine when the drag and drop objects have
14322 * Configuration attributes passed into the constructor
14329 * The id of the element that will be dragged. By default this is same
14330 * as the linked element , but could be changed to another element. Ex:
14332 * @property dragElId
14339 * the id of the element that initiates the drag operation. By default
14340 * this is the linked element, but could be changed to be a child of this
14341 * element. This lets us do things like only starting the drag when the
14342 * header element within the linked html element is clicked.
14343 * @property handleElId
14350 * An associative array of HTML tags that will be ignored if clicked.
14351 * @property invalidHandleTypes
14352 * @type {string: string}
14354 invalidHandleTypes: null,
14357 * An associative array of ids for elements that will be ignored if clicked
14358 * @property invalidHandleIds
14359 * @type {string: string}
14361 invalidHandleIds: null,
14364 * An indexted array of css class names for elements that will be ignored
14366 * @property invalidHandleClasses
14369 invalidHandleClasses: null,
14372 * The linked element's absolute X position at the time the drag was
14374 * @property startPageX
14381 * The linked element's absolute X position at the time the drag was
14383 * @property startPageY
14390 * The group defines a logical collection of DragDrop objects that are
14391 * related. Instances only get events when interacting with other
14392 * DragDrop object in the same group. This lets us define multiple
14393 * groups using a single DragDrop subclass if we want.
14395 * @type {string: string}
14400 * Individual drag/drop instances can be locked. This will prevent
14401 * onmousedown start drag.
14409 * Lock this instance
14412 lock: function() { this.locked = true; },
14415 * Unlock this instace
14418 unlock: function() { this.locked = false; },
14421 * By default, all insances can be a drop target. This can be disabled by
14422 * setting isTarget to false.
14429 * The padding configured for this drag and drop object for calculating
14430 * the drop zone intersection with this object.
14437 * Cached reference to the linked element
14438 * @property _domRef
14444 * Internal typeof flag
14445 * @property __ygDragDrop
14448 __ygDragDrop: true,
14451 * Set to true when horizontal contraints are applied
14452 * @property constrainX
14459 * Set to true when vertical contraints are applied
14460 * @property constrainY
14467 * The left constraint
14475 * The right constraint
14483 * The up constraint
14492 * The down constraint
14500 * Maintain offsets when we resetconstraints. Set to true when you want
14501 * the position of the element relative to its parent to stay the same
14502 * when the page changes
14504 * @property maintainOffset
14507 maintainOffset: false,
14510 * Array of pixel locations the element will snap to if we specified a
14511 * horizontal graduation/interval. This array is generated automatically
14512 * when you define a tick interval.
14519 * Array of pixel locations the element will snap to if we specified a
14520 * vertical graduation/interval. This array is generated automatically
14521 * when you define a tick interval.
14528 * By default the drag and drop instance will only respond to the primary
14529 * button click (left button for a right-handed mouse). Set to true to
14530 * allow drag and drop to start with any mouse click that is propogated
14532 * @property primaryButtonOnly
14535 primaryButtonOnly: true,
14538 * The availabe property is false until the linked dom element is accessible.
14539 * @property available
14545 * By default, drags can only be initiated if the mousedown occurs in the
14546 * region the linked element is. This is done in part to work around a
14547 * bug in some browsers that mis-report the mousedown if the previous
14548 * mouseup happened outside of the window. This property is set to true
14549 * if outer handles are defined.
14551 * @property hasOuterHandles
14555 hasOuterHandles: false,
14558 * Code that executes immediately before the startDrag event
14559 * @method b4StartDrag
14562 b4StartDrag: function(x, y) { },
14565 * Abstract method called after a drag/drop object is clicked
14566 * and the drag or mousedown time thresholds have beeen met.
14567 * @method startDrag
14568 * @param {int} X click location
14569 * @param {int} Y click location
14571 startDrag: function(x, y) { /* override this */ },
14574 * Code that executes immediately before the onDrag event
14578 b4Drag: function(e) { },
14581 * Abstract method called during the onMouseMove event while dragging an
14584 * @param {Event} e the mousemove event
14586 onDrag: function(e) { /* override this */ },
14589 * Abstract method called when this element fist begins hovering over
14590 * another DragDrop obj
14591 * @method onDragEnter
14592 * @param {Event} e the mousemove event
14593 * @param {String|DragDrop[]} id In POINT mode, the element
14594 * id this is hovering over. In INTERSECT mode, an array of one or more
14595 * dragdrop items being hovered over.
14597 onDragEnter: function(e, id) { /* override this */ },
14600 * Code that executes immediately before the onDragOver event
14601 * @method b4DragOver
14604 b4DragOver: function(e) { },
14607 * Abstract method called when this element is hovering over another
14609 * @method onDragOver
14610 * @param {Event} e the mousemove event
14611 * @param {String|DragDrop[]} id In POINT mode, the element
14612 * id this is hovering over. In INTERSECT mode, an array of dd items
14613 * being hovered over.
14615 onDragOver: function(e, id) { /* override this */ },
14618 * Code that executes immediately before the onDragOut event
14619 * @method b4DragOut
14622 b4DragOut: function(e) { },
14625 * Abstract method called when we are no longer hovering over an element
14626 * @method onDragOut
14627 * @param {Event} e the mousemove event
14628 * @param {String|DragDrop[]} id In POINT mode, the element
14629 * id this was hovering over. In INTERSECT mode, an array of dd items
14630 * that the mouse is no longer over.
14632 onDragOut: function(e, id) { /* override this */ },
14635 * Code that executes immediately before the onDragDrop event
14636 * @method b4DragDrop
14639 b4DragDrop: function(e) { },
14642 * Abstract method called when this item is dropped on another DragDrop
14644 * @method onDragDrop
14645 * @param {Event} e the mouseup event
14646 * @param {String|DragDrop[]} id In POINT mode, the element
14647 * id this was dropped on. In INTERSECT mode, an array of dd items this
14650 onDragDrop: function(e, id) { /* override this */ },
14653 * Abstract method called when this item is dropped on an area with no
14655 * @method onInvalidDrop
14656 * @param {Event} e the mouseup event
14658 onInvalidDrop: function(e) { /* override this */ },
14661 * Code that executes immediately before the endDrag event
14662 * @method b4EndDrag
14665 b4EndDrag: function(e) { },
14668 * Fired when we are done dragging the object
14670 * @param {Event} e the mouseup event
14672 endDrag: function(e) { /* override this */ },
14675 * Code executed immediately before the onMouseDown event
14676 * @method b4MouseDown
14677 * @param {Event} e the mousedown event
14680 b4MouseDown: function(e) { },
14683 * Event handler that fires when a drag/drop obj gets a mousedown
14684 * @method onMouseDown
14685 * @param {Event} e the mousedown event
14687 onMouseDown: function(e) { /* override this */ },
14690 * Event handler that fires when a drag/drop obj gets a mouseup
14691 * @method onMouseUp
14692 * @param {Event} e the mouseup event
14694 onMouseUp: function(e) { /* override this */ },
14697 * Override the onAvailable method to do what is needed after the initial
14698 * position was determined.
14699 * @method onAvailable
14701 onAvailable: function () {
14705 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14708 defaultPadding : {left:0, right:0, top:0, bottom:0},
14711 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14715 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14716 { dragElId: "existingProxyDiv" });
14717 dd.startDrag = function(){
14718 this.constrainTo("parent-id");
14721 * Or you can initalize it using the {@link Roo.Element} object:
14723 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14724 startDrag : function(){
14725 this.constrainTo("parent-id");
14729 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
14730 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
14731 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
14732 * an object containing the sides to pad. For example: {right:10, bottom:10}
14733 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
14735 constrainTo : function(constrainTo, pad, inContent){
14736 if(typeof pad == "number"){
14737 pad = {left: pad, right:pad, top:pad, bottom:pad};
14739 pad = pad || this.defaultPadding;
14740 var b = Roo.get(this.getEl()).getBox();
14741 var ce = Roo.get(constrainTo);
14742 var s = ce.getScroll();
14743 var c, cd = ce.dom;
14744 if(cd == document.body){
14745 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
14748 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
14752 var topSpace = b.y - c.y;
14753 var leftSpace = b.x - c.x;
14755 this.resetConstraints();
14756 this.setXConstraint(leftSpace - (pad.left||0), // left
14757 c.width - leftSpace - b.width - (pad.right||0) //right
14759 this.setYConstraint(topSpace - (pad.top||0), //top
14760 c.height - topSpace - b.height - (pad.bottom||0) //bottom
14765 * Returns a reference to the linked element
14767 * @return {HTMLElement} the html element
14769 getEl: function() {
14770 if (!this._domRef) {
14771 this._domRef = Roo.getDom(this.id);
14774 return this._domRef;
14778 * Returns a reference to the actual element to drag. By default this is
14779 * the same as the html element, but it can be assigned to another
14780 * element. An example of this can be found in Roo.dd.DDProxy
14781 * @method getDragEl
14782 * @return {HTMLElement} the html element
14784 getDragEl: function() {
14785 return Roo.getDom(this.dragElId);
14789 * Sets up the DragDrop object. Must be called in the constructor of any
14790 * Roo.dd.DragDrop subclass
14792 * @param id the id of the linked element
14793 * @param {String} sGroup the group of related items
14794 * @param {object} config configuration attributes
14796 init: function(id, sGroup, config) {
14797 this.initTarget(id, sGroup, config);
14798 Event.on(this.id, "mousedown", this.handleMouseDown, this);
14799 // Event.on(this.id, "selectstart", Event.preventDefault);
14803 * Initializes Targeting functionality only... the object does not
14804 * get a mousedown handler.
14805 * @method initTarget
14806 * @param id the id of the linked element
14807 * @param {String} sGroup the group of related items
14808 * @param {object} config configuration attributes
14810 initTarget: function(id, sGroup, config) {
14812 // configuration attributes
14813 this.config = config || {};
14815 // create a local reference to the drag and drop manager
14816 this.DDM = Roo.dd.DDM;
14817 // initialize the groups array
14820 // assume that we have an element reference instead of an id if the
14821 // parameter is not a string
14822 if (typeof id !== "string") {
14829 // add to an interaction group
14830 this.addToGroup((sGroup) ? sGroup : "default");
14832 // We don't want to register this as the handle with the manager
14833 // so we just set the id rather than calling the setter.
14834 this.handleElId = id;
14836 // the linked element is the element that gets dragged by default
14837 this.setDragElId(id);
14839 // by default, clicked anchors will not start drag operations.
14840 this.invalidHandleTypes = { A: "A" };
14841 this.invalidHandleIds = {};
14842 this.invalidHandleClasses = [];
14844 this.applyConfig();
14846 this.handleOnAvailable();
14850 * Applies the configuration parameters that were passed into the constructor.
14851 * This is supposed to happen at each level through the inheritance chain. So
14852 * a DDProxy implentation will execute apply config on DDProxy, DD, and
14853 * DragDrop in order to get all of the parameters that are available in
14855 * @method applyConfig
14857 applyConfig: function() {
14859 // configurable properties:
14860 // padding, isTarget, maintainOffset, primaryButtonOnly
14861 this.padding = this.config.padding || [0, 0, 0, 0];
14862 this.isTarget = (this.config.isTarget !== false);
14863 this.maintainOffset = (this.config.maintainOffset);
14864 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
14869 * Executed when the linked element is available
14870 * @method handleOnAvailable
14873 handleOnAvailable: function() {
14874 this.available = true;
14875 this.resetConstraints();
14876 this.onAvailable();
14880 * Configures the padding for the target zone in px. Effectively expands
14881 * (or reduces) the virtual object size for targeting calculations.
14882 * Supports css-style shorthand; if only one parameter is passed, all sides
14883 * will have that padding, and if only two are passed, the top and bottom
14884 * will have the first param, the left and right the second.
14885 * @method setPadding
14886 * @param {int} iTop Top pad
14887 * @param {int} iRight Right pad
14888 * @param {int} iBot Bot pad
14889 * @param {int} iLeft Left pad
14891 setPadding: function(iTop, iRight, iBot, iLeft) {
14892 // this.padding = [iLeft, iRight, iTop, iBot];
14893 if (!iRight && 0 !== iRight) {
14894 this.padding = [iTop, iTop, iTop, iTop];
14895 } else if (!iBot && 0 !== iBot) {
14896 this.padding = [iTop, iRight, iTop, iRight];
14898 this.padding = [iTop, iRight, iBot, iLeft];
14903 * Stores the initial placement of the linked element.
14904 * @method setInitialPosition
14905 * @param {int} diffX the X offset, default 0
14906 * @param {int} diffY the Y offset, default 0
14908 setInitPosition: function(diffX, diffY) {
14909 var el = this.getEl();
14911 if (!this.DDM.verifyEl(el)) {
14915 var dx = diffX || 0;
14916 var dy = diffY || 0;
14918 var p = Dom.getXY( el );
14920 this.initPageX = p[0] - dx;
14921 this.initPageY = p[1] - dy;
14923 this.lastPageX = p[0];
14924 this.lastPageY = p[1];
14927 this.setStartPosition(p);
14931 * Sets the start position of the element. This is set when the obj
14932 * is initialized, the reset when a drag is started.
14933 * @method setStartPosition
14934 * @param pos current position (from previous lookup)
14937 setStartPosition: function(pos) {
14938 var p = pos || Dom.getXY( this.getEl() );
14939 this.deltaSetXY = null;
14941 this.startPageX = p[0];
14942 this.startPageY = p[1];
14946 * Add this instance to a group of related drag/drop objects. All
14947 * instances belong to at least one group, and can belong to as many
14948 * groups as needed.
14949 * @method addToGroup
14950 * @param sGroup {string} the name of the group
14952 addToGroup: function(sGroup) {
14953 this.groups[sGroup] = true;
14954 this.DDM.regDragDrop(this, sGroup);
14958 * Remove's this instance from the supplied interaction group
14959 * @method removeFromGroup
14960 * @param {string} sGroup The group to drop
14962 removeFromGroup: function(sGroup) {
14963 if (this.groups[sGroup]) {
14964 delete this.groups[sGroup];
14967 this.DDM.removeDDFromGroup(this, sGroup);
14971 * Allows you to specify that an element other than the linked element
14972 * will be moved with the cursor during a drag
14973 * @method setDragElId
14974 * @param id {string} the id of the element that will be used to initiate the drag
14976 setDragElId: function(id) {
14977 this.dragElId = id;
14981 * Allows you to specify a child of the linked element that should be
14982 * used to initiate the drag operation. An example of this would be if
14983 * you have a content div with text and links. Clicking anywhere in the
14984 * content area would normally start the drag operation. Use this method
14985 * to specify that an element inside of the content div is the element
14986 * that starts the drag operation.
14987 * @method setHandleElId
14988 * @param id {string} the id of the element that will be used to
14989 * initiate the drag.
14991 setHandleElId: function(id) {
14992 if (typeof id !== "string") {
14995 this.handleElId = id;
14996 this.DDM.regHandle(this.id, id);
15000 * Allows you to set an element outside of the linked element as a drag
15002 * @method setOuterHandleElId
15003 * @param id the id of the element that will be used to initiate the drag
15005 setOuterHandleElId: function(id) {
15006 if (typeof id !== "string") {
15009 Event.on(id, "mousedown",
15010 this.handleMouseDown, this);
15011 this.setHandleElId(id);
15013 this.hasOuterHandles = true;
15017 * Remove all drag and drop hooks for this element
15020 unreg: function() {
15021 Event.un(this.id, "mousedown",
15022 this.handleMouseDown);
15023 this._domRef = null;
15024 this.DDM._remove(this);
15027 destroy : function(){
15032 * Returns true if this instance is locked, or the drag drop mgr is locked
15033 * (meaning that all drag/drop is disabled on the page.)
15035 * @return {boolean} true if this obj or all drag/drop is locked, else
15038 isLocked: function() {
15039 return (this.DDM.isLocked() || this.locked);
15043 * Fired when this object is clicked
15044 * @method handleMouseDown
15046 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15049 handleMouseDown: function(e, oDD){
15050 if (this.primaryButtonOnly && e.button != 0) {
15054 if (this.isLocked()) {
15058 this.DDM.refreshCache(this.groups);
15060 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15061 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15063 if (this.clickValidator(e)) {
15065 // set the initial element position
15066 this.setStartPosition();
15069 this.b4MouseDown(e);
15070 this.onMouseDown(e);
15072 this.DDM.handleMouseDown(e, this);
15074 this.DDM.stopEvent(e);
15082 clickValidator: function(e) {
15083 var target = e.getTarget();
15084 return ( this.isValidHandleChild(target) &&
15085 (this.id == this.handleElId ||
15086 this.DDM.handleWasClicked(target, this.id)) );
15090 * Allows you to specify a tag name that should not start a drag operation
15091 * when clicked. This is designed to facilitate embedding links within a
15092 * drag handle that do something other than start the drag.
15093 * @method addInvalidHandleType
15094 * @param {string} tagName the type of element to exclude
15096 addInvalidHandleType: function(tagName) {
15097 var type = tagName.toUpperCase();
15098 this.invalidHandleTypes[type] = type;
15102 * Lets you to specify an element id for a child of a drag handle
15103 * that should not initiate a drag
15104 * @method addInvalidHandleId
15105 * @param {string} id the element id of the element you wish to ignore
15107 addInvalidHandleId: function(id) {
15108 if (typeof id !== "string") {
15111 this.invalidHandleIds[id] = id;
15115 * Lets you specify a css class of elements that will not initiate a drag
15116 * @method addInvalidHandleClass
15117 * @param {string} cssClass the class of the elements you wish to ignore
15119 addInvalidHandleClass: function(cssClass) {
15120 this.invalidHandleClasses.push(cssClass);
15124 * Unsets an excluded tag name set by addInvalidHandleType
15125 * @method removeInvalidHandleType
15126 * @param {string} tagName the type of element to unexclude
15128 removeInvalidHandleType: function(tagName) {
15129 var type = tagName.toUpperCase();
15130 // this.invalidHandleTypes[type] = null;
15131 delete this.invalidHandleTypes[type];
15135 * Unsets an invalid handle id
15136 * @method removeInvalidHandleId
15137 * @param {string} id the id of the element to re-enable
15139 removeInvalidHandleId: function(id) {
15140 if (typeof id !== "string") {
15143 delete this.invalidHandleIds[id];
15147 * Unsets an invalid css class
15148 * @method removeInvalidHandleClass
15149 * @param {string} cssClass the class of the element(s) you wish to
15152 removeInvalidHandleClass: function(cssClass) {
15153 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15154 if (this.invalidHandleClasses[i] == cssClass) {
15155 delete this.invalidHandleClasses[i];
15161 * Checks the tag exclusion list to see if this click should be ignored
15162 * @method isValidHandleChild
15163 * @param {HTMLElement} node the HTMLElement to evaluate
15164 * @return {boolean} true if this is a valid tag type, false if not
15166 isValidHandleChild: function(node) {
15169 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15172 nodeName = node.nodeName.toUpperCase();
15174 nodeName = node.nodeName;
15176 valid = valid && !this.invalidHandleTypes[nodeName];
15177 valid = valid && !this.invalidHandleIds[node.id];
15179 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15180 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15189 * Create the array of horizontal tick marks if an interval was specified
15190 * in setXConstraint().
15191 * @method setXTicks
15194 setXTicks: function(iStartX, iTickSize) {
15196 this.xTickSize = iTickSize;
15200 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15202 this.xTicks[this.xTicks.length] = i;
15207 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15209 this.xTicks[this.xTicks.length] = i;
15214 this.xTicks.sort(this.DDM.numericSort) ;
15218 * Create the array of vertical tick marks if an interval was specified in
15219 * setYConstraint().
15220 * @method setYTicks
15223 setYTicks: function(iStartY, iTickSize) {
15225 this.yTickSize = iTickSize;
15229 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15231 this.yTicks[this.yTicks.length] = i;
15236 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15238 this.yTicks[this.yTicks.length] = i;
15243 this.yTicks.sort(this.DDM.numericSort) ;
15247 * By default, the element can be dragged any place on the screen. Use
15248 * this method to limit the horizontal travel of the element. Pass in
15249 * 0,0 for the parameters if you want to lock the drag to the y axis.
15250 * @method setXConstraint
15251 * @param {int} iLeft the number of pixels the element can move to the left
15252 * @param {int} iRight the number of pixels the element can move to the
15254 * @param {int} iTickSize optional parameter for specifying that the
15256 * should move iTickSize pixels at a time.
15258 setXConstraint: function(iLeft, iRight, iTickSize) {
15259 this.leftConstraint = iLeft;
15260 this.rightConstraint = iRight;
15262 this.minX = this.initPageX - iLeft;
15263 this.maxX = this.initPageX + iRight;
15264 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15266 this.constrainX = true;
15270 * Clears any constraints applied to this instance. Also clears ticks
15271 * since they can't exist independent of a constraint at this time.
15272 * @method clearConstraints
15274 clearConstraints: function() {
15275 this.constrainX = false;
15276 this.constrainY = false;
15281 * Clears any tick interval defined for this instance
15282 * @method clearTicks
15284 clearTicks: function() {
15285 this.xTicks = null;
15286 this.yTicks = null;
15287 this.xTickSize = 0;
15288 this.yTickSize = 0;
15292 * By default, the element can be dragged any place on the screen. Set
15293 * this to limit the vertical travel of the element. Pass in 0,0 for the
15294 * parameters if you want to lock the drag to the x axis.
15295 * @method setYConstraint
15296 * @param {int} iUp the number of pixels the element can move up
15297 * @param {int} iDown the number of pixels the element can move down
15298 * @param {int} iTickSize optional parameter for specifying that the
15299 * element should move iTickSize pixels at a time.
15301 setYConstraint: function(iUp, iDown, iTickSize) {
15302 this.topConstraint = iUp;
15303 this.bottomConstraint = iDown;
15305 this.minY = this.initPageY - iUp;
15306 this.maxY = this.initPageY + iDown;
15307 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15309 this.constrainY = true;
15314 * resetConstraints must be called if you manually reposition a dd element.
15315 * @method resetConstraints
15316 * @param {boolean} maintainOffset
15318 resetConstraints: function() {
15321 // Maintain offsets if necessary
15322 if (this.initPageX || this.initPageX === 0) {
15323 // figure out how much this thing has moved
15324 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15325 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15327 this.setInitPosition(dx, dy);
15329 // This is the first time we have detected the element's position
15331 this.setInitPosition();
15334 if (this.constrainX) {
15335 this.setXConstraint( this.leftConstraint,
15336 this.rightConstraint,
15340 if (this.constrainY) {
15341 this.setYConstraint( this.topConstraint,
15342 this.bottomConstraint,
15348 * Normally the drag element is moved pixel by pixel, but we can specify
15349 * that it move a number of pixels at a time. This method resolves the
15350 * location when we have it set up like this.
15352 * @param {int} val where we want to place the object
15353 * @param {int[]} tickArray sorted array of valid points
15354 * @return {int} the closest tick
15357 getTick: function(val, tickArray) {
15360 // If tick interval is not defined, it is effectively 1 pixel,
15361 // so we return the value passed to us.
15363 } else if (tickArray[0] >= val) {
15364 // The value is lower than the first tick, so we return the first
15366 return tickArray[0];
15368 for (var i=0, len=tickArray.length; i<len; ++i) {
15370 if (tickArray[next] && tickArray[next] >= val) {
15371 var diff1 = val - tickArray[i];
15372 var diff2 = tickArray[next] - val;
15373 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15377 // The value is larger than the last tick, so we return the last
15379 return tickArray[tickArray.length - 1];
15386 * @return {string} string representation of the dd obj
15388 toString: function() {
15389 return ("DragDrop " + this.id);
15397 * Ext JS Library 1.1.1
15398 * Copyright(c) 2006-2007, Ext JS, LLC.
15400 * Originally Released Under LGPL - original licence link has changed is not relivant.
15403 * <script type="text/javascript">
15408 * The drag and drop utility provides a framework for building drag and drop
15409 * applications. In addition to enabling drag and drop for specific elements,
15410 * the drag and drop elements are tracked by the manager class, and the
15411 * interactions between the various elements are tracked during the drag and
15412 * the implementing code is notified about these important moments.
15415 // Only load the library once. Rewriting the manager class would orphan
15416 // existing drag and drop instances.
15417 if (!Roo.dd.DragDropMgr) {
15420 * @class Roo.dd.DragDropMgr
15421 * DragDropMgr is a singleton that tracks the element interaction for
15422 * all DragDrop items in the window. Generally, you will not call
15423 * this class directly, but it does have helper methods that could
15424 * be useful in your DragDrop implementations.
15427 Roo.dd.DragDropMgr = function() {
15429 var Event = Roo.EventManager;
15434 * Two dimensional Array of registered DragDrop objects. The first
15435 * dimension is the DragDrop item group, the second the DragDrop
15438 * @type {string: string}
15445 * Array of element ids defined as drag handles. Used to determine
15446 * if the element that generated the mousedown event is actually the
15447 * handle and not the html element itself.
15448 * @property handleIds
15449 * @type {string: string}
15456 * the DragDrop object that is currently being dragged
15457 * @property dragCurrent
15465 * the DragDrop object(s) that are being hovered over
15466 * @property dragOvers
15474 * the X distance between the cursor and the object being dragged
15483 * the Y distance between the cursor and the object being dragged
15492 * Flag to determine if we should prevent the default behavior of the
15493 * events we define. By default this is true, but this can be set to
15494 * false if you need the default behavior (not recommended)
15495 * @property preventDefault
15499 preventDefault: true,
15502 * Flag to determine if we should stop the propagation of the events
15503 * we generate. This is true by default but you may want to set it to
15504 * false if the html element contains other features that require the
15506 * @property stopPropagation
15510 stopPropagation: true,
15513 * Internal flag that is set to true when drag and drop has been
15515 * @property initialized
15522 * All drag and drop can be disabled.
15530 * Called the first time an element is registered.
15536 this.initialized = true;
15540 * In point mode, drag and drop interaction is defined by the
15541 * location of the cursor during the drag/drop
15549 * In intersect mode, drag and drop interactio nis defined by the
15550 * overlap of two or more drag and drop objects.
15551 * @property INTERSECT
15558 * The current drag and drop mode. Default: POINT
15566 * Runs method on all drag and drop objects
15567 * @method _execOnAll
15571 _execOnAll: function(sMethod, args) {
15572 for (var i in this.ids) {
15573 for (var j in this.ids[i]) {
15574 var oDD = this.ids[i][j];
15575 if (! this.isTypeOfDD(oDD)) {
15578 oDD[sMethod].apply(oDD, args);
15584 * Drag and drop initialization. Sets up the global event handlers
15589 _onLoad: function() {
15594 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15595 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15596 Event.on(window, "unload", this._onUnload, this, true);
15597 Event.on(window, "resize", this._onResize, this, true);
15598 // Event.on(window, "mouseout", this._test);
15603 * Reset constraints on all drag and drop objs
15604 * @method _onResize
15608 _onResize: function(e) {
15609 this._execOnAll("resetConstraints", []);
15613 * Lock all drag and drop functionality
15617 lock: function() { this.locked = true; },
15620 * Unlock all drag and drop functionality
15624 unlock: function() { this.locked = false; },
15627 * Is drag and drop locked?
15629 * @return {boolean} True if drag and drop is locked, false otherwise.
15632 isLocked: function() { return this.locked; },
15635 * Location cache that is set for all drag drop objects when a drag is
15636 * initiated, cleared when the drag is finished.
15637 * @property locationCache
15644 * Set useCache to false if you want to force object the lookup of each
15645 * drag and drop linked element constantly during a drag.
15646 * @property useCache
15653 * The number of pixels that the mouse needs to move after the
15654 * mousedown before the drag is initiated. Default=3;
15655 * @property clickPixelThresh
15659 clickPixelThresh: 3,
15662 * The number of milliseconds after the mousedown event to initiate the
15663 * drag if we don't get a mouseup event. Default=1000
15664 * @property clickTimeThresh
15668 clickTimeThresh: 350,
15671 * Flag that indicates that either the drag pixel threshold or the
15672 * mousdown time threshold has been met
15673 * @property dragThreshMet
15678 dragThreshMet: false,
15681 * Timeout used for the click time threshold
15682 * @property clickTimeout
15687 clickTimeout: null,
15690 * The X position of the mousedown event stored for later use when a
15691 * drag threshold is met.
15700 * The Y position of the mousedown event stored for later use when a
15701 * drag threshold is met.
15710 * Each DragDrop instance must be registered with the DragDropMgr.
15711 * This is executed in DragDrop.init()
15712 * @method regDragDrop
15713 * @param {DragDrop} oDD the DragDrop object to register
15714 * @param {String} sGroup the name of the group this element belongs to
15717 regDragDrop: function(oDD, sGroup) {
15718 if (!this.initialized) { this.init(); }
15720 if (!this.ids[sGroup]) {
15721 this.ids[sGroup] = {};
15723 this.ids[sGroup][oDD.id] = oDD;
15727 * Removes the supplied dd instance from the supplied group. Executed
15728 * by DragDrop.removeFromGroup, so don't call this function directly.
15729 * @method removeDDFromGroup
15733 removeDDFromGroup: function(oDD, sGroup) {
15734 if (!this.ids[sGroup]) {
15735 this.ids[sGroup] = {};
15738 var obj = this.ids[sGroup];
15739 if (obj && obj[oDD.id]) {
15740 delete obj[oDD.id];
15745 * Unregisters a drag and drop item. This is executed in
15746 * DragDrop.unreg, use that method instead of calling this directly.
15751 _remove: function(oDD) {
15752 for (var g in oDD.groups) {
15753 if (g && this.ids[g][oDD.id]) {
15754 delete this.ids[g][oDD.id];
15757 delete this.handleIds[oDD.id];
15761 * Each DragDrop handle element must be registered. This is done
15762 * automatically when executing DragDrop.setHandleElId()
15763 * @method regHandle
15764 * @param {String} sDDId the DragDrop id this element is a handle for
15765 * @param {String} sHandleId the id of the element that is the drag
15769 regHandle: function(sDDId, sHandleId) {
15770 if (!this.handleIds[sDDId]) {
15771 this.handleIds[sDDId] = {};
15773 this.handleIds[sDDId][sHandleId] = sHandleId;
15777 * Utility function to determine if a given element has been
15778 * registered as a drag drop item.
15779 * @method isDragDrop
15780 * @param {String} id the element id to check
15781 * @return {boolean} true if this element is a DragDrop item,
15785 isDragDrop: function(id) {
15786 return ( this.getDDById(id) ) ? true : false;
15790 * Returns the drag and drop instances that are in all groups the
15791 * passed in instance belongs to.
15792 * @method getRelated
15793 * @param {DragDrop} p_oDD the obj to get related data for
15794 * @param {boolean} bTargetsOnly if true, only return targetable objs
15795 * @return {DragDrop[]} the related instances
15798 getRelated: function(p_oDD, bTargetsOnly) {
15800 for (var i in p_oDD.groups) {
15801 for (j in this.ids[i]) {
15802 var dd = this.ids[i][j];
15803 if (! this.isTypeOfDD(dd)) {
15806 if (!bTargetsOnly || dd.isTarget) {
15807 oDDs[oDDs.length] = dd;
15816 * Returns true if the specified dd target is a legal target for
15817 * the specifice drag obj
15818 * @method isLegalTarget
15819 * @param {DragDrop} the drag obj
15820 * @param {DragDrop} the target
15821 * @return {boolean} true if the target is a legal target for the
15825 isLegalTarget: function (oDD, oTargetDD) {
15826 var targets = this.getRelated(oDD, true);
15827 for (var i=0, len=targets.length;i<len;++i) {
15828 if (targets[i].id == oTargetDD.id) {
15837 * My goal is to be able to transparently determine if an object is
15838 * typeof DragDrop, and the exact subclass of DragDrop. typeof
15839 * returns "object", oDD.constructor.toString() always returns
15840 * "DragDrop" and not the name of the subclass. So for now it just
15841 * evaluates a well-known variable in DragDrop.
15842 * @method isTypeOfDD
15843 * @param {Object} the object to evaluate
15844 * @return {boolean} true if typeof oDD = DragDrop
15847 isTypeOfDD: function (oDD) {
15848 return (oDD && oDD.__ygDragDrop);
15852 * Utility function to determine if a given element has been
15853 * registered as a drag drop handle for the given Drag Drop object.
15855 * @param {String} id the element id to check
15856 * @return {boolean} true if this element is a DragDrop handle, false
15860 isHandle: function(sDDId, sHandleId) {
15861 return ( this.handleIds[sDDId] &&
15862 this.handleIds[sDDId][sHandleId] );
15866 * Returns the DragDrop instance for a given id
15867 * @method getDDById
15868 * @param {String} id the id of the DragDrop object
15869 * @return {DragDrop} the drag drop object, null if it is not found
15872 getDDById: function(id) {
15873 for (var i in this.ids) {
15874 if (this.ids[i][id]) {
15875 return this.ids[i][id];
15882 * Fired after a registered DragDrop object gets the mousedown event.
15883 * Sets up the events required to track the object being dragged
15884 * @method handleMouseDown
15885 * @param {Event} e the event
15886 * @param oDD the DragDrop object being dragged
15890 handleMouseDown: function(e, oDD) {
15892 Roo.QuickTips.disable();
15894 this.currentTarget = e.getTarget();
15896 this.dragCurrent = oDD;
15898 var el = oDD.getEl();
15900 // track start position
15901 this.startX = e.getPageX();
15902 this.startY = e.getPageY();
15904 this.deltaX = this.startX - el.offsetLeft;
15905 this.deltaY = this.startY - el.offsetTop;
15907 this.dragThreshMet = false;
15909 this.clickTimeout = setTimeout(
15911 var DDM = Roo.dd.DDM;
15912 DDM.startDrag(DDM.startX, DDM.startY);
15914 this.clickTimeThresh );
15918 * Fired when either the drag pixel threshol or the mousedown hold
15919 * time threshold has been met.
15920 * @method startDrag
15921 * @param x {int} the X position of the original mousedown
15922 * @param y {int} the Y position of the original mousedown
15925 startDrag: function(x, y) {
15926 clearTimeout(this.clickTimeout);
15927 if (this.dragCurrent) {
15928 this.dragCurrent.b4StartDrag(x, y);
15929 this.dragCurrent.startDrag(x, y);
15931 this.dragThreshMet = true;
15935 * Internal function to handle the mouseup event. Will be invoked
15936 * from the context of the document.
15937 * @method handleMouseUp
15938 * @param {Event} e the event
15942 handleMouseUp: function(e) {
15945 Roo.QuickTips.enable();
15947 if (! this.dragCurrent) {
15951 clearTimeout(this.clickTimeout);
15953 if (this.dragThreshMet) {
15954 this.fireEvents(e, true);
15964 * Utility to stop event propagation and event default, if these
15965 * features are turned on.
15966 * @method stopEvent
15967 * @param {Event} e the event as returned by this.getEvent()
15970 stopEvent: function(e){
15971 if(this.stopPropagation) {
15972 e.stopPropagation();
15975 if (this.preventDefault) {
15976 e.preventDefault();
15981 * Internal function to clean up event handlers after the drag
15982 * operation is complete
15984 * @param {Event} e the event
15988 stopDrag: function(e) {
15989 // Fire the drag end event for the item that was dragged
15990 if (this.dragCurrent) {
15991 if (this.dragThreshMet) {
15992 this.dragCurrent.b4EndDrag(e);
15993 this.dragCurrent.endDrag(e);
15996 this.dragCurrent.onMouseUp(e);
15999 this.dragCurrent = null;
16000 this.dragOvers = {};
16004 * Internal function to handle the mousemove event. Will be invoked
16005 * from the context of the html element.
16007 * @TODO figure out what we can do about mouse events lost when the
16008 * user drags objects beyond the window boundary. Currently we can
16009 * detect this in internet explorer by verifying that the mouse is
16010 * down during the mousemove event. Firefox doesn't give us the
16011 * button state on the mousemove event.
16012 * @method handleMouseMove
16013 * @param {Event} e the event
16017 handleMouseMove: function(e) {
16018 if (! this.dragCurrent) {
16022 // var button = e.which || e.button;
16024 // check for IE mouseup outside of page boundary
16025 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16027 return this.handleMouseUp(e);
16030 if (!this.dragThreshMet) {
16031 var diffX = Math.abs(this.startX - e.getPageX());
16032 var diffY = Math.abs(this.startY - e.getPageY());
16033 if (diffX > this.clickPixelThresh ||
16034 diffY > this.clickPixelThresh) {
16035 this.startDrag(this.startX, this.startY);
16039 if (this.dragThreshMet) {
16040 this.dragCurrent.b4Drag(e);
16041 this.dragCurrent.onDrag(e);
16042 if(!this.dragCurrent.moveOnly){
16043 this.fireEvents(e, false);
16053 * Iterates over all of the DragDrop elements to find ones we are
16054 * hovering over or dropping on
16055 * @method fireEvents
16056 * @param {Event} e the event
16057 * @param {boolean} isDrop is this a drop op or a mouseover op?
16061 fireEvents: function(e, isDrop) {
16062 var dc = this.dragCurrent;
16064 // If the user did the mouse up outside of the window, we could
16065 // get here even though we have ended the drag.
16066 if (!dc || dc.isLocked()) {
16070 var pt = e.getPoint();
16072 // cache the previous dragOver array
16078 var enterEvts = [];
16080 // Check to see if the object(s) we were hovering over is no longer
16081 // being hovered over so we can fire the onDragOut event
16082 for (var i in this.dragOvers) {
16084 var ddo = this.dragOvers[i];
16086 if (! this.isTypeOfDD(ddo)) {
16090 if (! this.isOverTarget(pt, ddo, this.mode)) {
16091 outEvts.push( ddo );
16094 oldOvers[i] = true;
16095 delete this.dragOvers[i];
16098 for (var sGroup in dc.groups) {
16100 if ("string" != typeof sGroup) {
16104 for (i in this.ids[sGroup]) {
16105 var oDD = this.ids[sGroup][i];
16106 if (! this.isTypeOfDD(oDD)) {
16110 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16111 if (this.isOverTarget(pt, oDD, this.mode)) {
16112 // look for drop interactions
16114 dropEvts.push( oDD );
16115 // look for drag enter and drag over interactions
16118 // initial drag over: dragEnter fires
16119 if (!oldOvers[oDD.id]) {
16120 enterEvts.push( oDD );
16121 // subsequent drag overs: dragOver fires
16123 overEvts.push( oDD );
16126 this.dragOvers[oDD.id] = oDD;
16134 if (outEvts.length) {
16135 dc.b4DragOut(e, outEvts);
16136 dc.onDragOut(e, outEvts);
16139 if (enterEvts.length) {
16140 dc.onDragEnter(e, enterEvts);
16143 if (overEvts.length) {
16144 dc.b4DragOver(e, overEvts);
16145 dc.onDragOver(e, overEvts);
16148 if (dropEvts.length) {
16149 dc.b4DragDrop(e, dropEvts);
16150 dc.onDragDrop(e, dropEvts);
16154 // fire dragout events
16156 for (i=0, len=outEvts.length; i<len; ++i) {
16157 dc.b4DragOut(e, outEvts[i].id);
16158 dc.onDragOut(e, outEvts[i].id);
16161 // fire enter events
16162 for (i=0,len=enterEvts.length; i<len; ++i) {
16163 // dc.b4DragEnter(e, oDD.id);
16164 dc.onDragEnter(e, enterEvts[i].id);
16167 // fire over events
16168 for (i=0,len=overEvts.length; i<len; ++i) {
16169 dc.b4DragOver(e, overEvts[i].id);
16170 dc.onDragOver(e, overEvts[i].id);
16173 // fire drop events
16174 for (i=0, len=dropEvts.length; i<len; ++i) {
16175 dc.b4DragDrop(e, dropEvts[i].id);
16176 dc.onDragDrop(e, dropEvts[i].id);
16181 // notify about a drop that did not find a target
16182 if (isDrop && !dropEvts.length) {
16183 dc.onInvalidDrop(e);
16189 * Helper function for getting the best match from the list of drag
16190 * and drop objects returned by the drag and drop events when we are
16191 * in INTERSECT mode. It returns either the first object that the
16192 * cursor is over, or the object that has the greatest overlap with
16193 * the dragged element.
16194 * @method getBestMatch
16195 * @param {DragDrop[]} dds The array of drag and drop objects
16197 * @return {DragDrop} The best single match
16200 getBestMatch: function(dds) {
16202 // Return null if the input is not what we expect
16203 //if (!dds || !dds.length || dds.length == 0) {
16205 // If there is only one item, it wins
16206 //} else if (dds.length == 1) {
16208 var len = dds.length;
16213 // Loop through the targeted items
16214 for (var i=0; i<len; ++i) {
16216 // If the cursor is over the object, it wins. If the
16217 // cursor is over multiple matches, the first one we come
16219 if (dd.cursorIsOver) {
16222 // Otherwise the object with the most overlap wins
16225 winner.overlap.getArea() < dd.overlap.getArea()) {
16236 * Refreshes the cache of the top-left and bottom-right points of the
16237 * drag and drop objects in the specified group(s). This is in the
16238 * format that is stored in the drag and drop instance, so typical
16241 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16245 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16247 * @TODO this really should be an indexed array. Alternatively this
16248 * method could accept both.
16249 * @method refreshCache
16250 * @param {Object} groups an associative array of groups to refresh
16253 refreshCache: function(groups) {
16254 for (var sGroup in groups) {
16255 if ("string" != typeof sGroup) {
16258 for (var i in this.ids[sGroup]) {
16259 var oDD = this.ids[sGroup][i];
16261 if (this.isTypeOfDD(oDD)) {
16262 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16263 var loc = this.getLocation(oDD);
16265 this.locationCache[oDD.id] = loc;
16267 delete this.locationCache[oDD.id];
16268 // this will unregister the drag and drop object if
16269 // the element is not in a usable state
16278 * This checks to make sure an element exists and is in the DOM. The
16279 * main purpose is to handle cases where innerHTML is used to remove
16280 * drag and drop objects from the DOM. IE provides an 'unspecified
16281 * error' when trying to access the offsetParent of such an element
16283 * @param {HTMLElement} el the element to check
16284 * @return {boolean} true if the element looks usable
16287 verifyEl: function(el) {
16292 parent = el.offsetParent;
16295 parent = el.offsetParent;
16306 * Returns a Region object containing the drag and drop element's position
16307 * and size, including the padding configured for it
16308 * @method getLocation
16309 * @param {DragDrop} oDD the drag and drop object to get the
16311 * @return {Roo.lib.Region} a Region object representing the total area
16312 * the element occupies, including any padding
16313 * the instance is configured for.
16316 getLocation: function(oDD) {
16317 if (! this.isTypeOfDD(oDD)) {
16321 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16324 pos= Roo.lib.Dom.getXY(el);
16332 x2 = x1 + el.offsetWidth;
16334 y2 = y1 + el.offsetHeight;
16336 t = y1 - oDD.padding[0];
16337 r = x2 + oDD.padding[1];
16338 b = y2 + oDD.padding[2];
16339 l = x1 - oDD.padding[3];
16341 return new Roo.lib.Region( t, r, b, l );
16345 * Checks the cursor location to see if it over the target
16346 * @method isOverTarget
16347 * @param {Roo.lib.Point} pt The point to evaluate
16348 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16349 * @return {boolean} true if the mouse is over the target
16353 isOverTarget: function(pt, oTarget, intersect) {
16354 // use cache if available
16355 var loc = this.locationCache[oTarget.id];
16356 if (!loc || !this.useCache) {
16357 loc = this.getLocation(oTarget);
16358 this.locationCache[oTarget.id] = loc;
16366 oTarget.cursorIsOver = loc.contains( pt );
16368 // DragDrop is using this as a sanity check for the initial mousedown
16369 // in this case we are done. In POINT mode, if the drag obj has no
16370 // contraints, we are also done. Otherwise we need to evaluate the
16371 // location of the target as related to the actual location of the
16372 // dragged element.
16373 var dc = this.dragCurrent;
16374 if (!dc || !dc.getTargetCoord ||
16375 (!intersect && !dc.constrainX && !dc.constrainY)) {
16376 return oTarget.cursorIsOver;
16379 oTarget.overlap = null;
16381 // Get the current location of the drag element, this is the
16382 // location of the mouse event less the delta that represents
16383 // where the original mousedown happened on the element. We
16384 // need to consider constraints and ticks as well.
16385 var pos = dc.getTargetCoord(pt.x, pt.y);
16387 var el = dc.getDragEl();
16388 var curRegion = new Roo.lib.Region( pos.y,
16389 pos.x + el.offsetWidth,
16390 pos.y + el.offsetHeight,
16393 var overlap = curRegion.intersect(loc);
16396 oTarget.overlap = overlap;
16397 return (intersect) ? true : oTarget.cursorIsOver;
16404 * unload event handler
16405 * @method _onUnload
16409 _onUnload: function(e, me) {
16410 Roo.dd.DragDropMgr.unregAll();
16414 * Cleans up the drag and drop events and objects.
16419 unregAll: function() {
16421 if (this.dragCurrent) {
16423 this.dragCurrent = null;
16426 this._execOnAll("unreg", []);
16428 for (i in this.elementCache) {
16429 delete this.elementCache[i];
16432 this.elementCache = {};
16437 * A cache of DOM elements
16438 * @property elementCache
16445 * Get the wrapper for the DOM element specified
16446 * @method getElWrapper
16447 * @param {String} id the id of the element to get
16448 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16450 * @deprecated This wrapper isn't that useful
16453 getElWrapper: function(id) {
16454 var oWrapper = this.elementCache[id];
16455 if (!oWrapper || !oWrapper.el) {
16456 oWrapper = this.elementCache[id] =
16457 new this.ElementWrapper(Roo.getDom(id));
16463 * Returns the actual DOM element
16464 * @method getElement
16465 * @param {String} id the id of the elment to get
16466 * @return {Object} The element
16467 * @deprecated use Roo.getDom instead
16470 getElement: function(id) {
16471 return Roo.getDom(id);
16475 * Returns the style property for the DOM element (i.e.,
16476 * document.getElById(id).style)
16478 * @param {String} id the id of the elment to get
16479 * @return {Object} The style property of the element
16480 * @deprecated use Roo.getDom instead
16483 getCss: function(id) {
16484 var el = Roo.getDom(id);
16485 return (el) ? el.style : null;
16489 * Inner class for cached elements
16490 * @class DragDropMgr.ElementWrapper
16495 ElementWrapper: function(el) {
16500 this.el = el || null;
16505 this.id = this.el && el.id;
16507 * A reference to the style property
16510 this.css = this.el && el.style;
16514 * Returns the X position of an html element
16516 * @param el the element for which to get the position
16517 * @return {int} the X coordinate
16519 * @deprecated use Roo.lib.Dom.getX instead
16522 getPosX: function(el) {
16523 return Roo.lib.Dom.getX(el);
16527 * Returns the Y position of an html element
16529 * @param el the element for which to get the position
16530 * @return {int} the Y coordinate
16531 * @deprecated use Roo.lib.Dom.getY instead
16534 getPosY: function(el) {
16535 return Roo.lib.Dom.getY(el);
16539 * Swap two nodes. In IE, we use the native method, for others we
16540 * emulate the IE behavior
16542 * @param n1 the first node to swap
16543 * @param n2 the other node to swap
16546 swapNode: function(n1, n2) {
16550 var p = n2.parentNode;
16551 var s = n2.nextSibling;
16554 p.insertBefore(n1, n2);
16555 } else if (n2 == n1.nextSibling) {
16556 p.insertBefore(n2, n1);
16558 n1.parentNode.replaceChild(n2, n1);
16559 p.insertBefore(n1, s);
16565 * Returns the current scroll position
16566 * @method getScroll
16570 getScroll: function () {
16571 var t, l, dde=document.documentElement, db=document.body;
16572 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16574 l = dde.scrollLeft;
16581 return { top: t, left: l };
16585 * Returns the specified element style property
16587 * @param {HTMLElement} el the element
16588 * @param {string} styleProp the style property
16589 * @return {string} The value of the style property
16590 * @deprecated use Roo.lib.Dom.getStyle
16593 getStyle: function(el, styleProp) {
16594 return Roo.fly(el).getStyle(styleProp);
16598 * Gets the scrollTop
16599 * @method getScrollTop
16600 * @return {int} the document's scrollTop
16603 getScrollTop: function () { return this.getScroll().top; },
16606 * Gets the scrollLeft
16607 * @method getScrollLeft
16608 * @return {int} the document's scrollTop
16611 getScrollLeft: function () { return this.getScroll().left; },
16614 * Sets the x/y position of an element to the location of the
16617 * @param {HTMLElement} moveEl The element to move
16618 * @param {HTMLElement} targetEl The position reference element
16621 moveToEl: function (moveEl, targetEl) {
16622 var aCoord = Roo.lib.Dom.getXY(targetEl);
16623 Roo.lib.Dom.setXY(moveEl, aCoord);
16627 * Numeric array sort function
16628 * @method numericSort
16631 numericSort: function(a, b) { return (a - b); },
16635 * @property _timeoutCount
16642 * Trying to make the load order less important. Without this we get
16643 * an error if this file is loaded before the Event Utility.
16644 * @method _addListeners
16648 _addListeners: function() {
16649 var DDM = Roo.dd.DDM;
16650 if ( Roo.lib.Event && document ) {
16653 if (DDM._timeoutCount > 2000) {
16655 setTimeout(DDM._addListeners, 10);
16656 if (document && document.body) {
16657 DDM._timeoutCount += 1;
16664 * Recursively searches the immediate parent and all child nodes for
16665 * the handle element in order to determine wheter or not it was
16667 * @method handleWasClicked
16668 * @param node the html element to inspect
16671 handleWasClicked: function(node, id) {
16672 if (this.isHandle(id, node.id)) {
16675 // check to see if this is a text node child of the one we want
16676 var p = node.parentNode;
16679 if (this.isHandle(id, p.id)) {
16694 // shorter alias, save a few bytes
16695 Roo.dd.DDM = Roo.dd.DragDropMgr;
16696 Roo.dd.DDM._addListeners();
16700 * Ext JS Library 1.1.1
16701 * Copyright(c) 2006-2007, Ext JS, LLC.
16703 * Originally Released Under LGPL - original licence link has changed is not relivant.
16706 * <script type="text/javascript">
16711 * A DragDrop implementation where the linked element follows the
16712 * mouse cursor during a drag.
16713 * @extends Roo.dd.DragDrop
16715 * @param {String} id the id of the linked element
16716 * @param {String} sGroup the group of related DragDrop items
16717 * @param {object} config an object containing configurable attributes
16718 * Valid properties for DD:
16721 Roo.dd.DD = function(id, sGroup, config) {
16723 this.init(id, sGroup, config);
16727 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
16730 * When set to true, the utility automatically tries to scroll the browser
16731 * window wehn a drag and drop element is dragged near the viewport boundary.
16732 * Defaults to true.
16739 * Sets the pointer offset to the distance between the linked element's top
16740 * left corner and the location the element was clicked
16741 * @method autoOffset
16742 * @param {int} iPageX the X coordinate of the click
16743 * @param {int} iPageY the Y coordinate of the click
16745 autoOffset: function(iPageX, iPageY) {
16746 var x = iPageX - this.startPageX;
16747 var y = iPageY - this.startPageY;
16748 this.setDelta(x, y);
16752 * Sets the pointer offset. You can call this directly to force the
16753 * offset to be in a particular location (e.g., pass in 0,0 to set it
16754 * to the center of the object)
16756 * @param {int} iDeltaX the distance from the left
16757 * @param {int} iDeltaY the distance from the top
16759 setDelta: function(iDeltaX, iDeltaY) {
16760 this.deltaX = iDeltaX;
16761 this.deltaY = iDeltaY;
16765 * Sets the drag element to the location of the mousedown or click event,
16766 * maintaining the cursor location relative to the location on the element
16767 * that was clicked. Override this if you want to place the element in a
16768 * location other than where the cursor is.
16769 * @method setDragElPos
16770 * @param {int} iPageX the X coordinate of the mousedown or drag event
16771 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16773 setDragElPos: function(iPageX, iPageY) {
16774 // the first time we do this, we are going to check to make sure
16775 // the element has css positioning
16777 var el = this.getDragEl();
16778 this.alignElWithMouse(el, iPageX, iPageY);
16782 * Sets the element to the location of the mousedown or click event,
16783 * maintaining the cursor location relative to the location on the element
16784 * that was clicked. Override this if you want to place the element in a
16785 * location other than where the cursor is.
16786 * @method alignElWithMouse
16787 * @param {HTMLElement} el the element to move
16788 * @param {int} iPageX the X coordinate of the mousedown or drag event
16789 * @param {int} iPageY the Y coordinate of the mousedown or drag event
16791 alignElWithMouse: function(el, iPageX, iPageY) {
16792 var oCoord = this.getTargetCoord(iPageX, iPageY);
16793 var fly = el.dom ? el : Roo.fly(el);
16794 if (!this.deltaSetXY) {
16795 var aCoord = [oCoord.x, oCoord.y];
16797 var newLeft = fly.getLeft(true);
16798 var newTop = fly.getTop(true);
16799 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
16801 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
16804 this.cachePosition(oCoord.x, oCoord.y);
16805 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
16810 * Saves the most recent position so that we can reset the constraints and
16811 * tick marks on-demand. We need to know this so that we can calculate the
16812 * number of pixels the element is offset from its original position.
16813 * @method cachePosition
16814 * @param iPageX the current x position (optional, this just makes it so we
16815 * don't have to look it up again)
16816 * @param iPageY the current y position (optional, this just makes it so we
16817 * don't have to look it up again)
16819 cachePosition: function(iPageX, iPageY) {
16821 this.lastPageX = iPageX;
16822 this.lastPageY = iPageY;
16824 var aCoord = Roo.lib.Dom.getXY(this.getEl());
16825 this.lastPageX = aCoord[0];
16826 this.lastPageY = aCoord[1];
16831 * Auto-scroll the window if the dragged object has been moved beyond the
16832 * visible window boundary.
16833 * @method autoScroll
16834 * @param {int} x the drag element's x position
16835 * @param {int} y the drag element's y position
16836 * @param {int} h the height of the drag element
16837 * @param {int} w the width of the drag element
16840 autoScroll: function(x, y, h, w) {
16843 // The client height
16844 var clientH = Roo.lib.Dom.getViewWidth();
16846 // The client width
16847 var clientW = Roo.lib.Dom.getViewHeight();
16849 // The amt scrolled down
16850 var st = this.DDM.getScrollTop();
16852 // The amt scrolled right
16853 var sl = this.DDM.getScrollLeft();
16855 // Location of the bottom of the element
16858 // Location of the right of the element
16861 // The distance from the cursor to the bottom of the visible area,
16862 // adjusted so that we don't scroll if the cursor is beyond the
16863 // element drag constraints
16864 var toBot = (clientH + st - y - this.deltaY);
16866 // The distance from the cursor to the right of the visible area
16867 var toRight = (clientW + sl - x - this.deltaX);
16870 // How close to the edge the cursor must be before we scroll
16871 // var thresh = (document.all) ? 100 : 40;
16874 // How many pixels to scroll per autoscroll op. This helps to reduce
16875 // clunky scrolling. IE is more sensitive about this ... it needs this
16876 // value to be higher.
16877 var scrAmt = (document.all) ? 80 : 30;
16879 // Scroll down if we are near the bottom of the visible page and the
16880 // obj extends below the crease
16881 if ( bot > clientH && toBot < thresh ) {
16882 window.scrollTo(sl, st + scrAmt);
16885 // Scroll up if the window is scrolled down and the top of the object
16886 // goes above the top border
16887 if ( y < st && st > 0 && y - st < thresh ) {
16888 window.scrollTo(sl, st - scrAmt);
16891 // Scroll right if the obj is beyond the right border and the cursor is
16892 // near the border.
16893 if ( right > clientW && toRight < thresh ) {
16894 window.scrollTo(sl + scrAmt, st);
16897 // Scroll left if the window has been scrolled to the right and the obj
16898 // extends past the left border
16899 if ( x < sl && sl > 0 && x - sl < thresh ) {
16900 window.scrollTo(sl - scrAmt, st);
16906 * Finds the location the element should be placed if we want to move
16907 * it to where the mouse location less the click offset would place us.
16908 * @method getTargetCoord
16909 * @param {int} iPageX the X coordinate of the click
16910 * @param {int} iPageY the Y coordinate of the click
16911 * @return an object that contains the coordinates (Object.x and Object.y)
16914 getTargetCoord: function(iPageX, iPageY) {
16917 var x = iPageX - this.deltaX;
16918 var y = iPageY - this.deltaY;
16920 if (this.constrainX) {
16921 if (x < this.minX) { x = this.minX; }
16922 if (x > this.maxX) { x = this.maxX; }
16925 if (this.constrainY) {
16926 if (y < this.minY) { y = this.minY; }
16927 if (y > this.maxY) { y = this.maxY; }
16930 x = this.getTick(x, this.xTicks);
16931 y = this.getTick(y, this.yTicks);
16938 * Sets up config options specific to this class. Overrides
16939 * Roo.dd.DragDrop, but all versions of this method through the
16940 * inheritance chain are called
16942 applyConfig: function() {
16943 Roo.dd.DD.superclass.applyConfig.call(this);
16944 this.scroll = (this.config.scroll !== false);
16948 * Event that fires prior to the onMouseDown event. Overrides
16951 b4MouseDown: function(e) {
16952 // this.resetConstraints();
16953 this.autoOffset(e.getPageX(),
16958 * Event that fires prior to the onDrag event. Overrides
16961 b4Drag: function(e) {
16962 this.setDragElPos(e.getPageX(),
16966 toString: function() {
16967 return ("DD " + this.id);
16970 //////////////////////////////////////////////////////////////////////////
16971 // Debugging ygDragDrop events that can be overridden
16972 //////////////////////////////////////////////////////////////////////////
16974 startDrag: function(x, y) {
16977 onDrag: function(e) {
16980 onDragEnter: function(e, id) {
16983 onDragOver: function(e, id) {
16986 onDragOut: function(e, id) {
16989 onDragDrop: function(e, id) {
16992 endDrag: function(e) {
16999 * Ext JS Library 1.1.1
17000 * Copyright(c) 2006-2007, Ext JS, LLC.
17002 * Originally Released Under LGPL - original licence link has changed is not relivant.
17005 * <script type="text/javascript">
17009 * @class Roo.dd.DDProxy
17010 * A DragDrop implementation that inserts an empty, bordered div into
17011 * the document that follows the cursor during drag operations. At the time of
17012 * the click, the frame div is resized to the dimensions of the linked html
17013 * element, and moved to the exact location of the linked element.
17015 * References to the "frame" element refer to the single proxy element that
17016 * was created to be dragged in place of all DDProxy elements on the
17019 * @extends Roo.dd.DD
17021 * @param {String} id the id of the linked html element
17022 * @param {String} sGroup the group of related DragDrop objects
17023 * @param {object} config an object containing configurable attributes
17024 * Valid properties for DDProxy in addition to those in DragDrop:
17025 * resizeFrame, centerFrame, dragElId
17027 Roo.dd.DDProxy = function(id, sGroup, config) {
17029 this.init(id, sGroup, config);
17035 * The default drag frame div id
17036 * @property Roo.dd.DDProxy.dragElId
17040 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17042 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17045 * By default we resize the drag frame to be the same size as the element
17046 * we want to drag (this is to get the frame effect). We can turn it off
17047 * if we want a different behavior.
17048 * @property resizeFrame
17054 * By default the frame is positioned exactly where the drag element is, so
17055 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17056 * you do not have constraints on the obj is to have the drag frame centered
17057 * around the cursor. Set centerFrame to true for this effect.
17058 * @property centerFrame
17061 centerFrame: false,
17064 * Creates the proxy element if it does not yet exist
17065 * @method createFrame
17067 createFrame: function() {
17069 var body = document.body;
17071 if (!body || !body.firstChild) {
17072 setTimeout( function() { self.createFrame(); }, 50 );
17076 var div = this.getDragEl();
17079 div = document.createElement("div");
17080 div.id = this.dragElId;
17083 s.position = "absolute";
17084 s.visibility = "hidden";
17086 s.border = "2px solid #aaa";
17089 // appendChild can blow up IE if invoked prior to the window load event
17090 // while rendering a table. It is possible there are other scenarios
17091 // that would cause this to happen as well.
17092 body.insertBefore(div, body.firstChild);
17097 * Initialization for the drag frame element. Must be called in the
17098 * constructor of all subclasses
17099 * @method initFrame
17101 initFrame: function() {
17102 this.createFrame();
17105 applyConfig: function() {
17106 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17108 this.resizeFrame = (this.config.resizeFrame !== false);
17109 this.centerFrame = (this.config.centerFrame);
17110 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17114 * Resizes the drag frame to the dimensions of the clicked object, positions
17115 * it over the object, and finally displays it
17116 * @method showFrame
17117 * @param {int} iPageX X click position
17118 * @param {int} iPageY Y click position
17121 showFrame: function(iPageX, iPageY) {
17122 var el = this.getEl();
17123 var dragEl = this.getDragEl();
17124 var s = dragEl.style;
17126 this._resizeProxy();
17128 if (this.centerFrame) {
17129 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17130 Math.round(parseInt(s.height, 10)/2) );
17133 this.setDragElPos(iPageX, iPageY);
17135 Roo.fly(dragEl).show();
17139 * The proxy is automatically resized to the dimensions of the linked
17140 * element when a drag is initiated, unless resizeFrame is set to false
17141 * @method _resizeProxy
17144 _resizeProxy: function() {
17145 if (this.resizeFrame) {
17146 var el = this.getEl();
17147 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17151 // overrides Roo.dd.DragDrop
17152 b4MouseDown: function(e) {
17153 var x = e.getPageX();
17154 var y = e.getPageY();
17155 this.autoOffset(x, y);
17156 this.setDragElPos(x, y);
17159 // overrides Roo.dd.DragDrop
17160 b4StartDrag: function(x, y) {
17161 // show the drag frame
17162 this.showFrame(x, y);
17165 // overrides Roo.dd.DragDrop
17166 b4EndDrag: function(e) {
17167 Roo.fly(this.getDragEl()).hide();
17170 // overrides Roo.dd.DragDrop
17171 // By default we try to move the element to the last location of the frame.
17172 // This is so that the default behavior mirrors that of Roo.dd.DD.
17173 endDrag: function(e) {
17175 var lel = this.getEl();
17176 var del = this.getDragEl();
17178 // Show the drag frame briefly so we can get its position
17179 del.style.visibility = "";
17182 // Hide the linked element before the move to get around a Safari
17184 lel.style.visibility = "hidden";
17185 Roo.dd.DDM.moveToEl(lel, del);
17186 del.style.visibility = "hidden";
17187 lel.style.visibility = "";
17192 beforeMove : function(){
17196 afterDrag : function(){
17200 toString: function() {
17201 return ("DDProxy " + this.id);
17207 * Ext JS Library 1.1.1
17208 * Copyright(c) 2006-2007, Ext JS, LLC.
17210 * Originally Released Under LGPL - original licence link has changed is not relivant.
17213 * <script type="text/javascript">
17217 * @class Roo.dd.DDTarget
17218 * A DragDrop implementation that does not move, but can be a drop
17219 * target. You would get the same result by simply omitting implementation
17220 * for the event callbacks, but this way we reduce the processing cost of the
17221 * event listener and the callbacks.
17222 * @extends Roo.dd.DragDrop
17224 * @param {String} id the id of the element that is a drop target
17225 * @param {String} sGroup the group of related DragDrop objects
17226 * @param {object} config an object containing configurable attributes
17227 * Valid properties for DDTarget in addition to those in
17231 Roo.dd.DDTarget = function(id, sGroup, config) {
17233 this.initTarget(id, sGroup, config);
17237 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17238 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17239 toString: function() {
17240 return ("DDTarget " + this.id);
17245 * Ext JS Library 1.1.1
17246 * Copyright(c) 2006-2007, Ext JS, LLC.
17248 * Originally Released Under LGPL - original licence link has changed is not relivant.
17251 * <script type="text/javascript">
17256 * @class Roo.dd.ScrollManager
17257 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17258 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17261 Roo.dd.ScrollManager = function(){
17262 var ddm = Roo.dd.DragDropMgr;
17267 var onStop = function(e){
17272 var triggerRefresh = function(){
17273 if(ddm.dragCurrent){
17274 ddm.refreshCache(ddm.dragCurrent.groups);
17278 var doScroll = function(){
17279 if(ddm.dragCurrent){
17280 var dds = Roo.dd.ScrollManager;
17282 if(proc.el.scroll(proc.dir, dds.increment)){
17286 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17291 var clearProc = function(){
17293 clearInterval(proc.id);
17300 var startProc = function(el, dir){
17304 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17307 var onFire = function(e, isDrop){
17308 if(isDrop || !ddm.dragCurrent){ return; }
17309 var dds = Roo.dd.ScrollManager;
17310 if(!dragEl || dragEl != ddm.dragCurrent){
17311 dragEl = ddm.dragCurrent;
17312 // refresh regions on drag start
17313 dds.refreshCache();
17316 var xy = Roo.lib.Event.getXY(e);
17317 var pt = new Roo.lib.Point(xy[0], xy[1]);
17318 for(var id in els){
17319 var el = els[id], r = el._region;
17320 if(r && r.contains(pt) && el.isScrollable()){
17321 if(r.bottom - pt.y <= dds.thresh){
17323 startProc(el, "down");
17326 }else if(r.right - pt.x <= dds.thresh){
17328 startProc(el, "left");
17331 }else if(pt.y - r.top <= dds.thresh){
17333 startProc(el, "up");
17336 }else if(pt.x - r.left <= dds.thresh){
17338 startProc(el, "right");
17347 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17348 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17352 * Registers new overflow element(s) to auto scroll
17353 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17355 register : function(el){
17356 if(el instanceof Array){
17357 for(var i = 0, len = el.length; i < len; i++) {
17358 this.register(el[i]);
17367 * Unregisters overflow element(s) so they are no longer scrolled
17368 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17370 unregister : function(el){
17371 if(el instanceof Array){
17372 for(var i = 0, len = el.length; i < len; i++) {
17373 this.unregister(el[i]);
17382 * The number of pixels from the edge of a container the pointer needs to be to
17383 * trigger scrolling (defaults to 25)
17389 * The number of pixels to scroll in each scroll increment (defaults to 50)
17395 * The frequency of scrolls in milliseconds (defaults to 500)
17401 * True to animate the scroll (defaults to true)
17407 * The animation duration in seconds -
17408 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17414 * Manually trigger a cache refresh.
17416 refreshCache : function(){
17417 for(var id in els){
17418 if(typeof els[id] == 'object'){ // for people extending the object prototype
17419 els[id]._region = els[id].getRegion();
17426 * Ext JS Library 1.1.1
17427 * Copyright(c) 2006-2007, Ext JS, LLC.
17429 * Originally Released Under LGPL - original licence link has changed is not relivant.
17432 * <script type="text/javascript">
17437 * @class Roo.dd.Registry
17438 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17439 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17442 Roo.dd.Registry = function(){
17445 var autoIdSeed = 0;
17447 var getId = function(el, autogen){
17448 if(typeof el == "string"){
17452 if(!id && autogen !== false){
17453 id = "roodd-" + (++autoIdSeed);
17461 * Register a drag drop element
17462 * @param {String/HTMLElement) element The id or DOM node to register
17463 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17464 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17465 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17466 * populated in the data object (if applicable):
17468 Value Description<br />
17469 --------- ------------------------------------------<br />
17470 handles Array of DOM nodes that trigger dragging<br />
17471 for the element being registered<br />
17472 isHandle True if the element passed in triggers<br />
17473 dragging itself, else false
17476 register : function(el, data){
17478 if(typeof el == "string"){
17479 el = document.getElementById(el);
17482 elements[getId(el)] = data;
17483 if(data.isHandle !== false){
17484 handles[data.ddel.id] = data;
17487 var hs = data.handles;
17488 for(var i = 0, len = hs.length; i < len; i++){
17489 handles[getId(hs[i])] = data;
17495 * Unregister a drag drop element
17496 * @param {String/HTMLElement) element The id or DOM node to unregister
17498 unregister : function(el){
17499 var id = getId(el, false);
17500 var data = elements[id];
17502 delete elements[id];
17504 var hs = data.handles;
17505 for(var i = 0, len = hs.length; i < len; i++){
17506 delete handles[getId(hs[i], false)];
17513 * Returns the handle registered for a DOM Node by id
17514 * @param {String/HTMLElement} id The DOM node or id to look up
17515 * @return {Object} handle The custom handle data
17517 getHandle : function(id){
17518 if(typeof id != "string"){ // must be element?
17521 return handles[id];
17525 * Returns the handle that is registered for the DOM node that is the target of the event
17526 * @param {Event} e The event
17527 * @return {Object} handle The custom handle data
17529 getHandleFromEvent : function(e){
17530 var t = Roo.lib.Event.getTarget(e);
17531 return t ? handles[t.id] : null;
17535 * Returns a custom data object that is registered for a DOM node by id
17536 * @param {String/HTMLElement} id The DOM node or id to look up
17537 * @return {Object} data The custom data
17539 getTarget : function(id){
17540 if(typeof id != "string"){ // must be element?
17543 return elements[id];
17547 * Returns a custom data object that is registered for the DOM node that is the target of the event
17548 * @param {Event} e The event
17549 * @return {Object} data The custom data
17551 getTargetFromEvent : function(e){
17552 var t = Roo.lib.Event.getTarget(e);
17553 return t ? elements[t.id] || handles[t.id] : null;
17558 * Ext JS Library 1.1.1
17559 * Copyright(c) 2006-2007, Ext JS, LLC.
17561 * Originally Released Under LGPL - original licence link has changed is not relivant.
17564 * <script type="text/javascript">
17569 * @class Roo.dd.StatusProxy
17570 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17571 * default drag proxy used by all Roo.dd components.
17573 * @param {Object} config
17575 Roo.dd.StatusProxy = function(config){
17576 Roo.apply(this, config);
17577 this.id = this.id || Roo.id();
17578 this.el = new Roo.Layer({
17580 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17581 {tag: "div", cls: "x-dd-drop-icon"},
17582 {tag: "div", cls: "x-dd-drag-ghost"}
17585 shadow: !config || config.shadow !== false
17587 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17588 this.dropStatus = this.dropNotAllowed;
17591 Roo.dd.StatusProxy.prototype = {
17593 * @cfg {String} dropAllowed
17594 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17596 dropAllowed : "x-dd-drop-ok",
17598 * @cfg {String} dropNotAllowed
17599 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17601 dropNotAllowed : "x-dd-drop-nodrop",
17604 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17605 * over the current target element.
17606 * @param {String} cssClass The css class for the new drop status indicator image
17608 setStatus : function(cssClass){
17609 cssClass = cssClass || this.dropNotAllowed;
17610 if(this.dropStatus != cssClass){
17611 this.el.replaceClass(this.dropStatus, cssClass);
17612 this.dropStatus = cssClass;
17617 * Resets the status indicator to the default dropNotAllowed value
17618 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17620 reset : function(clearGhost){
17621 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17622 this.dropStatus = this.dropNotAllowed;
17624 this.ghost.update("");
17629 * Updates the contents of the ghost element
17630 * @param {String} html The html that will replace the current innerHTML of the ghost element
17632 update : function(html){
17633 if(typeof html == "string"){
17634 this.ghost.update(html);
17636 this.ghost.update("");
17637 html.style.margin = "0";
17638 this.ghost.dom.appendChild(html);
17640 // ensure float = none set?? cant remember why though.
17641 var el = this.ghost.dom.firstChild;
17643 Roo.fly(el).setStyle('float', 'none');
17648 * Returns the underlying proxy {@link Roo.Layer}
17649 * @return {Roo.Layer} el
17651 getEl : function(){
17656 * Returns the ghost element
17657 * @return {Roo.Element} el
17659 getGhost : function(){
17665 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17667 hide : function(clear){
17675 * Stops the repair animation if it's currently running
17678 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17684 * Displays this proxy
17691 * Force the Layer to sync its shadow and shim positions to the element
17698 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17699 * invalid drop operation by the item being dragged.
17700 * @param {Array} xy The XY position of the element ([x, y])
17701 * @param {Function} callback The function to call after the repair is complete
17702 * @param {Object} scope The scope in which to execute the callback
17704 repair : function(xy, callback, scope){
17705 this.callback = callback;
17706 this.scope = scope;
17707 if(xy && this.animRepair !== false){
17708 this.el.addClass("x-dd-drag-repair");
17709 this.el.hideUnders(true);
17710 this.anim = this.el.shift({
17711 duration: this.repairDuration || .5,
17715 callback: this.afterRepair,
17719 this.afterRepair();
17724 afterRepair : function(){
17726 if(typeof this.callback == "function"){
17727 this.callback.call(this.scope || this);
17729 this.callback = null;
17734 * Ext JS Library 1.1.1
17735 * Copyright(c) 2006-2007, Ext JS, LLC.
17737 * Originally Released Under LGPL - original licence link has changed is not relivant.
17740 * <script type="text/javascript">
17744 * @class Roo.dd.DragSource
17745 * @extends Roo.dd.DDProxy
17746 * A simple class that provides the basic implementation needed to make any element draggable.
17748 * @param {String/HTMLElement/Element} el The container element
17749 * @param {Object} config
17751 Roo.dd.DragSource = function(el, config){
17752 this.el = Roo.get(el);
17753 this.dragData = {};
17755 Roo.apply(this, config);
17758 this.proxy = new Roo.dd.StatusProxy();
17761 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
17762 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
17764 this.dragging = false;
17767 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
17769 * @cfg {String} dropAllowed
17770 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
17772 dropAllowed : "x-dd-drop-ok",
17774 * @cfg {String} dropNotAllowed
17775 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
17777 dropNotAllowed : "x-dd-drop-nodrop",
17780 * Returns the data object associated with this drag source
17781 * @return {Object} data An object containing arbitrary data
17783 getDragData : function(e){
17784 return this.dragData;
17788 onDragEnter : function(e, id){
17789 var target = Roo.dd.DragDropMgr.getDDById(id);
17790 this.cachedTarget = target;
17791 if(this.beforeDragEnter(target, e, id) !== false){
17792 if(target.isNotifyTarget){
17793 var status = target.notifyEnter(this, e, this.dragData);
17794 this.proxy.setStatus(status);
17796 this.proxy.setStatus(this.dropAllowed);
17799 if(this.afterDragEnter){
17801 * An empty function by default, but provided so that you can perform a custom action
17802 * when the dragged item enters the drop target by providing an implementation.
17803 * @param {Roo.dd.DragDrop} target The drop target
17804 * @param {Event} e The event object
17805 * @param {String} id The id of the dragged element
17806 * @method afterDragEnter
17808 this.afterDragEnter(target, e, id);
17814 * An empty function by default, but provided so that you can perform a custom action
17815 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
17816 * @param {Roo.dd.DragDrop} target The drop target
17817 * @param {Event} e The event object
17818 * @param {String} id The id of the dragged element
17819 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17821 beforeDragEnter : function(target, e, id){
17826 alignElWithMouse: function() {
17827 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
17832 onDragOver : function(e, id){
17833 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17834 if(this.beforeDragOver(target, e, id) !== false){
17835 if(target.isNotifyTarget){
17836 var status = target.notifyOver(this, e, this.dragData);
17837 this.proxy.setStatus(status);
17840 if(this.afterDragOver){
17842 * An empty function by default, but provided so that you can perform a custom action
17843 * while the dragged item is over the drop target by providing an implementation.
17844 * @param {Roo.dd.DragDrop} target The drop target
17845 * @param {Event} e The event object
17846 * @param {String} id The id of the dragged element
17847 * @method afterDragOver
17849 this.afterDragOver(target, e, id);
17855 * An empty function by default, but provided so that you can perform a custom action
17856 * while the dragged item is over the drop target and optionally cancel the onDragOver.
17857 * @param {Roo.dd.DragDrop} target The drop target
17858 * @param {Event} e The event object
17859 * @param {String} id The id of the dragged element
17860 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17862 beforeDragOver : function(target, e, id){
17867 onDragOut : function(e, id){
17868 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17869 if(this.beforeDragOut(target, e, id) !== false){
17870 if(target.isNotifyTarget){
17871 target.notifyOut(this, e, this.dragData);
17873 this.proxy.reset();
17874 if(this.afterDragOut){
17876 * An empty function by default, but provided so that you can perform a custom action
17877 * after the dragged item is dragged out of the target without dropping.
17878 * @param {Roo.dd.DragDrop} target The drop target
17879 * @param {Event} e The event object
17880 * @param {String} id The id of the dragged element
17881 * @method afterDragOut
17883 this.afterDragOut(target, e, id);
17886 this.cachedTarget = null;
17890 * An empty function by default, but provided so that you can perform a custom action before the dragged
17891 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
17892 * @param {Roo.dd.DragDrop} target The drop target
17893 * @param {Event} e The event object
17894 * @param {String} id The id of the dragged element
17895 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
17897 beforeDragOut : function(target, e, id){
17902 onDragDrop : function(e, id){
17903 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
17904 if(this.beforeDragDrop(target, e, id) !== false){
17905 if(target.isNotifyTarget){
17906 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
17907 this.onValidDrop(target, e, id);
17909 this.onInvalidDrop(target, e, id);
17912 this.onValidDrop(target, e, id);
17915 if(this.afterDragDrop){
17917 * An empty function by default, but provided so that you can perform a custom action
17918 * after a valid drag drop has occurred by providing an implementation.
17919 * @param {Roo.dd.DragDrop} target The drop target
17920 * @param {Event} e The event object
17921 * @param {String} id The id of the dropped element
17922 * @method afterDragDrop
17924 this.afterDragDrop(target, e, id);
17927 delete this.cachedTarget;
17931 * An empty function by default, but provided so that you can perform a custom action before the dragged
17932 * item is dropped onto the target and optionally cancel the onDragDrop.
17933 * @param {Roo.dd.DragDrop} target The drop target
17934 * @param {Event} e The event object
17935 * @param {String} id The id of the dragged element
17936 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
17938 beforeDragDrop : function(target, e, id){
17943 onValidDrop : function(target, e, id){
17945 if(this.afterValidDrop){
17947 * An empty function by default, but provided so that you can perform a custom action
17948 * after a valid drop has occurred by providing an implementation.
17949 * @param {Object} target The target DD
17950 * @param {Event} e The event object
17951 * @param {String} id The id of the dropped element
17952 * @method afterInvalidDrop
17954 this.afterValidDrop(target, e, id);
17959 getRepairXY : function(e, data){
17960 return this.el.getXY();
17964 onInvalidDrop : function(target, e, id){
17965 this.beforeInvalidDrop(target, e, id);
17966 if(this.cachedTarget){
17967 if(this.cachedTarget.isNotifyTarget){
17968 this.cachedTarget.notifyOut(this, e, this.dragData);
17970 this.cacheTarget = null;
17972 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
17974 if(this.afterInvalidDrop){
17976 * An empty function by default, but provided so that you can perform a custom action
17977 * after an invalid drop has occurred by providing an implementation.
17978 * @param {Event} e The event object
17979 * @param {String} id The id of the dropped element
17980 * @method afterInvalidDrop
17982 this.afterInvalidDrop(e, id);
17987 afterRepair : function(){
17989 this.el.highlight(this.hlColor || "c3daf9");
17991 this.dragging = false;
17995 * An empty function by default, but provided so that you can perform a custom action after an invalid
17996 * drop has occurred.
17997 * @param {Roo.dd.DragDrop} target The drop target
17998 * @param {Event} e The event object
17999 * @param {String} id The id of the dragged element
18000 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18002 beforeInvalidDrop : function(target, e, id){
18007 handleMouseDown : function(e){
18008 if(this.dragging) {
18011 var data = this.getDragData(e);
18012 if(data && this.onBeforeDrag(data, e) !== false){
18013 this.dragData = data;
18015 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18020 * An empty function by default, but provided so that you can perform a custom action before the initial
18021 * drag event begins and optionally cancel it.
18022 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18023 * @param {Event} e The event object
18024 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18026 onBeforeDrag : function(data, e){
18031 * An empty function by default, but provided so that you can perform a custom action once the initial
18032 * drag event has begun. The drag cannot be canceled from this function.
18033 * @param {Number} x The x position of the click on the dragged object
18034 * @param {Number} y The y position of the click on the dragged object
18036 onStartDrag : Roo.emptyFn,
18038 // private - YUI override
18039 startDrag : function(x, y){
18040 this.proxy.reset();
18041 this.dragging = true;
18042 this.proxy.update("");
18043 this.onInitDrag(x, y);
18048 onInitDrag : function(x, y){
18049 var clone = this.el.dom.cloneNode(true);
18050 clone.id = Roo.id(); // prevent duplicate ids
18051 this.proxy.update(clone);
18052 this.onStartDrag(x, y);
18057 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18058 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18060 getProxy : function(){
18065 * Hides the drag source's {@link Roo.dd.StatusProxy}
18067 hideProxy : function(){
18069 this.proxy.reset(true);
18070 this.dragging = false;
18074 triggerCacheRefresh : function(){
18075 Roo.dd.DDM.refreshCache(this.groups);
18078 // private - override to prevent hiding
18079 b4EndDrag: function(e) {
18082 // private - override to prevent moving
18083 endDrag : function(e){
18084 this.onEndDrag(this.dragData, e);
18088 onEndDrag : function(data, e){
18091 // private - pin to cursor
18092 autoOffset : function(x, y) {
18093 this.setDelta(-12, -20);
18097 * Ext JS Library 1.1.1
18098 * Copyright(c) 2006-2007, Ext JS, LLC.
18100 * Originally Released Under LGPL - original licence link has changed is not relivant.
18103 * <script type="text/javascript">
18108 * @class Roo.dd.DropTarget
18109 * @extends Roo.dd.DDTarget
18110 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18111 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18113 * @param {String/HTMLElement/Element} el The container element
18114 * @param {Object} config
18116 Roo.dd.DropTarget = function(el, config){
18117 this.el = Roo.get(el);
18119 Roo.apply(this, config);
18121 if(this.containerScroll){
18122 Roo.dd.ScrollManager.register(this.el);
18125 Roo.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18130 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18132 * @cfg {String} overClass
18133 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18136 * @cfg {String} dropAllowed
18137 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18139 dropAllowed : "x-dd-drop-ok",
18141 * @cfg {String} dropNotAllowed
18142 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18144 dropNotAllowed : "x-dd-drop-nodrop",
18150 isNotifyTarget : true,
18153 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18154 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18155 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18156 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18157 * @param {Event} e The event
18158 * @param {Object} data An object containing arbitrary data supplied by the drag source
18159 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18160 * underlying {@link Roo.dd.StatusProxy} can be updated
18162 notifyEnter : function(dd, e, data){
18163 if(this.overClass){
18164 this.el.addClass(this.overClass);
18166 return this.dropAllowed;
18170 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18171 * This method will be called on every mouse movement while the drag source is over the drop target.
18172 * This default implementation simply returns the dropAllowed config value.
18173 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18174 * @param {Event} e The event
18175 * @param {Object} data An object containing arbitrary data supplied by the drag source
18176 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18177 * underlying {@link Roo.dd.StatusProxy} can be updated
18179 notifyOver : function(dd, e, data){
18180 return this.dropAllowed;
18184 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18185 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18186 * overClass (if any) from the drop element.
18187 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18188 * @param {Event} e The event
18189 * @param {Object} data An object containing arbitrary data supplied by the drag source
18191 notifyOut : function(dd, e, data){
18192 if(this.overClass){
18193 this.el.removeClass(this.overClass);
18198 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18199 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18200 * implementation that does something to process the drop event and returns true so that the drag source's
18201 * repair action does not run.
18202 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18203 * @param {Event} e The event
18204 * @param {Object} data An object containing arbitrary data supplied by the drag source
18205 * @return {Boolean} True if the drop was valid, else false
18207 notifyDrop : function(dd, e, data){
18212 * Ext JS Library 1.1.1
18213 * Copyright(c) 2006-2007, Ext JS, LLC.
18215 * Originally Released Under LGPL - original licence link has changed is not relivant.
18218 * <script type="text/javascript">
18223 * @class Roo.dd.DragZone
18224 * @extends Roo.dd.DragSource
18225 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18226 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18228 * @param {String/HTMLElement/Element} el The container element
18229 * @param {Object} config
18231 Roo.dd.DragZone = function(el, config){
18232 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18233 if(this.containerScroll){
18234 Roo.dd.ScrollManager.register(this.el);
18238 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18240 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18241 * for auto scrolling during drag operations.
18244 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18245 * method after a failed drop (defaults to "c3daf9" - light blue)
18249 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18250 * for a valid target to drag based on the mouse down. Override this method
18251 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18252 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18253 * @param {EventObject} e The mouse down event
18254 * @return {Object} The dragData
18256 getDragData : function(e){
18257 return Roo.dd.Registry.getHandleFromEvent(e);
18261 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18262 * this.dragData.ddel
18263 * @param {Number} x The x position of the click on the dragged object
18264 * @param {Number} y The y position of the click on the dragged object
18265 * @return {Boolean} true to continue the drag, false to cancel
18267 onInitDrag : function(x, y){
18268 this.proxy.update(this.dragData.ddel.cloneNode(true));
18269 this.onStartDrag(x, y);
18274 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18276 afterRepair : function(){
18278 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18280 this.dragging = false;
18284 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18285 * the XY of this.dragData.ddel
18286 * @param {EventObject} e The mouse up event
18287 * @return {Array} The xy location (e.g. [100, 200])
18289 getRepairXY : function(e){
18290 return Roo.Element.fly(this.dragData.ddel).getXY();
18294 * Ext JS Library 1.1.1
18295 * Copyright(c) 2006-2007, Ext JS, LLC.
18297 * Originally Released Under LGPL - original licence link has changed is not relivant.
18300 * <script type="text/javascript">
18303 * @class Roo.dd.DropZone
18304 * @extends Roo.dd.DropTarget
18305 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18306 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18308 * @param {String/HTMLElement/Element} el The container element
18309 * @param {Object} config
18311 Roo.dd.DropZone = function(el, config){
18312 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18315 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18317 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18318 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18319 * provide your own custom lookup.
18320 * @param {Event} e The event
18321 * @return {Object} data The custom data
18323 getTargetFromEvent : function(e){
18324 return Roo.dd.Registry.getTargetFromEvent(e);
18328 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18329 * that it has registered. This method has no default implementation and should be overridden to provide
18330 * node-specific processing if necessary.
18331 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18332 * {@link #getTargetFromEvent} for this node)
18333 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18334 * @param {Event} e The event
18335 * @param {Object} data An object containing arbitrary data supplied by the drag source
18337 onNodeEnter : function(n, dd, e, data){
18342 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18343 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18344 * overridden to provide the proper feedback.
18345 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18346 * {@link #getTargetFromEvent} for this node)
18347 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18348 * @param {Event} e The event
18349 * @param {Object} data An object containing arbitrary data supplied by the drag source
18350 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18351 * underlying {@link Roo.dd.StatusProxy} can be updated
18353 onNodeOver : function(n, dd, e, data){
18354 return this.dropAllowed;
18358 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18359 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18360 * node-specific processing if necessary.
18361 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18362 * {@link #getTargetFromEvent} for this node)
18363 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18364 * @param {Event} e The event
18365 * @param {Object} data An object containing arbitrary data supplied by the drag source
18367 onNodeOut : function(n, dd, e, data){
18372 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18373 * the drop node. The default implementation returns false, so it should be overridden to provide the
18374 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18375 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18376 * {@link #getTargetFromEvent} for this node)
18377 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18378 * @param {Event} e The event
18379 * @param {Object} data An object containing arbitrary data supplied by the drag source
18380 * @return {Boolean} True if the drop was valid, else false
18382 onNodeDrop : function(n, dd, e, data){
18387 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18388 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18389 * it should be overridden to provide the proper feedback if necessary.
18390 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18391 * @param {Event} e The event
18392 * @param {Object} data An object containing arbitrary data supplied by the drag source
18393 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18394 * underlying {@link Roo.dd.StatusProxy} can be updated
18396 onContainerOver : function(dd, e, data){
18397 return this.dropNotAllowed;
18401 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18402 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18403 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18404 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18405 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18406 * @param {Event} e The event
18407 * @param {Object} data An object containing arbitrary data supplied by the drag source
18408 * @return {Boolean} True if the drop was valid, else false
18410 onContainerDrop : function(dd, e, data){
18415 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18416 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18417 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18418 * you should override this method and provide a custom implementation.
18419 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18420 * @param {Event} e The event
18421 * @param {Object} data An object containing arbitrary data supplied by the drag source
18422 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18423 * underlying {@link Roo.dd.StatusProxy} can be updated
18425 notifyEnter : function(dd, e, data){
18426 return this.dropNotAllowed;
18430 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18431 * This method will be called on every mouse movement while the drag source is over the drop zone.
18432 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18433 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18434 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18435 * registered node, it will call {@link #onContainerOver}.
18436 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18437 * @param {Event} e The event
18438 * @param {Object} data An object containing arbitrary data supplied by the drag source
18439 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18440 * underlying {@link Roo.dd.StatusProxy} can be updated
18442 notifyOver : function(dd, e, data){
18443 var n = this.getTargetFromEvent(e);
18444 if(!n){ // not over valid drop target
18445 if(this.lastOverNode){
18446 this.onNodeOut(this.lastOverNode, dd, e, data);
18447 this.lastOverNode = null;
18449 return this.onContainerOver(dd, e, data);
18451 if(this.lastOverNode != n){
18452 if(this.lastOverNode){
18453 this.onNodeOut(this.lastOverNode, dd, e, data);
18455 this.onNodeEnter(n, dd, e, data);
18456 this.lastOverNode = n;
18458 return this.onNodeOver(n, dd, e, data);
18462 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18463 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18464 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18465 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18466 * @param {Event} e The event
18467 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18469 notifyOut : function(dd, e, data){
18470 if(this.lastOverNode){
18471 this.onNodeOut(this.lastOverNode, dd, e, data);
18472 this.lastOverNode = null;
18477 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18478 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18479 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18480 * otherwise it will call {@link #onContainerDrop}.
18481 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18482 * @param {Event} e The event
18483 * @param {Object} data An object containing arbitrary data supplied by the drag source
18484 * @return {Boolean} True if the drop was valid, else false
18486 notifyDrop : function(dd, e, data){
18487 if(this.lastOverNode){
18488 this.onNodeOut(this.lastOverNode, dd, e, data);
18489 this.lastOverNode = null;
18491 var n = this.getTargetFromEvent(e);
18493 this.onNodeDrop(n, dd, e, data) :
18494 this.onContainerDrop(dd, e, data);
18498 triggerCacheRefresh : function(){
18499 Roo.dd.DDM.refreshCache(this.groups);
18503 * Ext JS Library 1.1.1
18504 * Copyright(c) 2006-2007, Ext JS, LLC.
18506 * Originally Released Under LGPL - original licence link has changed is not relivant.
18509 * <script type="text/javascript">
18514 * @class Roo.data.SortTypes
18516 * Defines the default sorting (casting?) comparison functions used when sorting data.
18518 Roo.data.SortTypes = {
18520 * Default sort that does nothing
18521 * @param {Mixed} s The value being converted
18522 * @return {Mixed} The comparison value
18524 none : function(s){
18529 * The regular expression used to strip tags
18533 stripTagsRE : /<\/?[^>]+>/gi,
18536 * Strips all HTML tags to sort on text only
18537 * @param {Mixed} s The value being converted
18538 * @return {String} The comparison value
18540 asText : function(s){
18541 return String(s).replace(this.stripTagsRE, "");
18545 * Strips all HTML tags to sort on text only - Case insensitive
18546 * @param {Mixed} s The value being converted
18547 * @return {String} The comparison value
18549 asUCText : function(s){
18550 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18554 * Case insensitive string
18555 * @param {Mixed} s The value being converted
18556 * @return {String} The comparison value
18558 asUCString : function(s) {
18559 return String(s).toUpperCase();
18564 * @param {Mixed} s The value being converted
18565 * @return {Number} The comparison value
18567 asDate : function(s) {
18571 if(s instanceof Date){
18572 return s.getTime();
18574 return Date.parse(String(s));
18579 * @param {Mixed} s The value being converted
18580 * @return {Float} The comparison value
18582 asFloat : function(s) {
18583 var val = parseFloat(String(s).replace(/,/g, ""));
18584 if(isNaN(val)) val = 0;
18590 * @param {Mixed} s The value being converted
18591 * @return {Number} The comparison value
18593 asInt : function(s) {
18594 var val = parseInt(String(s).replace(/,/g, ""));
18595 if(isNaN(val)) val = 0;
18600 * Ext JS Library 1.1.1
18601 * Copyright(c) 2006-2007, Ext JS, LLC.
18603 * Originally Released Under LGPL - original licence link has changed is not relivant.
18606 * <script type="text/javascript">
18610 * @class Roo.data.Record
18611 * Instances of this class encapsulate both record <em>definition</em> information, and record
18612 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18613 * to access Records cached in an {@link Roo.data.Store} object.<br>
18615 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18616 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18619 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18621 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18622 * {@link #create}. The parameters are the same.
18623 * @param {Array} data An associative Array of data values keyed by the field name.
18624 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18625 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18626 * not specified an integer id is generated.
18628 Roo.data.Record = function(data, id){
18629 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18634 * Generate a constructor for a specific record layout.
18635 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18636 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18637 * Each field definition object may contain the following properties: <ul>
18638 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
18639 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18640 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18641 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18642 * is being used, then this is a string containing the javascript expression to reference the data relative to
18643 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18644 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18645 * this may be omitted.</p></li>
18646 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
18647 * <ul><li>auto (Default, implies no conversion)</li>
18652 * <li>date</li></ul></p></li>
18653 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
18654 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
18655 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
18656 * by the Reader into an object that will be stored in the Record. It is passed the
18657 * following parameters:<ul>
18658 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
18660 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
18662 * <br>usage:<br><pre><code>
18663 var TopicRecord = Roo.data.Record.create(
18664 {name: 'title', mapping: 'topic_title'},
18665 {name: 'author', mapping: 'username'},
18666 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
18667 {name: 'lastPost', mapping: 'post_time', type: 'date'},
18668 {name: 'lastPoster', mapping: 'user2'},
18669 {name: 'excerpt', mapping: 'post_text'}
18672 var myNewRecord = new TopicRecord({
18673 title: 'Do my job please',
18676 lastPost: new Date(),
18677 lastPoster: 'Animal',
18678 excerpt: 'No way dude!'
18680 myStore.add(myNewRecord);
18685 Roo.data.Record.create = function(o){
18686 var f = function(){
18687 f.superclass.constructor.apply(this, arguments);
18689 Roo.extend(f, Roo.data.Record);
18690 var p = f.prototype;
18691 p.fields = new Roo.util.MixedCollection(false, function(field){
18694 for(var i = 0, len = o.length; i < len; i++){
18695 p.fields.add(new Roo.data.Field(o[i]));
18697 f.getField = function(name){
18698 return p.fields.get(name);
18703 Roo.data.Record.AUTO_ID = 1000;
18704 Roo.data.Record.EDIT = 'edit';
18705 Roo.data.Record.REJECT = 'reject';
18706 Roo.data.Record.COMMIT = 'commit';
18708 Roo.data.Record.prototype = {
18710 * Readonly flag - true if this record has been modified.
18719 join : function(store){
18720 this.store = store;
18724 * Set the named field to the specified value.
18725 * @param {String} name The name of the field to set.
18726 * @param {Object} value The value to set the field to.
18728 set : function(name, value){
18729 if(this.data[name] == value){
18733 if(!this.modified){
18734 this.modified = {};
18736 if(typeof this.modified[name] == 'undefined'){
18737 this.modified[name] = this.data[name];
18739 this.data[name] = value;
18741 this.store.afterEdit(this);
18746 * Get the value of the named field.
18747 * @param {String} name The name of the field to get the value of.
18748 * @return {Object} The value of the field.
18750 get : function(name){
18751 return this.data[name];
18755 beginEdit : function(){
18756 this.editing = true;
18757 this.modified = {};
18761 cancelEdit : function(){
18762 this.editing = false;
18763 delete this.modified;
18767 endEdit : function(){
18768 this.editing = false;
18769 if(this.dirty && this.store){
18770 this.store.afterEdit(this);
18775 * Usually called by the {@link Roo.data.Store} which owns the Record.
18776 * Rejects all changes made to the Record since either creation, or the last commit operation.
18777 * Modified fields are reverted to their original values.
18779 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18780 * of reject operations.
18782 reject : function(){
18783 var m = this.modified;
18785 if(typeof m[n] != "function"){
18786 this.data[n] = m[n];
18789 this.dirty = false;
18790 delete this.modified;
18791 this.editing = false;
18793 this.store.afterReject(this);
18798 * Usually called by the {@link Roo.data.Store} which owns the Record.
18799 * Commits all changes made to the Record since either creation, or the last commit operation.
18801 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
18802 * of commit operations.
18804 commit : function(){
18805 this.dirty = false;
18806 delete this.modified;
18807 this.editing = false;
18809 this.store.afterCommit(this);
18814 hasError : function(){
18815 return this.error != null;
18819 clearError : function(){
18824 * Creates a copy of this record.
18825 * @param {String} id (optional) A new record id if you don't want to use this record's id
18828 copy : function(newId) {
18829 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
18833 * Ext JS Library 1.1.1
18834 * Copyright(c) 2006-2007, Ext JS, LLC.
18836 * Originally Released Under LGPL - original licence link has changed is not relivant.
18839 * <script type="text/javascript">
18845 * @class Roo.data.Store
18846 * @extends Roo.util.Observable
18847 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
18848 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
18850 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
18851 * has no knowledge of the format of the data returned by the Proxy.<br>
18853 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
18854 * instances from the data object. These records are cached and made available through accessor functions.
18856 * Creates a new Store.
18857 * @param {Object} config A config object containing the objects needed for the Store to access data,
18858 * and read the data into Records.
18860 Roo.data.Store = function(config){
18861 this.data = new Roo.util.MixedCollection(false);
18862 this.data.getKey = function(o){
18865 this.baseParams = {};
18867 this.paramNames = {
18874 if(config && config.data){
18875 this.inlineData = config.data;
18876 delete config.data;
18879 Roo.apply(this, config);
18881 if(this.reader){ // reader passed
18882 this.reader = Roo.factory(this.reader, Roo.data);
18883 if(!this.recordType){
18884 this.recordType = this.reader.recordType;
18886 if(this.reader.onMetaChange){
18887 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
18891 if(this.recordType){
18892 this.fields = this.recordType.prototype.fields;
18894 this.modified = [];
18898 * @event datachanged
18899 * Fires when the data cache has changed, and a widget which is using this Store
18900 * as a Record cache should refresh its view.
18901 * @param {Store} this
18903 datachanged : true,
18905 * @event metachange
18906 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
18907 * @param {Store} this
18908 * @param {Object} meta The JSON metadata
18913 * Fires when Records have been added to the Store
18914 * @param {Store} this
18915 * @param {Roo.data.Record[]} records The array of Records added
18916 * @param {Number} index The index at which the record(s) were added
18921 * Fires when a Record has been removed from the Store
18922 * @param {Store} this
18923 * @param {Roo.data.Record} record The Record that was removed
18924 * @param {Number} index The index at which the record was removed
18929 * Fires when a Record has been updated
18930 * @param {Store} this
18931 * @param {Roo.data.Record} record The Record that was updated
18932 * @param {String} operation The update operation being performed. Value may be one of:
18934 Roo.data.Record.EDIT
18935 Roo.data.Record.REJECT
18936 Roo.data.Record.COMMIT
18942 * Fires when the data cache has been cleared.
18943 * @param {Store} this
18947 * @event beforeload
18948 * Fires before a request is made for a new data object. If the beforeload handler returns false
18949 * the load action will be canceled.
18950 * @param {Store} this
18951 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18956 * Fires after a new set of Records has been loaded.
18957 * @param {Store} this
18958 * @param {Roo.data.Record[]} records The Records that were loaded
18959 * @param {Object} options The loading options that were specified (see {@link #load} for details)
18963 * @event loadexception
18964 * Fires if an exception occurs in the Proxy during loading.
18965 * Called with the signature of the Proxy's "loadexception" event.
18966 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
18969 * @param {Object} return from JsonData.reader() - success, totalRecords, records
18970 * @param {Object} load options
18971 * @param {Object} jsonData from your request (normally this contains the Exception)
18973 loadexception : true
18977 this.proxy = Roo.factory(this.proxy, Roo.data);
18978 this.relayEvents(this.proxy, ["loadexception"]);
18980 this.sortToggle = {};
18982 Roo.data.Store.superclass.constructor.call(this);
18984 if(this.inlineData){
18985 this.loadData(this.inlineData);
18986 delete this.inlineData;
18989 Roo.extend(Roo.data.Store, Roo.util.Observable, {
18991 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
18992 * without a remote query - used by combo/forms at present.
18996 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
18999 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19002 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19003 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19006 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19007 * on any HTTP request
19010 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19013 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19014 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19016 remoteSort : false,
19019 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19020 * loaded or when a record is removed. (defaults to false).
19022 pruneModifiedRecords : false,
19025 lastOptions : null,
19028 * Add Records to the Store and fires the add event.
19029 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19031 add : function(records){
19032 records = [].concat(records);
19033 for(var i = 0, len = records.length; i < len; i++){
19034 records[i].join(this);
19036 var index = this.data.length;
19037 this.data.addAll(records);
19038 this.fireEvent("add", this, records, index);
19042 * Remove a Record from the Store and fires the remove event.
19043 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19045 remove : function(record){
19046 var index = this.data.indexOf(record);
19047 this.data.removeAt(index);
19048 if(this.pruneModifiedRecords){
19049 this.modified.remove(record);
19051 this.fireEvent("remove", this, record, index);
19055 * Remove all Records from the Store and fires the clear event.
19057 removeAll : function(){
19059 if(this.pruneModifiedRecords){
19060 this.modified = [];
19062 this.fireEvent("clear", this);
19066 * Inserts Records to the Store at the given index and fires the add event.
19067 * @param {Number} index The start index at which to insert the passed Records.
19068 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19070 insert : function(index, records){
19071 records = [].concat(records);
19072 for(var i = 0, len = records.length; i < len; i++){
19073 this.data.insert(index, records[i]);
19074 records[i].join(this);
19076 this.fireEvent("add", this, records, index);
19080 * Get the index within the cache of the passed Record.
19081 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19082 * @return {Number} The index of the passed Record. Returns -1 if not found.
19084 indexOf : function(record){
19085 return this.data.indexOf(record);
19089 * Get the index within the cache of the Record with the passed id.
19090 * @param {String} id The id of the Record to find.
19091 * @return {Number} The index of the Record. Returns -1 if not found.
19093 indexOfId : function(id){
19094 return this.data.indexOfKey(id);
19098 * Get the Record with the specified id.
19099 * @param {String} id The id of the Record to find.
19100 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19102 getById : function(id){
19103 return this.data.key(id);
19107 * Get the Record at the specified index.
19108 * @param {Number} index The index of the Record to find.
19109 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19111 getAt : function(index){
19112 return this.data.itemAt(index);
19116 * Returns a range of Records between specified indices.
19117 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19118 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19119 * @return {Roo.data.Record[]} An array of Records
19121 getRange : function(start, end){
19122 return this.data.getRange(start, end);
19126 storeOptions : function(o){
19127 o = Roo.apply({}, o);
19130 this.lastOptions = o;
19134 * Loads the Record cache from the configured Proxy using the configured Reader.
19136 * If using remote paging, then the first load call must specify the <em>start</em>
19137 * and <em>limit</em> properties in the options.params property to establish the initial
19138 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19140 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19141 * and this call will return before the new data has been loaded. Perform any post-processing
19142 * in a callback function, or in a "load" event handler.</strong>
19144 * @param {Object} options An object containing properties which control loading options:<ul>
19145 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19146 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19147 * passed the following arguments:<ul>
19148 * <li>r : Roo.data.Record[]</li>
19149 * <li>options: Options object from the load call</li>
19150 * <li>success: Boolean success indicator</li></ul></li>
19151 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19152 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19155 load : function(options){
19156 options = options || {};
19157 if(this.fireEvent("beforeload", this, options) !== false){
19158 this.storeOptions(options);
19159 var p = Roo.apply(options.params || {}, this.baseParams);
19160 if(this.sortInfo && this.remoteSort){
19161 var pn = this.paramNames;
19162 p[pn["sort"]] = this.sortInfo.field;
19163 p[pn["dir"]] = this.sortInfo.direction;
19165 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19170 * Reloads the Record cache from the configured Proxy using the configured Reader and
19171 * the options from the last load operation performed.
19172 * @param {Object} options (optional) An object containing properties which may override the options
19173 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19174 * the most recently used options are reused).
19176 reload : function(options){
19177 this.load(Roo.applyIf(options||{}, this.lastOptions));
19181 // Called as a callback by the Reader during a load operation.
19182 loadRecords : function(o, options, success){
19183 if(!o || success === false){
19184 if(success !== false){
19185 this.fireEvent("load", this, [], options);
19187 if(options.callback){
19188 options.callback.call(options.scope || this, [], options, false);
19192 // if data returned failure - throw an exception.
19193 if (o.success === false) {
19194 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19197 var r = o.records, t = o.totalRecords || r.length;
19198 if(!options || options.add !== true){
19199 if(this.pruneModifiedRecords){
19200 this.modified = [];
19202 for(var i = 0, len = r.length; i < len; i++){
19206 this.data = this.snapshot;
19207 delete this.snapshot;
19210 this.data.addAll(r);
19211 this.totalLength = t;
19213 this.fireEvent("datachanged", this);
19215 this.totalLength = Math.max(t, this.data.length+r.length);
19218 this.fireEvent("load", this, r, options);
19219 if(options.callback){
19220 options.callback.call(options.scope || this, r, options, true);
19225 * Loads data from a passed data block. A Reader which understands the format of the data
19226 * must have been configured in the constructor.
19227 * @param {Object} data The data block from which to read the Records. The format of the data expected
19228 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19229 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19231 loadData : function(o, append){
19232 var r = this.reader.readRecords(o);
19233 this.loadRecords(r, {add: append}, true);
19237 * Gets the number of cached records.
19239 * <em>If using paging, this may not be the total size of the dataset. If the data object
19240 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19241 * the data set size</em>
19243 getCount : function(){
19244 return this.data.length || 0;
19248 * Gets the total number of records in the dataset as returned by the server.
19250 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19251 * the dataset size</em>
19253 getTotalCount : function(){
19254 return this.totalLength || 0;
19258 * Returns the sort state of the Store as an object with two properties:
19260 field {String} The name of the field by which the Records are sorted
19261 direction {String} The sort order, "ASC" or "DESC"
19264 getSortState : function(){
19265 return this.sortInfo;
19269 applySort : function(){
19270 if(this.sortInfo && !this.remoteSort){
19271 var s = this.sortInfo, f = s.field;
19272 var st = this.fields.get(f).sortType;
19273 var fn = function(r1, r2){
19274 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19275 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19277 this.data.sort(s.direction, fn);
19278 if(this.snapshot && this.snapshot != this.data){
19279 this.snapshot.sort(s.direction, fn);
19285 * Sets the default sort column and order to be used by the next load operation.
19286 * @param {String} fieldName The name of the field to sort by.
19287 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19289 setDefaultSort : function(field, dir){
19290 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19294 * Sort the Records.
19295 * If remote sorting is used, the sort is performed on the server, and the cache is
19296 * reloaded. If local sorting is used, the cache is sorted internally.
19297 * @param {String} fieldName The name of the field to sort by.
19298 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19300 sort : function(fieldName, dir){
19301 var f = this.fields.get(fieldName);
19303 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
19304 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19309 this.sortToggle[f.name] = dir;
19310 this.sortInfo = {field: f.name, direction: dir};
19311 if(!this.remoteSort){
19313 this.fireEvent("datachanged", this);
19315 this.load(this.lastOptions);
19320 * Calls the specified function for each of the Records in the cache.
19321 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19322 * Returning <em>false</em> aborts and exits the iteration.
19323 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19325 each : function(fn, scope){
19326 this.data.each(fn, scope);
19330 * Gets all records modified since the last commit. Modified records are persisted across load operations
19331 * (e.g., during paging).
19332 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19334 getModifiedRecords : function(){
19335 return this.modified;
19339 createFilterFn : function(property, value, anyMatch){
19340 if(!value.exec){ // not a regex
19341 value = String(value);
19342 if(value.length == 0){
19345 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19347 return function(r){
19348 return value.test(r.data[property]);
19353 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19354 * @param {String} property A field on your records
19355 * @param {Number} start The record index to start at (defaults to 0)
19356 * @param {Number} end The last record index to include (defaults to length - 1)
19357 * @return {Number} The sum
19359 sum : function(property, start, end){
19360 var rs = this.data.items, v = 0;
19361 start = start || 0;
19362 end = (end || end === 0) ? end : rs.length-1;
19364 for(var i = start; i <= end; i++){
19365 v += (rs[i].data[property] || 0);
19371 * Filter the records by a specified property.
19372 * @param {String} field A field on your records
19373 * @param {String/RegExp} value Either a string that the field
19374 * should start with or a RegExp to test against the field
19375 * @param {Boolean} anyMatch True to match any part not just the beginning
19377 filter : function(property, value, anyMatch){
19378 var fn = this.createFilterFn(property, value, anyMatch);
19379 return fn ? this.filterBy(fn) : this.clearFilter();
19383 * Filter by a function. The specified function will be called with each
19384 * record in this data source. If the function returns true the record is included,
19385 * otherwise it is filtered.
19386 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19387 * @param {Object} scope (optional) The scope of the function (defaults to this)
19389 filterBy : function(fn, scope){
19390 this.snapshot = this.snapshot || this.data;
19391 this.data = this.queryBy(fn, scope||this);
19392 this.fireEvent("datachanged", this);
19396 * Query the records by a specified property.
19397 * @param {String} field A field on your records
19398 * @param {String/RegExp} value Either a string that the field
19399 * should start with or a RegExp to test against the field
19400 * @param {Boolean} anyMatch True to match any part not just the beginning
19401 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19403 query : function(property, value, anyMatch){
19404 var fn = this.createFilterFn(property, value, anyMatch);
19405 return fn ? this.queryBy(fn) : this.data.clone();
19409 * Query by a function. The specified function will be called with each
19410 * record in this data source. If the function returns true the record is included
19412 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19413 * @param {Object} scope (optional) The scope of the function (defaults to this)
19414 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19416 queryBy : function(fn, scope){
19417 var data = this.snapshot || this.data;
19418 return data.filterBy(fn, scope||this);
19422 * Collects unique values for a particular dataIndex from this store.
19423 * @param {String} dataIndex The property to collect
19424 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19425 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19426 * @return {Array} An array of the unique values
19428 collect : function(dataIndex, allowNull, bypassFilter){
19429 var d = (bypassFilter === true && this.snapshot) ?
19430 this.snapshot.items : this.data.items;
19431 var v, sv, r = [], l = {};
19432 for(var i = 0, len = d.length; i < len; i++){
19433 v = d[i].data[dataIndex];
19435 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19444 * Revert to a view of the Record cache with no filtering applied.
19445 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19447 clearFilter : function(suppressEvent){
19448 if(this.snapshot && this.snapshot != this.data){
19449 this.data = this.snapshot;
19450 delete this.snapshot;
19451 if(suppressEvent !== true){
19452 this.fireEvent("datachanged", this);
19458 afterEdit : function(record){
19459 if(this.modified.indexOf(record) == -1){
19460 this.modified.push(record);
19462 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19466 afterReject : function(record){
19467 this.modified.remove(record);
19468 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19472 afterCommit : function(record){
19473 this.modified.remove(record);
19474 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19478 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19479 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19481 commitChanges : function(){
19482 var m = this.modified.slice(0);
19483 this.modified = [];
19484 for(var i = 0, len = m.length; i < len; i++){
19490 * Cancel outstanding changes on all changed records.
19492 rejectChanges : function(){
19493 var m = this.modified.slice(0);
19494 this.modified = [];
19495 for(var i = 0, len = m.length; i < len; i++){
19500 onMetaChange : function(meta, rtype, o){
19501 this.recordType = rtype;
19502 this.fields = rtype.prototype.fields;
19503 delete this.snapshot;
19504 this.sortInfo = meta.sortInfo;
19505 this.modified = [];
19506 this.fireEvent('metachange', this, this.reader.meta);
19510 * Ext JS Library 1.1.1
19511 * Copyright(c) 2006-2007, Ext JS, LLC.
19513 * Originally Released Under LGPL - original licence link has changed is not relivant.
19516 * <script type="text/javascript">
19520 * @class Roo.data.SimpleStore
19521 * @extends Roo.data.Store
19522 * Small helper class to make creating Stores from Array data easier.
19523 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19524 * @cfg {Array} fields An array of field definition objects, or field name strings.
19525 * @cfg {Array} data The multi-dimensional array of data
19527 * @param {Object} config
19529 Roo.data.SimpleStore = function(config){
19530 Roo.data.SimpleStore.superclass.constructor.call(this, {
19532 reader: new Roo.data.ArrayReader({
19535 Roo.data.Record.create(config.fields)
19537 proxy : new Roo.data.MemoryProxy(config.data)
19541 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19543 * Ext JS Library 1.1.1
19544 * Copyright(c) 2006-2007, Ext JS, LLC.
19546 * Originally Released Under LGPL - original licence link has changed is not relivant.
19549 * <script type="text/javascript">
19554 * @extends Roo.data.Store
19555 * @class Roo.data.JsonStore
19556 * Small helper class to make creating Stores for JSON data easier. <br/>
19558 var store = new Roo.data.JsonStore({
19559 url: 'get-images.php',
19561 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19564 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19565 * JsonReader and HttpProxy (unless inline data is provided).</b>
19566 * @cfg {Array} fields An array of field definition objects, or field name strings.
19568 * @param {Object} config
19570 Roo.data.JsonStore = function(c){
19571 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19572 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19573 reader: new Roo.data.JsonReader(c, c.fields)
19576 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19578 * Ext JS Library 1.1.1
19579 * Copyright(c) 2006-2007, Ext JS, LLC.
19581 * Originally Released Under LGPL - original licence link has changed is not relivant.
19584 * <script type="text/javascript">
19588 Roo.data.Field = function(config){
19589 if(typeof config == "string"){
19590 config = {name: config};
19592 Roo.apply(this, config);
19595 this.type = "auto";
19598 var st = Roo.data.SortTypes;
19599 // named sortTypes are supported, here we look them up
19600 if(typeof this.sortType == "string"){
19601 this.sortType = st[this.sortType];
19604 // set default sortType for strings and dates
19605 if(!this.sortType){
19608 this.sortType = st.asUCString;
19611 this.sortType = st.asDate;
19614 this.sortType = st.none;
19619 var stripRe = /[\$,%]/g;
19621 // prebuilt conversion function for this field, instead of
19622 // switching every time we're reading a value
19624 var cv, dateFormat = this.dateFormat;
19629 cv = function(v){ return v; };
19632 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
19636 return v !== undefined && v !== null && v !== '' ?
19637 parseInt(String(v).replace(stripRe, ""), 10) : '';
19642 return v !== undefined && v !== null && v !== '' ?
19643 parseFloat(String(v).replace(stripRe, ""), 10) : '';
19648 cv = function(v){ return v === true || v === "true" || v == 1; };
19655 if(v instanceof Date){
19659 if(dateFormat == "timestamp"){
19660 return new Date(v*1000);
19662 return Date.parseDate(v, dateFormat);
19664 var parsed = Date.parse(v);
19665 return parsed ? new Date(parsed) : null;
19674 Roo.data.Field.prototype = {
19682 * Ext JS Library 1.1.1
19683 * Copyright(c) 2006-2007, Ext JS, LLC.
19685 * Originally Released Under LGPL - original licence link has changed is not relivant.
19688 * <script type="text/javascript">
19691 // Base class for reading structured data from a data source. This class is intended to be
19692 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
19695 * @class Roo.data.DataReader
19696 * Base class for reading structured data from a data source. This class is intended to be
19697 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
19700 Roo.data.DataReader = function(meta, recordType){
19704 this.recordType = recordType instanceof Array ?
19705 Roo.data.Record.create(recordType) : recordType;
19708 Roo.data.DataReader.prototype = {
19710 * Create an empty record
19711 * @param {Object} data (optional) - overlay some values
19712 * @return {Roo.data.Record} record created.
19714 newRow : function(d) {
19716 this.recordType.prototype.fields.each(function(c) {
19719 return new this.recordType(Roo.apply(da, d));
19724 * Ext JS Library 1.1.1
19725 * Copyright(c) 2006-2007, Ext JS, LLC.
19727 * Originally Released Under LGPL - original licence link has changed is not relivant.
19730 * <script type="text/javascript">
19734 * @class Roo.data.DataProxy
19735 * @extends Roo.data.Observable
19736 * This class is an abstract base class for implementations which provide retrieval of
19737 * unformatted data objects.<br>
19739 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
19740 * (of the appropriate type which knows how to parse the data object) to provide a block of
19741 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
19743 * Custom implementations must implement the load method as described in
19744 * {@link Roo.data.HttpProxy#load}.
19746 Roo.data.DataProxy = function(){
19749 * @event beforeload
19750 * Fires before a network request is made to retrieve a data object.
19751 * @param {Object} This DataProxy object.
19752 * @param {Object} params The params parameter to the load function.
19757 * Fires before the load method's callback is called.
19758 * @param {Object} This DataProxy object.
19759 * @param {Object} o The data object.
19760 * @param {Object} arg The callback argument object passed to the load function.
19764 * @event loadexception
19765 * Fires if an Exception occurs during data retrieval.
19766 * @param {Object} This DataProxy object.
19767 * @param {Object} o The data object.
19768 * @param {Object} arg The callback argument object passed to the load function.
19769 * @param {Object} e The Exception.
19771 loadexception : true
19773 Roo.data.DataProxy.superclass.constructor.call(this);
19776 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
19779 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
19783 * Ext JS Library 1.1.1
19784 * Copyright(c) 2006-2007, Ext JS, LLC.
19786 * Originally Released Under LGPL - original licence link has changed is not relivant.
19789 * <script type="text/javascript">
19792 * @class Roo.data.MemoryProxy
19793 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
19794 * to the Reader when its load method is called.
19796 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
19798 Roo.data.MemoryProxy = function(data){
19802 Roo.data.MemoryProxy.superclass.constructor.call(this);
19806 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
19808 * Load data from the requested source (in this case an in-memory
19809 * data object passed to the constructor), read the data object into
19810 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
19811 * process that block using the passed callback.
19812 * @param {Object} params This parameter is not used by the MemoryProxy class.
19813 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19814 * object into a block of Roo.data.Records.
19815 * @param {Function} callback The function into which to pass the block of Roo.data.records.
19816 * The function must be passed <ul>
19817 * <li>The Record block object</li>
19818 * <li>The "arg" argument from the load function</li>
19819 * <li>A boolean success indicator</li>
19821 * @param {Object} scope The scope in which to call the callback
19822 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19824 load : function(params, reader, callback, scope, arg){
19825 params = params || {};
19828 result = reader.readRecords(this.data);
19830 this.fireEvent("loadexception", this, arg, null, e);
19831 callback.call(scope, null, arg, false);
19834 callback.call(scope, result, arg, true);
19838 update : function(params, records){
19843 * Ext JS Library 1.1.1
19844 * Copyright(c) 2006-2007, Ext JS, LLC.
19846 * Originally Released Under LGPL - original licence link has changed is not relivant.
19849 * <script type="text/javascript">
19852 * @class Roo.data.HttpProxy
19853 * @extends Roo.data.DataProxy
19854 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
19855 * configured to reference a certain URL.<br><br>
19857 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
19858 * from which the running page was served.<br><br>
19860 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
19862 * Be aware that to enable the browser to parse an XML document, the server must set
19863 * the Content-Type header in the HTTP response to "text/xml".
19865 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
19866 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
19867 * will be used to make the request.
19869 Roo.data.HttpProxy = function(conn){
19870 Roo.data.HttpProxy.superclass.constructor.call(this);
19871 // is conn a conn config or a real conn?
19873 this.useAjax = !conn || !conn.events;
19877 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
19878 // thse are take from connection...
19881 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
19884 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
19885 * extra parameters to each request made by this object. (defaults to undefined)
19888 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
19889 * to each request made by this object. (defaults to undefined)
19892 * @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)
19895 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
19898 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
19904 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
19908 * Return the {@link Roo.data.Connection} object being used by this Proxy.
19909 * @return {Connection} The Connection object. This object may be used to subscribe to events on
19910 * a finer-grained basis than the DataProxy events.
19912 getConnection : function(){
19913 return this.useAjax ? Roo.Ajax : this.conn;
19917 * Load data from the configured {@link Roo.data.Connection}, read the data object into
19918 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
19919 * process that block using the passed callback.
19920 * @param {Object} params An object containing properties which are to be used as HTTP parameters
19921 * for the request to the remote server.
19922 * @param {Roo.data.DataReader} reader The Reader object which converts the data
19923 * object into a block of Roo.data.Records.
19924 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
19925 * The function must be passed <ul>
19926 * <li>The Record block object</li>
19927 * <li>The "arg" argument from the load function</li>
19928 * <li>A boolean success indicator</li>
19930 * @param {Object} scope The scope in which to call the callback
19931 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
19933 load : function(params, reader, callback, scope, arg){
19934 if(this.fireEvent("beforeload", this, params) !== false){
19936 params : params || {},
19938 callback : callback,
19943 callback : this.loadResponse,
19947 Roo.applyIf(o, this.conn);
19948 if(this.activeRequest){
19949 Roo.Ajax.abort(this.activeRequest);
19951 this.activeRequest = Roo.Ajax.request(o);
19953 this.conn.request(o);
19956 callback.call(scope||this, null, arg, false);
19961 loadResponse : function(o, success, response){
19962 delete this.activeRequest;
19964 this.fireEvent("loadexception", this, o, response);
19965 o.request.callback.call(o.request.scope, null, o.request.arg, false);
19970 result = o.reader.read(response);
19972 this.fireEvent("loadexception", this, o, response, e);
19973 o.request.callback.call(o.request.scope, null, o.request.arg, false);
19977 this.fireEvent("load", this, o, o.request.arg);
19978 o.request.callback.call(o.request.scope, result, o.request.arg, true);
19982 update : function(dataSet){
19987 updateResponse : function(dataSet){
19992 * Ext JS Library 1.1.1
19993 * Copyright(c) 2006-2007, Ext JS, LLC.
19995 * Originally Released Under LGPL - original licence link has changed is not relivant.
19998 * <script type="text/javascript">
20002 * @class Roo.data.ScriptTagProxy
20003 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20004 * other than the originating domain of the running page.<br><br>
20006 * <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
20007 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20009 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20010 * source code that is used as the source inside a <script> tag.<br><br>
20012 * In order for the browser to process the returned data, the server must wrap the data object
20013 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20014 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20015 * depending on whether the callback name was passed:
20018 boolean scriptTag = false;
20019 String cb = request.getParameter("callback");
20022 response.setContentType("text/javascript");
20024 response.setContentType("application/x-json");
20026 Writer out = response.getWriter();
20028 out.write(cb + "(");
20030 out.print(dataBlock.toJsonString());
20037 * @param {Object} config A configuration object.
20039 Roo.data.ScriptTagProxy = function(config){
20040 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20041 Roo.apply(this, config);
20042 this.head = document.getElementsByTagName("head")[0];
20045 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20047 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20049 * @cfg {String} url The URL from which to request the data object.
20052 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20056 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20057 * the server the name of the callback function set up by the load call to process the returned data object.
20058 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20059 * javascript output which calls this named function passing the data object as its only parameter.
20061 callbackParam : "callback",
20063 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20064 * name to the request.
20069 * Load data from the configured URL, read the data object into
20070 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20071 * process that block using the passed callback.
20072 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20073 * for the request to the remote server.
20074 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20075 * object into a block of Roo.data.Records.
20076 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20077 * The function must be passed <ul>
20078 * <li>The Record block object</li>
20079 * <li>The "arg" argument from the load function</li>
20080 * <li>A boolean success indicator</li>
20082 * @param {Object} scope The scope in which to call the callback
20083 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20085 load : function(params, reader, callback, scope, arg){
20086 if(this.fireEvent("beforeload", this, params) !== false){
20088 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20090 var url = this.url;
20091 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20093 url += "&_dc=" + (new Date().getTime());
20095 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20098 cb : "stcCallback"+transId,
20099 scriptId : "stcScript"+transId,
20103 callback : callback,
20109 window[trans.cb] = function(o){
20110 conn.handleResponse(o, trans);
20113 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20115 if(this.autoAbort !== false){
20119 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20121 var script = document.createElement("script");
20122 script.setAttribute("src", url);
20123 script.setAttribute("type", "text/javascript");
20124 script.setAttribute("id", trans.scriptId);
20125 this.head.appendChild(script);
20127 this.trans = trans;
20129 callback.call(scope||this, null, arg, false);
20134 isLoading : function(){
20135 return this.trans ? true : false;
20139 * Abort the current server request.
20141 abort : function(){
20142 if(this.isLoading()){
20143 this.destroyTrans(this.trans);
20148 destroyTrans : function(trans, isLoaded){
20149 this.head.removeChild(document.getElementById(trans.scriptId));
20150 clearTimeout(trans.timeoutId);
20152 window[trans.cb] = undefined;
20154 delete window[trans.cb];
20157 // if hasn't been loaded, wait for load to remove it to prevent script error
20158 window[trans.cb] = function(){
20159 window[trans.cb] = undefined;
20161 delete window[trans.cb];
20168 handleResponse : function(o, trans){
20169 this.trans = false;
20170 this.destroyTrans(trans, true);
20173 result = trans.reader.readRecords(o);
20175 this.fireEvent("loadexception", this, o, trans.arg, e);
20176 trans.callback.call(trans.scope||window, null, trans.arg, false);
20179 this.fireEvent("load", this, o, trans.arg);
20180 trans.callback.call(trans.scope||window, result, trans.arg, true);
20184 handleFailure : function(trans){
20185 this.trans = false;
20186 this.destroyTrans(trans, false);
20187 this.fireEvent("loadexception", this, null, trans.arg);
20188 trans.callback.call(trans.scope||window, null, trans.arg, false);
20192 * Ext JS Library 1.1.1
20193 * Copyright(c) 2006-2007, Ext JS, LLC.
20195 * Originally Released Under LGPL - original licence link has changed is not relivant.
20198 * <script type="text/javascript">
20202 * @class Roo.data.JsonReader
20203 * @extends Roo.data.DataReader
20204 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20205 * based on mappings in a provided Roo.data.Record constructor.
20209 var RecordDef = Roo.data.Record.create([
20210 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20211 {name: 'occupation'} // This field will use "occupation" as the mapping.
20213 var myReader = new Roo.data.JsonReader({
20214 totalProperty: "results", // The property which contains the total dataset size (optional)
20215 root: "rows", // The property which contains an Array of row objects
20216 id: "id" // The property within each row object that provides an ID for the record (optional)
20220 * This would consume a JSON file like this:
20222 { 'results': 2, 'rows': [
20223 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20224 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20227 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20228 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20229 * paged from the remote server.
20230 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20231 * @cfg {String} root name of the property which contains the Array of row objects.
20232 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20234 * Create a new JsonReader
20235 * @param {Object} meta Metadata configuration options
20236 * @param {Object} recordType Either an Array of field definition objects,
20237 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20239 Roo.data.JsonReader = function(meta, recordType){
20242 // set some defaults:
20243 Roo.applyIf(meta, {
20244 totalProperty: 'total',
20245 successProperty : 'success',
20250 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20252 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20254 * This method is only used by a DataProxy which has retrieved data from a remote server.
20255 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20256 * @return {Object} data A data block which is used by an Roo.data.Store object as
20257 * a cache of Roo.data.Records.
20259 read : function(response){
20260 var json = response.responseText;
20262 var o = eval("("+json+")");
20264 throw {message: "JsonReader.read: Json object not found"};
20269 this.meta = o.metaData;
20270 this.recordType = Roo.data.Record.create(o.metaData.fields);
20271 this.onMetaChange(this.meta, this.recordType, o);
20273 return this.readRecords(o);
20276 // private function a store will implement
20277 onMetaChange : function(meta, recordType, o){
20284 simpleAccess: function(obj, subsc) {
20291 getJsonAccessor: function(){
20293 return function(expr) {
20295 return(re.test(expr))
20296 ? new Function("obj", "return obj." + expr)
20301 return Roo.emptyFn;
20306 * Create a data block containing Roo.data.Records from an XML document.
20307 * @param {Object} o An object which contains an Array of row objects in the property specified
20308 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20309 * which contains the total size of the dataset.
20310 * @return {Object} data A data block which is used by an Roo.data.Store object as
20311 * a cache of Roo.data.Records.
20313 readRecords : function(o){
20315 * After any data loads, the raw JSON data is available for further custom processing.
20319 var s = this.meta, Record = this.recordType,
20320 f = Record.prototype.fields, fi = f.items, fl = f.length;
20322 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20324 if(s.totalProperty) {
20325 this.getTotal = this.getJsonAccessor(s.totalProperty);
20327 if(s.successProperty) {
20328 this.getSuccess = this.getJsonAccessor(s.successProperty);
20330 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20332 var g = this.getJsonAccessor(s.id);
20333 this.getId = function(rec) {
20335 return (r === undefined || r === "") ? null : r;
20338 this.getId = function(){return null;};
20341 for(var i = 0; i < fl; i++){
20343 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20344 this.ef[i] = this.getJsonAccessor(map);
20348 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20349 if(s.totalProperty){
20350 var v = parseInt(this.getTotal(o), 10);
20355 if(s.successProperty){
20356 var v = this.getSuccess(o);
20357 if(v === false || v === 'false'){
20362 for(var i = 0; i < c; i++){
20365 var id = this.getId(n);
20366 for(var j = 0; j < fl; j++){
20368 var v = this.ef[j](n);
20369 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20371 var record = new Record(values, id);
20373 records[i] = record;
20378 totalRecords : totalRecords
20383 * Ext JS Library 1.1.1
20384 * Copyright(c) 2006-2007, Ext JS, LLC.
20386 * Originally Released Under LGPL - original licence link has changed is not relivant.
20389 * <script type="text/javascript">
20393 * @class Roo.data.XmlReader
20394 * @extends Roo.data.DataReader
20395 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20396 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20398 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20399 * header in the HTTP response must be set to "text/xml".</em>
20403 var RecordDef = Roo.data.Record.create([
20404 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20405 {name: 'occupation'} // This field will use "occupation" as the mapping.
20407 var myReader = new Roo.data.XmlReader({
20408 totalRecords: "results", // The element which contains the total dataset size (optional)
20409 record: "row", // The repeated element which contains row information
20410 id: "id" // The element within the row that provides an ID for the record (optional)
20414 * This would consume an XML file like this:
20418 <results>2</results>
20421 <name>Bill</name>
20422 <occupation>Gardener</occupation>
20426 <name>Ben</name>
20427 <occupation>Horticulturalist</occupation>
20431 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20432 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20433 * paged from the remote server.
20434 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20435 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20436 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20437 * a record identifier value.
20439 * Create a new XmlReader
20440 * @param {Object} meta Metadata configuration options
20441 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20442 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20443 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20445 Roo.data.XmlReader = function(meta, recordType){
20447 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20449 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20451 * This method is only used by a DataProxy which has retrieved data from a remote server.
20452 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20453 * to contain a method called 'responseXML' that returns an XML document object.
20454 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20455 * a cache of Roo.data.Records.
20457 read : function(response){
20458 var doc = response.responseXML;
20460 throw {message: "XmlReader.read: XML Document not available"};
20462 return this.readRecords(doc);
20466 * Create a data block containing Roo.data.Records from an XML document.
20467 * @param {Object} doc A parsed XML document.
20468 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20469 * a cache of Roo.data.Records.
20471 readRecords : function(doc){
20473 * After any data loads/reads, the raw XML Document is available for further custom processing.
20474 * @type XMLDocument
20476 this.xmlData = doc;
20477 var root = doc.documentElement || doc;
20478 var q = Roo.DomQuery;
20479 var recordType = this.recordType, fields = recordType.prototype.fields;
20480 var sid = this.meta.id;
20481 var totalRecords = 0, success = true;
20482 if(this.meta.totalRecords){
20483 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20486 if(this.meta.success){
20487 var sv = q.selectValue(this.meta.success, root, true);
20488 success = sv !== false && sv !== 'false';
20491 var ns = q.select(this.meta.record, root);
20492 for(var i = 0, len = ns.length; i < len; i++) {
20495 var id = sid ? q.selectValue(sid, n) : undefined;
20496 for(var j = 0, jlen = fields.length; j < jlen; j++){
20497 var f = fields.items[j];
20498 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20500 values[f.name] = v;
20502 var record = new recordType(values, id);
20504 records[records.length] = record;
20510 totalRecords : totalRecords || records.length
20515 * Ext JS Library 1.1.1
20516 * Copyright(c) 2006-2007, Ext JS, LLC.
20518 * Originally Released Under LGPL - original licence link has changed is not relivant.
20521 * <script type="text/javascript">
20525 * @class Roo.data.ArrayReader
20526 * @extends Roo.data.DataReader
20527 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20528 * Each element of that Array represents a row of data fields. The
20529 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20530 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20534 var RecordDef = Roo.data.Record.create([
20535 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20536 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20538 var myReader = new Roo.data.ArrayReader({
20539 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20543 * This would consume an Array like this:
20545 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20547 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20549 * Create a new JsonReader
20550 * @param {Object} meta Metadata configuration options.
20551 * @param {Object} recordType Either an Array of field definition objects
20552 * as specified to {@link Roo.data.Record#create},
20553 * or an {@link Roo.data.Record} object
20554 * created using {@link Roo.data.Record#create}.
20556 Roo.data.ArrayReader = function(meta, recordType){
20557 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20560 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20562 * Create a data block containing Roo.data.Records from an XML document.
20563 * @param {Object} o An Array of row objects which represents the dataset.
20564 * @return {Object} data A data block which is used by an Roo.data.Store object as
20565 * a cache of Roo.data.Records.
20567 readRecords : function(o){
20568 var sid = this.meta ? this.meta.id : null;
20569 var recordType = this.recordType, fields = recordType.prototype.fields;
20572 for(var i = 0; i < root.length; i++){
20575 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20576 for(var j = 0, jlen = fields.length; j < jlen; j++){
20577 var f = fields.items[j];
20578 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20579 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20581 values[f.name] = v;
20583 var record = new recordType(values, id);
20585 records[records.length] = record;
20589 totalRecords : records.length
20594 * Ext JS Library 1.1.1
20595 * Copyright(c) 2006-2007, Ext JS, LLC.
20597 * Originally Released Under LGPL - original licence link has changed is not relivant.
20600 * <script type="text/javascript">
20605 * @class Roo.data.Tree
20606 * @extends Roo.util.Observable
20607 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
20608 * in the tree have most standard DOM functionality.
20610 * @param {Node} root (optional) The root node
20612 Roo.data.Tree = function(root){
20613 this.nodeHash = {};
20615 * The root node for this tree
20620 this.setRootNode(root);
20625 * Fires when a new child node is appended to a node in this tree.
20626 * @param {Tree} tree The owner tree
20627 * @param {Node} parent The parent node
20628 * @param {Node} node The newly appended node
20629 * @param {Number} index The index of the newly appended node
20634 * Fires when a child node is removed from a node in this tree.
20635 * @param {Tree} tree The owner tree
20636 * @param {Node} parent The parent node
20637 * @param {Node} node The child node removed
20642 * Fires when a node is moved to a new location in the tree
20643 * @param {Tree} tree The owner tree
20644 * @param {Node} node The node moved
20645 * @param {Node} oldParent The old parent of this node
20646 * @param {Node} newParent The new parent of this node
20647 * @param {Number} index The index it was moved to
20652 * Fires when a new child node is inserted in a node in this tree.
20653 * @param {Tree} tree The owner tree
20654 * @param {Node} parent The parent node
20655 * @param {Node} node The child node inserted
20656 * @param {Node} refNode The child node the node was inserted before
20660 * @event beforeappend
20661 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
20662 * @param {Tree} tree The owner tree
20663 * @param {Node} parent The parent node
20664 * @param {Node} node The child node to be appended
20666 "beforeappend" : true,
20668 * @event beforeremove
20669 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
20670 * @param {Tree} tree The owner tree
20671 * @param {Node} parent The parent node
20672 * @param {Node} node The child node to be removed
20674 "beforeremove" : true,
20676 * @event beforemove
20677 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
20678 * @param {Tree} tree The owner tree
20679 * @param {Node} node The node being moved
20680 * @param {Node} oldParent The parent of the node
20681 * @param {Node} newParent The new parent the node is moving to
20682 * @param {Number} index The index it is being moved to
20684 "beforemove" : true,
20686 * @event beforeinsert
20687 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
20688 * @param {Tree} tree The owner tree
20689 * @param {Node} parent The parent node
20690 * @param {Node} node The child node to be inserted
20691 * @param {Node} refNode The child node the node is being inserted before
20693 "beforeinsert" : true
20696 Roo.data.Tree.superclass.constructor.call(this);
20699 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
20700 pathSeparator: "/",
20702 proxyNodeEvent : function(){
20703 return this.fireEvent.apply(this, arguments);
20707 * Returns the root node for this tree.
20710 getRootNode : function(){
20715 * Sets the root node for this tree.
20716 * @param {Node} node
20719 setRootNode : function(node){
20721 node.ownerTree = this;
20722 node.isRoot = true;
20723 this.registerNode(node);
20728 * Gets a node in this tree by its id.
20729 * @param {String} id
20732 getNodeById : function(id){
20733 return this.nodeHash[id];
20736 registerNode : function(node){
20737 this.nodeHash[node.id] = node;
20740 unregisterNode : function(node){
20741 delete this.nodeHash[node.id];
20744 toString : function(){
20745 return "[Tree"+(this.id?" "+this.id:"")+"]";
20750 * @class Roo.data.Node
20751 * @extends Roo.util.Observable
20752 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
20753 * @cfg {String} id The id for this node. If one is not specified, one is generated.
20755 * @param {Object} attributes The attributes/config for the node
20757 Roo.data.Node = function(attributes){
20759 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
20762 this.attributes = attributes || {};
20763 this.leaf = this.attributes.leaf;
20765 * The node id. @type String
20767 this.id = this.attributes.id;
20769 this.id = Roo.id(null, "ynode-");
20770 this.attributes.id = this.id;
20773 * All child nodes of this node. @type Array
20775 this.childNodes = [];
20776 if(!this.childNodes.indexOf){ // indexOf is a must
20777 this.childNodes.indexOf = function(o){
20778 for(var i = 0, len = this.length; i < len; i++){
20779 if(this[i] == o) return i;
20785 * The parent node for this node. @type Node
20787 this.parentNode = null;
20789 * The first direct child node of this node, or null if this node has no child nodes. @type Node
20791 this.firstChild = null;
20793 * The last direct child node of this node, or null if this node has no child nodes. @type Node
20795 this.lastChild = null;
20797 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
20799 this.previousSibling = null;
20801 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
20803 this.nextSibling = null;
20808 * Fires when a new child node is appended
20809 * @param {Tree} tree The owner tree
20810 * @param {Node} this This node
20811 * @param {Node} node The newly appended node
20812 * @param {Number} index The index of the newly appended node
20817 * Fires when a child node is removed
20818 * @param {Tree} tree The owner tree
20819 * @param {Node} this This node
20820 * @param {Node} node The removed node
20825 * Fires when this node is moved to a new location in the tree
20826 * @param {Tree} tree The owner tree
20827 * @param {Node} this This node
20828 * @param {Node} oldParent The old parent of this node
20829 * @param {Node} newParent The new parent of this node
20830 * @param {Number} index The index it was moved to
20835 * Fires when a new child node is inserted.
20836 * @param {Tree} tree The owner tree
20837 * @param {Node} this This node
20838 * @param {Node} node The child node inserted
20839 * @param {Node} refNode The child node the node was inserted before
20843 * @event beforeappend
20844 * Fires before a new child is appended, return false to cancel the append.
20845 * @param {Tree} tree The owner tree
20846 * @param {Node} this This node
20847 * @param {Node} node The child node to be appended
20849 "beforeappend" : true,
20851 * @event beforeremove
20852 * Fires before a child is removed, return false to cancel the remove.
20853 * @param {Tree} tree The owner tree
20854 * @param {Node} this This node
20855 * @param {Node} node The child node to be removed
20857 "beforeremove" : true,
20859 * @event beforemove
20860 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
20861 * @param {Tree} tree The owner tree
20862 * @param {Node} this This node
20863 * @param {Node} oldParent The parent of this node
20864 * @param {Node} newParent The new parent this node is moving to
20865 * @param {Number} index The index it is being moved to
20867 "beforemove" : true,
20869 * @event beforeinsert
20870 * Fires before a new child is inserted, return false to cancel the insert.
20871 * @param {Tree} tree The owner tree
20872 * @param {Node} this This node
20873 * @param {Node} node The child node to be inserted
20874 * @param {Node} refNode The child node the node is being inserted before
20876 "beforeinsert" : true
20878 this.listeners = this.attributes.listeners;
20879 Roo.data.Node.superclass.constructor.call(this);
20882 Roo.extend(Roo.data.Node, Roo.util.Observable, {
20883 fireEvent : function(evtName){
20884 // first do standard event for this node
20885 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
20888 // then bubble it up to the tree if the event wasn't cancelled
20889 var ot = this.getOwnerTree();
20891 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
20899 * Returns true if this node is a leaf
20900 * @return {Boolean}
20902 isLeaf : function(){
20903 return this.leaf === true;
20907 setFirstChild : function(node){
20908 this.firstChild = node;
20912 setLastChild : function(node){
20913 this.lastChild = node;
20918 * Returns true if this node is the last child of its parent
20919 * @return {Boolean}
20921 isLast : function(){
20922 return (!this.parentNode ? true : this.parentNode.lastChild == this);
20926 * Returns true if this node is the first child of its parent
20927 * @return {Boolean}
20929 isFirst : function(){
20930 return (!this.parentNode ? true : this.parentNode.firstChild == this);
20933 hasChildNodes : function(){
20934 return !this.isLeaf() && this.childNodes.length > 0;
20938 * Insert node(s) as the last child node of this node.
20939 * @param {Node/Array} node The node or Array of nodes to append
20940 * @return {Node} The appended node if single append, or null if an array was passed
20942 appendChild : function(node){
20944 if(node instanceof Array){
20946 }else if(arguments.length > 1){
20949 // if passed an array or multiple args do them one by one
20951 for(var i = 0, len = multi.length; i < len; i++) {
20952 this.appendChild(multi[i]);
20955 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
20958 var index = this.childNodes.length;
20959 var oldParent = node.parentNode;
20960 // it's a move, make sure we move it cleanly
20962 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
20965 oldParent.removeChild(node);
20967 index = this.childNodes.length;
20969 this.setFirstChild(node);
20971 this.childNodes.push(node);
20972 node.parentNode = this;
20973 var ps = this.childNodes[index-1];
20975 node.previousSibling = ps;
20976 ps.nextSibling = node;
20978 node.previousSibling = null;
20980 node.nextSibling = null;
20981 this.setLastChild(node);
20982 node.setOwnerTree(this.getOwnerTree());
20983 this.fireEvent("append", this.ownerTree, this, node, index);
20985 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
20992 * Removes a child node from this node.
20993 * @param {Node} node The node to remove
20994 * @return {Node} The removed node
20996 removeChild : function(node){
20997 var index = this.childNodes.indexOf(node);
21001 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21005 // remove it from childNodes collection
21006 this.childNodes.splice(index, 1);
21009 if(node.previousSibling){
21010 node.previousSibling.nextSibling = node.nextSibling;
21012 if(node.nextSibling){
21013 node.nextSibling.previousSibling = node.previousSibling;
21016 // update child refs
21017 if(this.firstChild == node){
21018 this.setFirstChild(node.nextSibling);
21020 if(this.lastChild == node){
21021 this.setLastChild(node.previousSibling);
21024 node.setOwnerTree(null);
21025 // clear any references from the node
21026 node.parentNode = null;
21027 node.previousSibling = null;
21028 node.nextSibling = null;
21029 this.fireEvent("remove", this.ownerTree, this, node);
21034 * Inserts the first node before the second node in this nodes childNodes collection.
21035 * @param {Node} node The node to insert
21036 * @param {Node} refNode The node to insert before (if null the node is appended)
21037 * @return {Node} The inserted node
21039 insertBefore : function(node, refNode){
21040 if(!refNode){ // like standard Dom, refNode can be null for append
21041 return this.appendChild(node);
21044 if(node == refNode){
21048 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21051 var index = this.childNodes.indexOf(refNode);
21052 var oldParent = node.parentNode;
21053 var refIndex = index;
21055 // when moving internally, indexes will change after remove
21056 if(oldParent == this && this.childNodes.indexOf(node) < index){
21060 // it's a move, make sure we move it cleanly
21062 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21065 oldParent.removeChild(node);
21068 this.setFirstChild(node);
21070 this.childNodes.splice(refIndex, 0, node);
21071 node.parentNode = this;
21072 var ps = this.childNodes[refIndex-1];
21074 node.previousSibling = ps;
21075 ps.nextSibling = node;
21077 node.previousSibling = null;
21079 node.nextSibling = refNode;
21080 refNode.previousSibling = node;
21081 node.setOwnerTree(this.getOwnerTree());
21082 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21084 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21090 * Returns the child node at the specified index.
21091 * @param {Number} index
21094 item : function(index){
21095 return this.childNodes[index];
21099 * Replaces one child node in this node with another.
21100 * @param {Node} newChild The replacement node
21101 * @param {Node} oldChild The node to replace
21102 * @return {Node} The replaced node
21104 replaceChild : function(newChild, oldChild){
21105 this.insertBefore(newChild, oldChild);
21106 this.removeChild(oldChild);
21111 * Returns the index of a child node
21112 * @param {Node} node
21113 * @return {Number} The index of the node or -1 if it was not found
21115 indexOf : function(child){
21116 return this.childNodes.indexOf(child);
21120 * Returns the tree this node is in.
21123 getOwnerTree : function(){
21124 // if it doesn't have one, look for one
21125 if(!this.ownerTree){
21129 this.ownerTree = p.ownerTree;
21135 return this.ownerTree;
21139 * Returns depth of this node (the root node has a depth of 0)
21142 getDepth : function(){
21145 while(p.parentNode){
21153 setOwnerTree : function(tree){
21154 // if it's move, we need to update everyone
21155 if(tree != this.ownerTree){
21156 if(this.ownerTree){
21157 this.ownerTree.unregisterNode(this);
21159 this.ownerTree = tree;
21160 var cs = this.childNodes;
21161 for(var i = 0, len = cs.length; i < len; i++) {
21162 cs[i].setOwnerTree(tree);
21165 tree.registerNode(this);
21171 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21172 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21173 * @return {String} The path
21175 getPath : function(attr){
21176 attr = attr || "id";
21177 var p = this.parentNode;
21178 var b = [this.attributes[attr]];
21180 b.unshift(p.attributes[attr]);
21183 var sep = this.getOwnerTree().pathSeparator;
21184 return sep + b.join(sep);
21188 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21189 * function call will be the scope provided or the current node. The arguments to the function
21190 * will be the args provided or the current node. If the function returns false at any point,
21191 * the bubble is stopped.
21192 * @param {Function} fn The function to call
21193 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21194 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21196 bubble : function(fn, scope, args){
21199 if(fn.call(scope || p, args || p) === false){
21207 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21208 * function call will be the scope provided or the current node. The arguments to the function
21209 * will be the args provided or the current node. If the function returns false at any point,
21210 * the cascade is stopped on that branch.
21211 * @param {Function} fn The function to call
21212 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21213 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21215 cascade : function(fn, scope, args){
21216 if(fn.call(scope || this, args || this) !== false){
21217 var cs = this.childNodes;
21218 for(var i = 0, len = cs.length; i < len; i++) {
21219 cs[i].cascade(fn, scope, args);
21225 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21226 * function call will be the scope provided or the current node. The arguments to the function
21227 * will be the args provided or the current node. If the function returns false at any point,
21228 * the iteration stops.
21229 * @param {Function} fn The function to call
21230 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21231 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21233 eachChild : function(fn, scope, args){
21234 var cs = this.childNodes;
21235 for(var i = 0, len = cs.length; i < len; i++) {
21236 if(fn.call(scope || this, args || cs[i]) === false){
21243 * Finds the first child that has the attribute with the specified value.
21244 * @param {String} attribute The attribute name
21245 * @param {Mixed} value The value to search for
21246 * @return {Node} The found child or null if none was found
21248 findChild : function(attribute, value){
21249 var cs = this.childNodes;
21250 for(var i = 0, len = cs.length; i < len; i++) {
21251 if(cs[i].attributes[attribute] == value){
21259 * Finds the first child by a custom function. The child matches if the function passed
21261 * @param {Function} fn
21262 * @param {Object} scope (optional)
21263 * @return {Node} The found child or null if none was found
21265 findChildBy : function(fn, scope){
21266 var cs = this.childNodes;
21267 for(var i = 0, len = cs.length; i < len; i++) {
21268 if(fn.call(scope||cs[i], cs[i]) === true){
21276 * Sorts this nodes children using the supplied sort function
21277 * @param {Function} fn
21278 * @param {Object} scope (optional)
21280 sort : function(fn, scope){
21281 var cs = this.childNodes;
21282 var len = cs.length;
21284 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21286 for(var i = 0; i < len; i++){
21288 n.previousSibling = cs[i-1];
21289 n.nextSibling = cs[i+1];
21291 this.setFirstChild(n);
21294 this.setLastChild(n);
21301 * Returns true if this node is an ancestor (at any point) of the passed node.
21302 * @param {Node} node
21303 * @return {Boolean}
21305 contains : function(node){
21306 return node.isAncestor(this);
21310 * Returns true if the passed node is an ancestor (at any point) of this node.
21311 * @param {Node} node
21312 * @return {Boolean}
21314 isAncestor : function(node){
21315 var p = this.parentNode;
21325 toString : function(){
21326 return "[Node"+(this.id?" "+this.id:"")+"]";
21330 * Ext JS Library 1.1.1
21331 * Copyright(c) 2006-2007, Ext JS, LLC.
21333 * Originally Released Under LGPL - original licence link has changed is not relivant.
21336 * <script type="text/javascript">
21341 * @class Roo.ComponentMgr
21342 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21345 Roo.ComponentMgr = function(){
21346 var all = new Roo.util.MixedCollection();
21350 * Registers a component.
21351 * @param {Roo.Component} c The component
21353 register : function(c){
21358 * Unregisters a component.
21359 * @param {Roo.Component} c The component
21361 unregister : function(c){
21366 * Returns a component by id
21367 * @param {String} id The component id
21369 get : function(id){
21370 return all.get(id);
21374 * Registers a function that will be called when a specified component is added to ComponentMgr
21375 * @param {String} id The component id
21376 * @param {Funtction} fn The callback function
21377 * @param {Object} scope The scope of the callback
21379 onAvailable : function(id, fn, scope){
21380 all.on("add", function(index, o){
21382 fn.call(scope || o, o);
21383 all.un("add", fn, scope);
21390 * Ext JS Library 1.1.1
21391 * Copyright(c) 2006-2007, Ext JS, LLC.
21393 * Originally Released Under LGPL - original licence link has changed is not relivant.
21396 * <script type="text/javascript">
21400 * @class Roo.Component
21401 * @extends Roo.util.Observable
21402 * Base class for all major Ext components. All subclasses of Component can automatically participate in the standard
21403 * Ext component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21404 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21405 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21406 * All visual components (widgets) that require rendering into a layout should subclass Component.
21408 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21409 * 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
21410 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21412 Roo.Component = function(config){
21413 config = config || {};
21414 if(config.tagName || config.dom || typeof config == "string"){ // element object
21415 config = {el: config, id: config.id || config};
21417 this.initialConfig = config;
21419 Roo.apply(this, config);
21423 * Fires after the component is disabled.
21424 * @param {Roo.Component} this
21429 * Fires after the component is enabled.
21430 * @param {Roo.Component} this
21434 * @event beforeshow
21435 * Fires before the component is shown. Return false to stop the show.
21436 * @param {Roo.Component} this
21441 * Fires after the component is shown.
21442 * @param {Roo.Component} this
21446 * @event beforehide
21447 * Fires before the component is hidden. Return false to stop the hide.
21448 * @param {Roo.Component} this
21453 * Fires after the component is hidden.
21454 * @param {Roo.Component} this
21458 * @event beforerender
21459 * Fires before the component is rendered. Return false to stop the render.
21460 * @param {Roo.Component} this
21462 beforerender : true,
21465 * Fires after the component is rendered.
21466 * @param {Roo.Component} this
21470 * @event beforedestroy
21471 * Fires before the component is destroyed. Return false to stop the destroy.
21472 * @param {Roo.Component} this
21474 beforedestroy : true,
21477 * Fires after the component is destroyed.
21478 * @param {Roo.Component} this
21483 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21485 Roo.ComponentMgr.register(this);
21486 Roo.Component.superclass.constructor.call(this);
21487 this.initComponent();
21488 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21489 this.render(this.renderTo);
21490 delete this.renderTo;
21495 Roo.Component.AUTO_ID = 1000;
21497 Roo.extend(Roo.Component, Roo.util.Observable, {
21499 * @property {Boolean} hidden
21500 * true if this component is hidden. Read-only.
21504 * true if this component is disabled. Read-only.
21508 * true if this component has been rendered. Read-only.
21512 /** @cfg {String} disableClass
21513 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21515 disabledClass : "x-item-disabled",
21516 /** @cfg {Boolean} allowDomMove
21517 * Whether the component can move the Dom node when rendering (defaults to true).
21519 allowDomMove : true,
21520 /** @cfg {String} hideMode
21521 * How this component should hidden. Supported values are
21522 * "visibility" (css visibility), "offsets" (negative offset position) and
21523 * "display" (css display) - defaults to "display".
21525 hideMode: 'display',
21528 ctype : "Roo.Component",
21530 /** @cfg {String} actionMode
21531 * which property holds the element that used for hide() / show() / disable() / enable()
21537 getActionEl : function(){
21538 return this[this.actionMode];
21541 initComponent : Roo.emptyFn,
21543 * If this is a lazy rendering component, render it to its container element.
21544 * @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.
21546 render : function(container, position){
21547 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21548 if(!container && this.el){
21549 this.el = Roo.get(this.el);
21550 container = this.el.dom.parentNode;
21551 this.allowDomMove = false;
21553 this.container = Roo.get(container);
21554 this.rendered = true;
21555 if(position !== undefined){
21556 if(typeof position == 'number'){
21557 position = this.container.dom.childNodes[position];
21559 position = Roo.getDom(position);
21562 this.onRender(this.container, position || null);
21564 this.el.addClass(this.cls);
21568 this.el.applyStyles(this.style);
21571 this.fireEvent("render", this);
21572 this.afterRender(this.container);
21584 // default function is not really useful
21585 onRender : function(ct, position){
21587 this.el = Roo.get(this.el);
21588 if(this.allowDomMove !== false){
21589 ct.dom.insertBefore(this.el.dom, position);
21595 getAutoCreate : function(){
21596 var cfg = typeof this.autoCreate == "object" ?
21597 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
21598 if(this.id && !cfg.id){
21605 afterRender : Roo.emptyFn,
21608 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
21609 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
21611 destroy : function(){
21612 if(this.fireEvent("beforedestroy", this) !== false){
21613 this.purgeListeners();
21614 this.beforeDestroy();
21616 this.el.removeAllListeners();
21618 if(this.actionMode == "container"){
21619 this.container.remove();
21623 Roo.ComponentMgr.unregister(this);
21624 this.fireEvent("destroy", this);
21629 beforeDestroy : function(){
21634 onDestroy : function(){
21639 * Returns the underlying {@link Roo.Element}.
21640 * @return {Roo.Element} The element
21642 getEl : function(){
21647 * Returns the id of this component.
21650 getId : function(){
21655 * Try to focus this component.
21656 * @param {Boolean} selectText True to also select the text in this component (if applicable)
21657 * @return {Roo.Component} this
21659 focus : function(selectText){
21662 if(selectText === true){
21663 this.el.dom.select();
21678 * Disable this component.
21679 * @return {Roo.Component} this
21681 disable : function(){
21685 this.disabled = true;
21686 this.fireEvent("disable", this);
21691 onDisable : function(){
21692 this.getActionEl().addClass(this.disabledClass);
21693 this.el.dom.disabled = true;
21697 * Enable this component.
21698 * @return {Roo.Component} this
21700 enable : function(){
21704 this.disabled = false;
21705 this.fireEvent("enable", this);
21710 onEnable : function(){
21711 this.getActionEl().removeClass(this.disabledClass);
21712 this.el.dom.disabled = false;
21716 * Convenience function for setting disabled/enabled by boolean.
21717 * @param {Boolean} disabled
21719 setDisabled : function(disabled){
21720 this[disabled ? "disable" : "enable"]();
21724 * Show this component.
21725 * @return {Roo.Component} this
21728 if(this.fireEvent("beforeshow", this) !== false){
21729 this.hidden = false;
21733 this.fireEvent("show", this);
21739 onShow : function(){
21740 var ae = this.getActionEl();
21741 if(this.hideMode == 'visibility'){
21742 ae.dom.style.visibility = "visible";
21743 }else if(this.hideMode == 'offsets'){
21744 ae.removeClass('x-hidden');
21746 ae.dom.style.display = "";
21751 * Hide this component.
21752 * @return {Roo.Component} this
21755 if(this.fireEvent("beforehide", this) !== false){
21756 this.hidden = true;
21760 this.fireEvent("hide", this);
21766 onHide : function(){
21767 var ae = this.getActionEl();
21768 if(this.hideMode == 'visibility'){
21769 ae.dom.style.visibility = "hidden";
21770 }else if(this.hideMode == 'offsets'){
21771 ae.addClass('x-hidden');
21773 ae.dom.style.display = "none";
21778 * Convenience function to hide or show this component by boolean.
21779 * @param {Boolean} visible True to show, false to hide
21780 * @return {Roo.Component} this
21782 setVisible: function(visible){
21792 * Returns true if this component is visible.
21794 isVisible : function(){
21795 return this.getActionEl().isVisible();
21798 cloneConfig : function(overrides){
21799 overrides = overrides || {};
21800 var id = overrides.id || Roo.id();
21801 var cfg = Roo.applyIf(overrides, this.initialConfig);
21802 cfg.id = id; // prevent dup id
21803 return new this.constructor(cfg);
21807 * Ext JS Library 1.1.1
21808 * Copyright(c) 2006-2007, Ext JS, LLC.
21810 * Originally Released Under LGPL - original licence link has changed is not relivant.
21813 * <script type="text/javascript">
21818 * @extends Roo.Element
21819 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
21820 * automatic maintaining of shadow/shim positions.
21821 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
21822 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
21823 * you can pass a string with a CSS class name. False turns off the shadow.
21824 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
21825 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
21826 * @cfg {String} cls CSS class to add to the element
21827 * @cfg {Number} zindex Starting z-index (defaults to 11000)
21828 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
21830 * @param {Object} config An object with config options.
21831 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
21834 Roo.Layer = function(config, existingEl){
21835 config = config || {};
21836 var dh = Roo.DomHelper;
21837 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
21839 this.dom = Roo.getDom(existingEl);
21842 var o = config.dh || {tag: "div", cls: "x-layer"};
21843 this.dom = dh.append(pel, o);
21846 this.addClass(config.cls);
21848 this.constrain = config.constrain !== false;
21849 this.visibilityMode = Roo.Element.VISIBILITY;
21851 this.id = this.dom.id = config.id;
21853 this.id = Roo.id(this.dom);
21855 this.zindex = config.zindex || this.getZIndex();
21856 this.position("absolute", this.zindex);
21858 this.shadowOffset = config.shadowOffset || 4;
21859 this.shadow = new Roo.Shadow({
21860 offset : this.shadowOffset,
21861 mode : config.shadow
21864 this.shadowOffset = 0;
21866 this.useShim = config.shim !== false && Roo.useShims;
21867 this.useDisplay = config.useDisplay;
21871 var supr = Roo.Element.prototype;
21873 // shims are shared among layer to keep from having 100 iframes
21876 Roo.extend(Roo.Layer, Roo.Element, {
21878 getZIndex : function(){
21879 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
21882 getShim : function(){
21889 var shim = shims.shift();
21891 shim = this.createShim();
21892 shim.enableDisplayMode('block');
21893 shim.dom.style.display = 'none';
21894 shim.dom.style.visibility = 'visible';
21896 var pn = this.dom.parentNode;
21897 if(shim.dom.parentNode != pn){
21898 pn.insertBefore(shim.dom, this.dom);
21900 shim.setStyle('z-index', this.getZIndex()-2);
21905 hideShim : function(){
21907 this.shim.setDisplayed(false);
21908 shims.push(this.shim);
21913 disableShadow : function(){
21915 this.shadowDisabled = true;
21916 this.shadow.hide();
21917 this.lastShadowOffset = this.shadowOffset;
21918 this.shadowOffset = 0;
21922 enableShadow : function(show){
21924 this.shadowDisabled = false;
21925 this.shadowOffset = this.lastShadowOffset;
21926 delete this.lastShadowOffset;
21934 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
21935 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
21936 sync : function(doShow){
21937 var sw = this.shadow;
21938 if(!this.updating && this.isVisible() && (sw || this.useShim)){
21939 var sh = this.getShim();
21941 var w = this.getWidth(),
21942 h = this.getHeight();
21944 var l = this.getLeft(true),
21945 t = this.getTop(true);
21947 if(sw && !this.shadowDisabled){
21948 if(doShow && !sw.isVisible()){
21951 sw.realign(l, t, w, h);
21957 // fit the shim behind the shadow, so it is shimmed too
21958 var a = sw.adjusts, s = sh.dom.style;
21959 s.left = (Math.min(l, l+a.l))+"px";
21960 s.top = (Math.min(t, t+a.t))+"px";
21961 s.width = (w+a.w)+"px";
21962 s.height = (h+a.h)+"px";
21969 sh.setLeftTop(l, t);
21976 destroy : function(){
21979 this.shadow.hide();
21981 this.removeAllListeners();
21982 var pn = this.dom.parentNode;
21984 pn.removeChild(this.dom);
21986 Roo.Element.uncache(this.id);
21989 remove : function(){
21994 beginUpdate : function(){
21995 this.updating = true;
21999 endUpdate : function(){
22000 this.updating = false;
22005 hideUnders : function(negOffset){
22007 this.shadow.hide();
22013 constrainXY : function(){
22014 if(this.constrain){
22015 var vw = Roo.lib.Dom.getViewWidth(),
22016 vh = Roo.lib.Dom.getViewHeight();
22017 var s = Roo.get(document).getScroll();
22019 var xy = this.getXY();
22020 var x = xy[0], y = xy[1];
22021 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22022 // only move it if it needs it
22024 // first validate right/bottom
22025 if((x + w) > vw+s.left){
22026 x = vw - w - this.shadowOffset;
22029 if((y + h) > vh+s.top){
22030 y = vh - h - this.shadowOffset;
22033 // then make sure top/left isn't negative
22044 var ay = this.avoidY;
22045 if(y <= ay && (y+h) >= ay){
22051 supr.setXY.call(this, xy);
22057 isVisible : function(){
22058 return this.visible;
22062 showAction : function(){
22063 this.visible = true; // track visibility to prevent getStyle calls
22064 if(this.useDisplay === true){
22065 this.setDisplayed("");
22066 }else if(this.lastXY){
22067 supr.setXY.call(this, this.lastXY);
22068 }else if(this.lastLT){
22069 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22074 hideAction : function(){
22075 this.visible = false;
22076 if(this.useDisplay === true){
22077 this.setDisplayed(false);
22079 this.setLeftTop(-10000,-10000);
22083 // overridden Element method
22084 setVisible : function(v, a, d, c, e){
22089 var cb = function(){
22094 }.createDelegate(this);
22095 supr.setVisible.call(this, true, true, d, cb, e);
22098 this.hideUnders(true);
22107 }.createDelegate(this);
22109 supr.setVisible.call(this, v, a, d, cb, e);
22118 storeXY : function(xy){
22119 delete this.lastLT;
22123 storeLeftTop : function(left, top){
22124 delete this.lastXY;
22125 this.lastLT = [left, top];
22129 beforeFx : function(){
22130 this.beforeAction();
22131 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22135 afterFx : function(){
22136 Roo.Layer.superclass.afterFx.apply(this, arguments);
22137 this.sync(this.isVisible());
22141 beforeAction : function(){
22142 if(!this.updating && this.shadow){
22143 this.shadow.hide();
22147 // overridden Element method
22148 setLeft : function(left){
22149 this.storeLeftTop(left, this.getTop(true));
22150 supr.setLeft.apply(this, arguments);
22154 setTop : function(top){
22155 this.storeLeftTop(this.getLeft(true), top);
22156 supr.setTop.apply(this, arguments);
22160 setLeftTop : function(left, top){
22161 this.storeLeftTop(left, top);
22162 supr.setLeftTop.apply(this, arguments);
22166 setXY : function(xy, a, d, c, e){
22168 this.beforeAction();
22170 var cb = this.createCB(c);
22171 supr.setXY.call(this, xy, a, d, cb, e);
22178 createCB : function(c){
22189 // overridden Element method
22190 setX : function(x, a, d, c, e){
22191 this.setXY([x, this.getY()], a, d, c, e);
22194 // overridden Element method
22195 setY : function(y, a, d, c, e){
22196 this.setXY([this.getX(), y], a, d, c, e);
22199 // overridden Element method
22200 setSize : function(w, h, a, d, c, e){
22201 this.beforeAction();
22202 var cb = this.createCB(c);
22203 supr.setSize.call(this, w, h, a, d, cb, e);
22209 // overridden Element method
22210 setWidth : function(w, a, d, c, e){
22211 this.beforeAction();
22212 var cb = this.createCB(c);
22213 supr.setWidth.call(this, w, a, d, cb, e);
22219 // overridden Element method
22220 setHeight : function(h, a, d, c, e){
22221 this.beforeAction();
22222 var cb = this.createCB(c);
22223 supr.setHeight.call(this, h, a, d, cb, e);
22229 // overridden Element method
22230 setBounds : function(x, y, w, h, a, d, c, e){
22231 this.beforeAction();
22232 var cb = this.createCB(c);
22234 this.storeXY([x, y]);
22235 supr.setXY.call(this, [x, y]);
22236 supr.setSize.call(this, w, h, a, d, cb, e);
22239 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22245 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22246 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22247 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22248 * @param {Number} zindex The new z-index to set
22249 * @return {this} The Layer
22251 setZIndex : function(zindex){
22252 this.zindex = zindex;
22253 this.setStyle("z-index", zindex + 2);
22255 this.shadow.setZIndex(zindex + 1);
22258 this.shim.setStyle("z-index", zindex);
22264 * Ext JS Library 1.1.1
22265 * Copyright(c) 2006-2007, Ext JS, LLC.
22267 * Originally Released Under LGPL - original licence link has changed is not relivant.
22270 * <script type="text/javascript">
22275 * @class Roo.Shadow
22276 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22277 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22278 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22280 * Create a new Shadow
22281 * @param {Object} config The config object
22283 Roo.Shadow = function(config){
22284 Roo.apply(this, config);
22285 if(typeof this.mode != "string"){
22286 this.mode = this.defaultMode;
22288 var o = this.offset, a = {h: 0};
22289 var rad = Math.floor(this.offset/2);
22290 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22296 a.l -= this.offset + rad;
22297 a.t -= this.offset + rad;
22308 a.l -= (this.offset - rad);
22309 a.t -= this.offset + rad;
22311 a.w -= (this.offset - rad)*2;
22322 a.l -= (this.offset - rad);
22323 a.t -= (this.offset - rad);
22325 a.w -= (this.offset + rad + 1);
22326 a.h -= (this.offset + rad);
22335 Roo.Shadow.prototype = {
22337 * @cfg {String} mode
22338 * The shadow display mode. Supports the following options:<br />
22339 * sides: Shadow displays on both sides and bottom only<br />
22340 * frame: Shadow displays equally on all four sides<br />
22341 * drop: Traditional bottom-right drop shadow (default)
22344 * @cfg {String} offset
22345 * The number of pixels to offset the shadow from the element (defaults to 4)
22350 defaultMode: "drop",
22353 * Displays the shadow under the target element
22354 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22356 show : function(target){
22357 target = Roo.get(target);
22359 this.el = Roo.Shadow.Pool.pull();
22360 if(this.el.dom.nextSibling != target.dom){
22361 this.el.insertBefore(target);
22364 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22366 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22369 target.getLeft(true),
22370 target.getTop(true),
22374 this.el.dom.style.display = "block";
22378 * Returns true if the shadow is visible, else false
22380 isVisible : function(){
22381 return this.el ? true : false;
22385 * Direct alignment when values are already available. Show must be called at least once before
22386 * calling this method to ensure it is initialized.
22387 * @param {Number} left The target element left position
22388 * @param {Number} top The target element top position
22389 * @param {Number} width The target element width
22390 * @param {Number} height The target element height
22392 realign : function(l, t, w, h){
22396 var a = this.adjusts, d = this.el.dom, s = d.style;
22398 s.left = (l+a.l)+"px";
22399 s.top = (t+a.t)+"px";
22400 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22401 if(s.width != sws || s.height != shs){
22405 var cn = d.childNodes;
22406 var sww = Math.max(0, (sw-12))+"px";
22407 cn[0].childNodes[1].style.width = sww;
22408 cn[1].childNodes[1].style.width = sww;
22409 cn[2].childNodes[1].style.width = sww;
22410 cn[1].style.height = Math.max(0, (sh-12))+"px";
22416 * Hides this shadow
22420 this.el.dom.style.display = "none";
22421 Roo.Shadow.Pool.push(this.el);
22427 * Adjust the z-index of this shadow
22428 * @param {Number} zindex The new z-index
22430 setZIndex : function(z){
22433 this.el.setStyle("z-index", z);
22438 // Private utility class that manages the internal Shadow cache
22439 Roo.Shadow.Pool = function(){
22441 var markup = Roo.isIE ?
22442 '<div class="x-ie-shadow"></div>' :
22443 '<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>';
22446 var sh = p.shift();
22448 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22449 sh.autoBoxAdjust = false;
22454 push : function(sh){
22460 * Ext JS Library 1.1.1
22461 * Copyright(c) 2006-2007, Ext JS, LLC.
22463 * Originally Released Under LGPL - original licence link has changed is not relivant.
22466 * <script type="text/javascript">
22470 * @class Roo.BoxComponent
22471 * @extends Roo.Component
22472 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22473 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22474 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22475 * layout containers.
22477 * @param {Roo.Element/String/Object} config The configuration options.
22479 Roo.BoxComponent = function(config){
22480 Roo.Component.call(this, config);
22484 * Fires after the component is resized.
22485 * @param {Roo.Component} this
22486 * @param {Number} adjWidth The box-adjusted width that was set
22487 * @param {Number} adjHeight The box-adjusted height that was set
22488 * @param {Number} rawWidth The width that was originally specified
22489 * @param {Number} rawHeight The height that was originally specified
22494 * Fires after the component is moved.
22495 * @param {Roo.Component} this
22496 * @param {Number} x The new x position
22497 * @param {Number} y The new y position
22503 Roo.extend(Roo.BoxComponent, Roo.Component, {
22504 // private, set in afterRender to signify that the component has been rendered
22506 // private, used to defer height settings to subclasses
22507 deferHeight: false,
22508 /** @cfg {Number} width
22509 * width (optional) size of component
22511 /** @cfg {Number} height
22512 * height (optional) size of component
22516 * Sets the width and height of the component. This method fires the resize event. This method can accept
22517 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22518 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22519 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22520 * @return {Roo.BoxComponent} this
22522 setSize : function(w, h){
22523 // support for standard size objects
22524 if(typeof w == 'object'){
22529 if(!this.boxReady){
22535 // prevent recalcs when not needed
22536 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22539 this.lastSize = {width: w, height: h};
22541 var adj = this.adjustSize(w, h);
22542 var aw = adj.width, ah = adj.height;
22543 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22544 var rz = this.getResizeEl();
22545 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22546 rz.setSize(aw, ah);
22547 }else if(!this.deferHeight && ah !== undefined){
22549 }else if(aw !== undefined){
22552 this.onResize(aw, ah, w, h);
22553 this.fireEvent('resize', this, aw, ah, w, h);
22559 * Gets the current size of the component's underlying element.
22560 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22562 getSize : function(){
22563 return this.el.getSize();
22567 * Gets the current XY position of the component's underlying element.
22568 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22569 * @return {Array} The XY position of the element (e.g., [100, 200])
22571 getPosition : function(local){
22572 if(local === true){
22573 return [this.el.getLeft(true), this.el.getTop(true)];
22575 return this.xy || this.el.getXY();
22579 * Gets the current box measurements of the component's underlying element.
22580 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22581 * @returns {Object} box An object in the format {x, y, width, height}
22583 getBox : function(local){
22584 var s = this.el.getSize();
22586 s.x = this.el.getLeft(true);
22587 s.y = this.el.getTop(true);
22589 var xy = this.xy || this.el.getXY();
22597 * Sets the current box measurements of the component's underlying element.
22598 * @param {Object} box An object in the format {x, y, width, height}
22599 * @returns {Roo.BoxComponent} this
22601 updateBox : function(box){
22602 this.setSize(box.width, box.height);
22603 this.setPagePosition(box.x, box.y);
22608 getResizeEl : function(){
22609 return this.resizeEl || this.el;
22613 getPositionEl : function(){
22614 return this.positionEl || this.el;
22618 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
22619 * This method fires the move event.
22620 * @param {Number} left The new left
22621 * @param {Number} top The new top
22622 * @returns {Roo.BoxComponent} this
22624 setPosition : function(x, y){
22627 if(!this.boxReady){
22630 var adj = this.adjustPosition(x, y);
22631 var ax = adj.x, ay = adj.y;
22633 var el = this.getPositionEl();
22634 if(ax !== undefined || ay !== undefined){
22635 if(ax !== undefined && ay !== undefined){
22636 el.setLeftTop(ax, ay);
22637 }else if(ax !== undefined){
22639 }else if(ay !== undefined){
22642 this.onPosition(ax, ay);
22643 this.fireEvent('move', this, ax, ay);
22649 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
22650 * This method fires the move event.
22651 * @param {Number} x The new x position
22652 * @param {Number} y The new y position
22653 * @returns {Roo.BoxComponent} this
22655 setPagePosition : function(x, y){
22658 if(!this.boxReady){
22661 if(x === undefined || y === undefined){ // cannot translate undefined points
22664 var p = this.el.translatePoints(x, y);
22665 this.setPosition(p.left, p.top);
22670 onRender : function(ct, position){
22671 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
22673 this.resizeEl = Roo.get(this.resizeEl);
22675 if(this.positionEl){
22676 this.positionEl = Roo.get(this.positionEl);
22681 afterRender : function(){
22682 Roo.BoxComponent.superclass.afterRender.call(this);
22683 this.boxReady = true;
22684 this.setSize(this.width, this.height);
22685 if(this.x || this.y){
22686 this.setPosition(this.x, this.y);
22688 if(this.pageX || this.pageY){
22689 this.setPagePosition(this.pageX, this.pageY);
22694 * Force the component's size to recalculate based on the underlying element's current height and width.
22695 * @returns {Roo.BoxComponent} this
22697 syncSize : function(){
22698 delete this.lastSize;
22699 this.setSize(this.el.getWidth(), this.el.getHeight());
22704 * Called after the component is resized, this method is empty by default but can be implemented by any
22705 * subclass that needs to perform custom logic after a resize occurs.
22706 * @param {Number} adjWidth The box-adjusted width that was set
22707 * @param {Number} adjHeight The box-adjusted height that was set
22708 * @param {Number} rawWidth The width that was originally specified
22709 * @param {Number} rawHeight The height that was originally specified
22711 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
22716 * Called after the component is moved, this method is empty by default but can be implemented by any
22717 * subclass that needs to perform custom logic after a move occurs.
22718 * @param {Number} x The new x position
22719 * @param {Number} y The new y position
22721 onPosition : function(x, y){
22726 adjustSize : function(w, h){
22727 if(this.autoWidth){
22730 if(this.autoHeight){
22733 return {width : w, height: h};
22737 adjustPosition : function(x, y){
22738 return {x : x, y: y};
22742 * Ext JS Library 1.1.1
22743 * Copyright(c) 2006-2007, Ext JS, LLC.
22745 * Originally Released Under LGPL - original licence link has changed is not relivant.
22748 * <script type="text/javascript">
22753 * @class Roo.SplitBar
22754 * @extends Roo.util.Observable
22755 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
22759 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
22760 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
22761 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
22762 split.minSize = 100;
22763 split.maxSize = 600;
22764 split.animate = true;
22765 split.on('moved', splitterMoved);
22768 * Create a new SplitBar
22769 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
22770 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
22771 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22772 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
22773 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
22774 position of the SplitBar).
22776 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
22779 this.el = Roo.get(dragElement, true);
22780 this.el.dom.unselectable = "on";
22782 this.resizingEl = Roo.get(resizingElement, true);
22786 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
22787 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
22790 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
22793 * The minimum size of the resizing element. (Defaults to 0)
22799 * The maximum size of the resizing element. (Defaults to 2000)
22802 this.maxSize = 2000;
22805 * Whether to animate the transition to the new size
22808 this.animate = false;
22811 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
22814 this.useShim = false;
22819 if(!existingProxy){
22821 this.proxy = Roo.SplitBar.createProxy(this.orientation);
22823 this.proxy = Roo.get(existingProxy).dom;
22826 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
22829 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
22832 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
22835 this.dragSpecs = {};
22838 * @private The adapter to use to positon and resize elements
22840 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
22841 this.adapter.init(this);
22843 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22845 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
22846 this.el.addClass("x-splitbar-h");
22849 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
22850 this.el.addClass("x-splitbar-v");
22856 * Fires when the splitter is moved (alias for {@link #event-moved})
22857 * @param {Roo.SplitBar} this
22858 * @param {Number} newSize the new width or height
22863 * Fires when the splitter is moved
22864 * @param {Roo.SplitBar} this
22865 * @param {Number} newSize the new width or height
22869 * @event beforeresize
22870 * Fires before the splitter is dragged
22871 * @param {Roo.SplitBar} this
22873 "beforeresize" : true,
22875 "beforeapply" : true
22878 Roo.util.Observable.call(this);
22881 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
22882 onStartProxyDrag : function(x, y){
22883 this.fireEvent("beforeresize", this);
22885 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
22887 o.enableDisplayMode("block");
22888 // all splitbars share the same overlay
22889 Roo.SplitBar.prototype.overlay = o;
22891 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
22892 this.overlay.show();
22893 Roo.get(this.proxy).setDisplayed("block");
22894 var size = this.adapter.getElementSize(this);
22895 this.activeMinSize = this.getMinimumSize();;
22896 this.activeMaxSize = this.getMaximumSize();;
22897 var c1 = size - this.activeMinSize;
22898 var c2 = Math.max(this.activeMaxSize - size, 0);
22899 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22900 this.dd.resetConstraints();
22901 this.dd.setXConstraint(
22902 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
22903 this.placement == Roo.SplitBar.LEFT ? c2 : c1
22905 this.dd.setYConstraint(0, 0);
22907 this.dd.resetConstraints();
22908 this.dd.setXConstraint(0, 0);
22909 this.dd.setYConstraint(
22910 this.placement == Roo.SplitBar.TOP ? c1 : c2,
22911 this.placement == Roo.SplitBar.TOP ? c2 : c1
22914 this.dragSpecs.startSize = size;
22915 this.dragSpecs.startPoint = [x, y];
22916 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
22920 * @private Called after the drag operation by the DDProxy
22922 onEndProxyDrag : function(e){
22923 Roo.get(this.proxy).setDisplayed(false);
22924 var endPoint = Roo.lib.Event.getXY(e);
22926 this.overlay.hide();
22929 if(this.orientation == Roo.SplitBar.HORIZONTAL){
22930 newSize = this.dragSpecs.startSize +
22931 (this.placement == Roo.SplitBar.LEFT ?
22932 endPoint[0] - this.dragSpecs.startPoint[0] :
22933 this.dragSpecs.startPoint[0] - endPoint[0]
22936 newSize = this.dragSpecs.startSize +
22937 (this.placement == Roo.SplitBar.TOP ?
22938 endPoint[1] - this.dragSpecs.startPoint[1] :
22939 this.dragSpecs.startPoint[1] - endPoint[1]
22942 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
22943 if(newSize != this.dragSpecs.startSize){
22944 if(this.fireEvent('beforeapply', this, newSize) !== false){
22945 this.adapter.setElementSize(this, newSize);
22946 this.fireEvent("moved", this, newSize);
22947 this.fireEvent("resize", this, newSize);
22953 * Get the adapter this SplitBar uses
22954 * @return The adapter object
22956 getAdapter : function(){
22957 return this.adapter;
22961 * Set the adapter this SplitBar uses
22962 * @param {Object} adapter A SplitBar adapter object
22964 setAdapter : function(adapter){
22965 this.adapter = adapter;
22966 this.adapter.init(this);
22970 * Gets the minimum size for the resizing element
22971 * @return {Number} The minimum size
22973 getMinimumSize : function(){
22974 return this.minSize;
22978 * Sets the minimum size for the resizing element
22979 * @param {Number} minSize The minimum size
22981 setMinimumSize : function(minSize){
22982 this.minSize = minSize;
22986 * Gets the maximum size for the resizing element
22987 * @return {Number} The maximum size
22989 getMaximumSize : function(){
22990 return this.maxSize;
22994 * Sets the maximum size for the resizing element
22995 * @param {Number} maxSize The maximum size
22997 setMaximumSize : function(maxSize){
22998 this.maxSize = maxSize;
23002 * Sets the initialize size for the resizing element
23003 * @param {Number} size The initial size
23005 setCurrentSize : function(size){
23006 var oldAnimate = this.animate;
23007 this.animate = false;
23008 this.adapter.setElementSize(this, size);
23009 this.animate = oldAnimate;
23013 * Destroy this splitbar.
23014 * @param {Boolean} removeEl True to remove the element
23016 destroy : function(removeEl){
23018 this.shim.remove();
23021 this.proxy.parentNode.removeChild(this.proxy);
23029 * @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.
23031 Roo.SplitBar.createProxy = function(dir){
23032 var proxy = new Roo.Element(document.createElement("div"));
23033 proxy.unselectable();
23034 var cls = 'x-splitbar-proxy';
23035 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23036 document.body.appendChild(proxy.dom);
23041 * @class Roo.SplitBar.BasicLayoutAdapter
23042 * Default Adapter. It assumes the splitter and resizing element are not positioned
23043 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23045 Roo.SplitBar.BasicLayoutAdapter = function(){
23048 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23049 // do nothing for now
23050 init : function(s){
23054 * Called before drag operations to get the current size of the resizing element.
23055 * @param {Roo.SplitBar} s The SplitBar using this adapter
23057 getElementSize : function(s){
23058 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23059 return s.resizingEl.getWidth();
23061 return s.resizingEl.getHeight();
23066 * Called after drag operations to set the size of the resizing element.
23067 * @param {Roo.SplitBar} s The SplitBar using this adapter
23068 * @param {Number} newSize The new size to set
23069 * @param {Function} onComplete A function to be invoked when resizing is complete
23071 setElementSize : function(s, newSize, onComplete){
23072 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23074 s.resizingEl.setWidth(newSize);
23076 onComplete(s, newSize);
23079 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23084 s.resizingEl.setHeight(newSize);
23086 onComplete(s, newSize);
23089 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23096 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23097 * @extends Roo.SplitBar.BasicLayoutAdapter
23098 * Adapter that moves the splitter element to align with the resized sizing element.
23099 * Used with an absolute positioned SplitBar.
23100 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23101 * document.body, make sure you assign an id to the body element.
23103 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23104 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23105 this.container = Roo.get(container);
23108 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23109 init : function(s){
23110 this.basic.init(s);
23113 getElementSize : function(s){
23114 return this.basic.getElementSize(s);
23117 setElementSize : function(s, newSize, onComplete){
23118 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23121 moveSplitter : function(s){
23122 var yes = Roo.SplitBar;
23123 switch(s.placement){
23125 s.el.setX(s.resizingEl.getRight());
23128 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23131 s.el.setY(s.resizingEl.getBottom());
23134 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23141 * Orientation constant - Create a vertical SplitBar
23145 Roo.SplitBar.VERTICAL = 1;
23148 * Orientation constant - Create a horizontal SplitBar
23152 Roo.SplitBar.HORIZONTAL = 2;
23155 * Placement constant - The resizing element is to the left of the splitter element
23159 Roo.SplitBar.LEFT = 1;
23162 * Placement constant - The resizing element is to the right of the splitter element
23166 Roo.SplitBar.RIGHT = 2;
23169 * Placement constant - The resizing element is positioned above the splitter element
23173 Roo.SplitBar.TOP = 3;
23176 * Placement constant - The resizing element is positioned under splitter element
23180 Roo.SplitBar.BOTTOM = 4;
23183 * Ext JS Library 1.1.1
23184 * Copyright(c) 2006-2007, Ext JS, LLC.
23186 * Originally Released Under LGPL - original licence link has changed is not relivant.
23189 * <script type="text/javascript">
23194 * @extends Roo.util.Observable
23195 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23196 * This class also supports single and multi selection modes. <br>
23197 * Create a data model bound view:
23199 var store = new Roo.data.Store(...);
23201 var view = new Roo.View("my-element",
23202 '<div id="{0}">{2} - {1}</div>', // auto create template
23204 singleSelect: true,
23205 selectedClass: "ydataview-selected",
23209 // listen for node click?
23210 view.on("click", function(vw, index, node, e){
23211 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23215 dataModel.load("foobar.xml");
23217 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23219 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23220 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23222 * Create a new View
23223 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
23224 * @param {String/DomHelper.Template} tpl The rendering template or a string to create a template with
23225 * @param {Object} config The config object
23227 Roo.View = function(container, tpl, config){
23228 this.el = Roo.get(container);
23229 if(typeof tpl == "string"){
23230 tpl = new Roo.Template(tpl);
23234 * The template used by this View
23235 * @type {Roo.DomHelper.Template}
23239 Roo.apply(this, config);
23244 * @event beforeclick
23245 * Fires before a click is processed. Returns false to cancel the default action.
23246 * @param {Roo.View} this
23247 * @param {Number} index The index of the target node
23248 * @param {HTMLElement} node The target node
23249 * @param {Roo.EventObject} e The raw event object
23251 "beforeclick" : true,
23254 * Fires when a template node is clicked.
23255 * @param {Roo.View} this
23256 * @param {Number} index The index of the target node
23257 * @param {HTMLElement} node The target node
23258 * @param {Roo.EventObject} e The raw event object
23263 * Fires when a template node is double clicked.
23264 * @param {Roo.View} this
23265 * @param {Number} index The index of the target node
23266 * @param {HTMLElement} node The target node
23267 * @param {Roo.EventObject} e The raw event object
23271 * @event contextmenu
23272 * Fires when a template node is right clicked.
23273 * @param {Roo.View} this
23274 * @param {Number} index The index of the target node
23275 * @param {HTMLElement} node The target node
23276 * @param {Roo.EventObject} e The raw event object
23278 "contextmenu" : true,
23280 * @event selectionchange
23281 * Fires when the selected nodes change.
23282 * @param {Roo.View} this
23283 * @param {Array} selections Array of the selected nodes
23285 "selectionchange" : true,
23288 * @event beforeselect
23289 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23290 * @param {Roo.View} this
23291 * @param {HTMLElement} node The node to be selected
23292 * @param {Array} selections Array of currently selected nodes
23294 "beforeselect" : true
23298 "click": this.onClick,
23299 "dblclick": this.onDblClick,
23300 "contextmenu": this.onContextMenu,
23304 this.selections = [];
23306 this.cmp = new Roo.CompositeElementLite([]);
23308 this.store = Roo.factory(this.store, Roo.data);
23309 this.setStore(this.store, true);
23311 Roo.View.superclass.constructor.call(this);
23314 Roo.extend(Roo.View, Roo.util.Observable, {
23316 * The css class to add to selected nodes
23317 * @type {Roo.DomHelper.Template}
23319 selectedClass : "x-view-selected",
23323 * Returns the element this view is bound to.
23324 * @return {Roo.Element}
23326 getEl : function(){
23331 * Refreshes the view.
23333 refresh : function(){
23335 this.clearSelections();
23336 this.el.update("");
23338 var records = this.store.getRange();
23339 if(records.length < 1){
23340 this.el.update(this.emptyText);
23343 for(var i = 0, len = records.length; i < len; i++){
23344 var data = this.prepareData(records[i].data, i, records[i]);
23345 html[html.length] = t.apply(data);
23347 this.el.update(html.join(""));
23348 this.nodes = this.el.dom.childNodes;
23349 this.updateIndexes(0);
23353 * Function to override to reformat the data that is sent to
23354 * the template for each node.
23355 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23356 * a JSON object for an UpdateManager bound view).
23358 prepareData : function(data){
23362 onUpdate : function(ds, record){
23363 this.clearSelections();
23364 var index = this.store.indexOf(record);
23365 var n = this.nodes[index];
23366 this.tpl.insertBefore(n, this.prepareData(record.data));
23367 n.parentNode.removeChild(n);
23368 this.updateIndexes(index, index);
23371 onAdd : function(ds, records, index){
23372 this.clearSelections();
23373 if(this.nodes.length == 0){
23377 var n = this.nodes[index];
23378 for(var i = 0, len = records.length; i < len; i++){
23379 var d = this.prepareData(records[i].data);
23381 this.tpl.insertBefore(n, d);
23383 this.tpl.append(this.el, d);
23386 this.updateIndexes(index);
23389 onRemove : function(ds, record, index){
23390 this.clearSelections();
23391 this.el.dom.removeChild(this.nodes[index]);
23392 this.updateIndexes(index);
23396 * Refresh an individual node.
23397 * @param {Number} index
23399 refreshNode : function(index){
23400 this.onUpdate(this.store, this.store.getAt(index));
23403 updateIndexes : function(startIndex, endIndex){
23404 var ns = this.nodes;
23405 startIndex = startIndex || 0;
23406 endIndex = endIndex || ns.length - 1;
23407 for(var i = startIndex; i <= endIndex; i++){
23408 ns[i].nodeIndex = i;
23413 * Changes the data store this view uses and refresh the view.
23414 * @param {Store} store
23416 setStore : function(store, initial){
23417 if(!initial && this.store){
23418 this.store.un("datachanged", this.refresh);
23419 this.store.un("add", this.onAdd);
23420 this.store.un("remove", this.onRemove);
23421 this.store.un("update", this.onUpdate);
23422 this.store.un("clear", this.refresh);
23426 store.on("datachanged", this.refresh, this);
23427 store.on("add", this.onAdd, this);
23428 store.on("remove", this.onRemove, this);
23429 store.on("update", this.onUpdate, this);
23430 store.on("clear", this.refresh, this);
23439 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23440 * @param {HTMLElement} node
23441 * @return {HTMLElement} The template node
23443 findItemFromChild : function(node){
23444 var el = this.el.dom;
23445 if(!node || node.parentNode == el){
23448 var p = node.parentNode;
23449 while(p && p != el){
23450 if(p.parentNode == el){
23459 onClick : function(e){
23460 var item = this.findItemFromChild(e.getTarget());
23462 var index = this.indexOf(item);
23463 if(this.onItemClick(item, index, e) !== false){
23464 this.fireEvent("click", this, index, item, e);
23467 this.clearSelections();
23472 onContextMenu : function(e){
23473 var item = this.findItemFromChild(e.getTarget());
23475 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23480 onDblClick : function(e){
23481 var item = this.findItemFromChild(e.getTarget());
23483 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23487 onItemClick : function(item, index, e){
23488 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23491 if(this.multiSelect || this.singleSelect){
23492 if(this.multiSelect && e.shiftKey && this.lastSelection){
23493 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23495 this.select(item, this.multiSelect && e.ctrlKey);
23496 this.lastSelection = item;
23498 e.preventDefault();
23504 * Get the number of selected nodes.
23507 getSelectionCount : function(){
23508 return this.selections.length;
23512 * Get the currently selected nodes.
23513 * @return {Array} An array of HTMLElements
23515 getSelectedNodes : function(){
23516 return this.selections;
23520 * Get the indexes of the selected nodes.
23523 getSelectedIndexes : function(){
23524 var indexes = [], s = this.selections;
23525 for(var i = 0, len = s.length; i < len; i++){
23526 indexes.push(s[i].nodeIndex);
23532 * Clear all selections
23533 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
23535 clearSelections : function(suppressEvent){
23536 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
23537 this.cmp.elements = this.selections;
23538 this.cmp.removeClass(this.selectedClass);
23539 this.selections = [];
23540 if(!suppressEvent){
23541 this.fireEvent("selectionchange", this, this.selections);
23547 * Returns true if the passed node is selected
23548 * @param {HTMLElement/Number} node The node or node index
23549 * @return {Boolean}
23551 isSelected : function(node){
23552 var s = this.selections;
23556 node = this.getNode(node);
23557 return s.indexOf(node) !== -1;
23562 * @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
23563 * @param {Boolean} keepExisting (optional) true to keep existing selections
23564 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
23566 select : function(nodeInfo, keepExisting, suppressEvent){
23567 if(nodeInfo instanceof Array){
23569 this.clearSelections(true);
23571 for(var i = 0, len = nodeInfo.length; i < len; i++){
23572 this.select(nodeInfo[i], true, true);
23575 var node = this.getNode(nodeInfo);
23576 if(node && !this.isSelected(node)){
23578 this.clearSelections(true);
23580 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
23581 Roo.fly(node).addClass(this.selectedClass);
23582 this.selections.push(node);
23583 if(!suppressEvent){
23584 this.fireEvent("selectionchange", this, this.selections);
23592 * Gets a template node.
23593 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23594 * @return {HTMLElement} The node or null if it wasn't found
23596 getNode : function(nodeInfo){
23597 if(typeof nodeInfo == "string"){
23598 return document.getElementById(nodeInfo);
23599 }else if(typeof nodeInfo == "number"){
23600 return this.nodes[nodeInfo];
23606 * Gets a range template nodes.
23607 * @param {Number} startIndex
23608 * @param {Number} endIndex
23609 * @return {Array} An array of nodes
23611 getNodes : function(start, end){
23612 var ns = this.nodes;
23613 start = start || 0;
23614 end = typeof end == "undefined" ? ns.length - 1 : end;
23617 for(var i = start; i <= end; i++){
23621 for(var i = start; i >= end; i--){
23629 * Finds the index of the passed node
23630 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
23631 * @return {Number} The index of the node or -1
23633 indexOf : function(node){
23634 node = this.getNode(node);
23635 if(typeof node.nodeIndex == "number"){
23636 return node.nodeIndex;
23638 var ns = this.nodes;
23639 for(var i = 0, len = ns.length; i < len; i++){
23649 * Ext JS Library 1.1.1
23650 * Copyright(c) 2006-2007, Ext JS, LLC.
23652 * Originally Released Under LGPL - original licence link has changed is not relivant.
23655 * <script type="text/javascript">
23659 * @class Roo.JsonView
23660 * @extends Roo.View
23661 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
23663 var view = new Roo.JsonView("my-element",
23664 '<div id="{id}">{foo} - {bar}</div>', // auto create template
23665 { multiSelect: true, jsonRoot: "data" }
23668 // listen for node click?
23669 view.on("click", function(vw, index, node, e){
23670 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23673 // direct load of JSON data
23674 view.load("foobar.php");
23676 // Example from my blog list
23677 var tpl = new Roo.Template(
23678 '<div class="entry">' +
23679 '<a class="entry-title" href="{link}">{title}</a>' +
23680 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
23681 "</div><hr />"
23684 var moreView = new Roo.JsonView("entry-list", tpl, {
23687 moreView.on("beforerender", this.sortEntries, this);
23689 url: "/blog/get-posts.php",
23690 params: "allposts=true",
23691 text: "Loading Blog Entries..."
23695 * Create a new JsonView
23696 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
23697 * @param {Template} tpl The rendering template
23698 * @param {Object} config The config object
23700 Roo.JsonView = function(container, tpl, config){
23701 Roo.JsonView.superclass.constructor.call(this, container, tpl, config);
23703 var um = this.el.getUpdateManager();
23704 um.setRenderer(this);
23705 um.on("update", this.onLoad, this);
23706 um.on("failure", this.onLoadException, this);
23709 * @event beforerender
23710 * Fires before rendering of the downloaded JSON data.
23711 * @param {Roo.JsonView} this
23712 * @param {Object} data The JSON data loaded
23716 * Fires when data is loaded.
23717 * @param {Roo.JsonView} this
23718 * @param {Object} data The JSON data loaded
23719 * @param {Object} response The raw Connect response object
23722 * @event loadexception
23723 * Fires when loading fails.
23724 * @param {Roo.JsonView} this
23725 * @param {Object} response The raw Connect response object
23728 'beforerender' : true,
23730 'loadexception' : true
23733 Roo.extend(Roo.JsonView, Roo.View, {
23735 * The root property in the loaded JSON object that contains the data
23741 * Refreshes the view.
23743 refresh : function(){
23744 this.clearSelections();
23745 this.el.update("");
23747 var o = this.jsonData;
23748 if(o && o.length > 0){
23749 for(var i = 0, len = o.length; i < len; i++){
23750 var data = this.prepareData(o[i], i, o);
23751 html[html.length] = this.tpl.apply(data);
23754 html.push(this.emptyText);
23756 this.el.update(html.join(""));
23757 this.nodes = this.el.dom.childNodes;
23758 this.updateIndexes(0);
23762 * 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.
23763 * @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:
23766 url: "your-url.php",
23767 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
23768 callback: yourFunction,
23769 scope: yourObject, //(optional scope)
23772 text: "Loading...",
23777 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
23778 * 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.
23779 * @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}
23780 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
23781 * @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.
23784 var um = this.el.getUpdateManager();
23785 um.update.apply(um, arguments);
23788 render : function(el, response){
23789 this.clearSelections();
23790 this.el.update("");
23793 o = Roo.util.JSON.decode(response.responseText);
23796 o = /** eval:var:o */ eval("o." + this.jsonRoot);
23801 * The current JSON data or null
23804 this.beforeRender();
23809 * Get the number of records in the current JSON dataset
23812 getCount : function(){
23813 return this.jsonData ? this.jsonData.length : 0;
23817 * Returns the JSON object for the specified node(s)
23818 * @param {HTMLElement/Array} node The node or an array of nodes
23819 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
23820 * you get the JSON object for the node
23822 getNodeData : function(node){
23823 if(node instanceof Array){
23825 for(var i = 0, len = node.length; i < len; i++){
23826 data.push(this.getNodeData(node[i]));
23830 return this.jsonData[this.indexOf(node)] || null;
23833 beforeRender : function(){
23834 this.snapshot = this.jsonData;
23836 this.sort.apply(this, this.sortInfo);
23838 this.fireEvent("beforerender", this, this.jsonData);
23841 onLoad : function(el, o){
23842 this.fireEvent("load", this, this.jsonData, o);
23845 onLoadException : function(el, o){
23846 this.fireEvent("loadexception", this, o);
23850 * Filter the data by a specific property.
23851 * @param {String} property A property on your JSON objects
23852 * @param {String/RegExp} value Either string that the property values
23853 * should start with, or a RegExp to test against the property
23855 filter : function(property, value){
23858 var ss = this.snapshot;
23859 if(typeof value == "string"){
23860 var vlen = value.length;
23862 this.clearFilter();
23865 value = value.toLowerCase();
23866 for(var i = 0, len = ss.length; i < len; i++){
23868 if(o[property].substr(0, vlen).toLowerCase() == value){
23872 } else if(value.exec){ // regex?
23873 for(var i = 0, len = ss.length; i < len; i++){
23875 if(value.test(o[property])){
23882 this.jsonData = data;
23888 * Filter by a function. The passed function will be called with each
23889 * object in the current dataset. If the function returns true the value is kept,
23890 * otherwise it is filtered.
23891 * @param {Function} fn
23892 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
23894 filterBy : function(fn, scope){
23897 var ss = this.snapshot;
23898 for(var i = 0, len = ss.length; i < len; i++){
23900 if(fn.call(scope || this, o)){
23904 this.jsonData = data;
23910 * Clears the current filter.
23912 clearFilter : function(){
23913 if(this.snapshot && this.jsonData != this.snapshot){
23914 this.jsonData = this.snapshot;
23921 * Sorts the data for this view and refreshes it.
23922 * @param {String} property A property on your JSON objects to sort on
23923 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
23924 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
23926 sort : function(property, dir, sortType){
23927 this.sortInfo = Array.prototype.slice.call(arguments, 0);
23930 var dsc = dir && dir.toLowerCase() == "desc";
23931 var f = function(o1, o2){
23932 var v1 = sortType ? sortType(o1[p]) : o1[p];
23933 var v2 = sortType ? sortType(o2[p]) : o2[p];
23936 return dsc ? +1 : -1;
23937 } else if(v1 > v2){
23938 return dsc ? -1 : +1;
23943 this.jsonData.sort(f);
23945 if(this.jsonData != this.snapshot){
23946 this.snapshot.sort(f);
23952 * Ext JS Library 1.1.1
23953 * Copyright(c) 2006-2007, Ext JS, LLC.
23955 * Originally Released Under LGPL - original licence link has changed is not relivant.
23958 * <script type="text/javascript">
23963 * @class Roo.ColorPalette
23964 * @extends Roo.Component
23965 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
23966 * Here's an example of typical usage:
23968 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
23969 cp.render('my-div');
23971 cp.on('select', function(palette, selColor){
23972 // do something with selColor
23976 * Create a new ColorPalette
23977 * @param {Object} config The config object
23979 Roo.ColorPalette = function(config){
23980 Roo.ColorPalette.superclass.constructor.call(this, config);
23984 * Fires when a color is selected
23985 * @param {ColorPalette} this
23986 * @param {String} color The 6-digit color hex code (without the # symbol)
23992 this.on("select", this.handler, this.scope, true);
23995 Roo.extend(Roo.ColorPalette, Roo.Component, {
23997 * @cfg {String} itemCls
23998 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24000 itemCls : "x-color-palette",
24002 * @cfg {String} value
24003 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24004 * the hex codes are case-sensitive.
24007 clickEvent:'click',
24009 ctype: "Roo.ColorPalette",
24012 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24014 allowReselect : false,
24017 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24018 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24019 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24020 * of colors with the width setting until the box is symmetrical.</p>
24021 * <p>You can override individual colors if needed:</p>
24023 var cp = new Roo.ColorPalette();
24024 cp.colors[0] = "FF0000"; // change the first box to red
24027 Or you can provide a custom array of your own for complete control:
24029 var cp = new Roo.ColorPalette();
24030 cp.colors = ["000000", "993300", "333300"];
24035 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24036 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24037 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24038 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24039 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24043 onRender : function(container, position){
24044 var t = new Roo.MasterTemplate(
24045 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24047 var c = this.colors;
24048 for(var i = 0, len = c.length; i < len; i++){
24051 var el = document.createElement("div");
24052 el.className = this.itemCls;
24054 container.dom.insertBefore(el, position);
24055 this.el = Roo.get(el);
24056 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24057 if(this.clickEvent != 'click'){
24058 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24063 afterRender : function(){
24064 Roo.ColorPalette.superclass.afterRender.call(this);
24066 var s = this.value;
24073 handleClick : function(e, t){
24074 e.preventDefault();
24075 if(!this.disabled){
24076 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24077 this.select(c.toUpperCase());
24082 * Selects the specified color in the palette (fires the select event)
24083 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24085 select : function(color){
24086 color = color.replace("#", "");
24087 if(color != this.value || this.allowReselect){
24090 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24092 el.child("a.color-"+color).addClass("x-color-palette-sel");
24093 this.value = color;
24094 this.fireEvent("select", this, color);
24099 * Ext JS Library 1.1.1
24100 * Copyright(c) 2006-2007, Ext JS, LLC.
24102 * Originally Released Under LGPL - original licence link has changed is not relivant.
24105 * <script type="text/javascript">
24109 * @class Roo.DatePicker
24110 * @extends Roo.Component
24111 * Simple date picker class.
24113 * Create a new DatePicker
24114 * @param {Object} config The config object
24116 Roo.DatePicker = function(config){
24117 Roo.DatePicker.superclass.constructor.call(this, config);
24119 this.value = config && config.value ?
24120 config.value.clearTime() : new Date().clearTime();
24125 * Fires when a date is selected
24126 * @param {DatePicker} this
24127 * @param {Date} date The selected date
24133 this.on("select", this.handler, this.scope || this);
24135 // build the disabledDatesRE
24136 if(!this.disabledDatesRE && this.disabledDates){
24137 var dd = this.disabledDates;
24139 for(var i = 0; i < dd.length; i++){
24141 if(i != dd.length-1) re += "|";
24143 this.disabledDatesRE = new RegExp(re + ")");
24147 Roo.extend(Roo.DatePicker, Roo.Component, {
24149 * @cfg {String} todayText
24150 * The text to display on the button that selects the current date (defaults to "Today")
24152 todayText : "Today",
24154 * @cfg {String} okText
24155 * The text to display on the ok button
24157 okText : " OK ", //   to give the user extra clicking room
24159 * @cfg {String} cancelText
24160 * The text to display on the cancel button
24162 cancelText : "Cancel",
24164 * @cfg {String} todayTip
24165 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24167 todayTip : "{0} (Spacebar)",
24169 * @cfg {Date} minDate
24170 * Minimum allowable date (JavaScript date object, defaults to null)
24174 * @cfg {Date} maxDate
24175 * Maximum allowable date (JavaScript date object, defaults to null)
24179 * @cfg {String} minText
24180 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24182 minText : "This date is before the minimum date",
24184 * @cfg {String} maxText
24185 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24187 maxText : "This date is after the maximum date",
24189 * @cfg {String} format
24190 * The default date format string which can be overriden for localization support. The format must be
24191 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24195 * @cfg {Array} disabledDays
24196 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24198 disabledDays : null,
24200 * @cfg {String} disabledDaysText
24201 * The tooltip to display when the date falls on a disabled day (defaults to "")
24203 disabledDaysText : "",
24205 * @cfg {RegExp} disabledDatesRE
24206 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24208 disabledDatesRE : null,
24210 * @cfg {String} disabledDatesText
24211 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24213 disabledDatesText : "",
24215 * @cfg {Boolean} constrainToViewport
24216 * True to constrain the date picker to the viewport (defaults to true)
24218 constrainToViewport : true,
24220 * @cfg {Array} monthNames
24221 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24223 monthNames : Date.monthNames,
24225 * @cfg {Array} dayNames
24226 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24228 dayNames : Date.dayNames,
24230 * @cfg {String} nextText
24231 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24233 nextText: 'Next Month (Control+Right)',
24235 * @cfg {String} prevText
24236 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24238 prevText: 'Previous Month (Control+Left)',
24240 * @cfg {String} monthYearText
24241 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24243 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24245 * @cfg {Number} startDay
24246 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24250 * @cfg {Bool} showClear
24251 * Show a clear button (usefull for date form elements that can be blank.)
24257 * Sets the value of the date field
24258 * @param {Date} value The date to set
24260 setValue : function(value){
24261 var old = this.value;
24262 this.value = value.clearTime(true);
24264 this.update(this.value);
24269 * Gets the current selected value of the date field
24270 * @return {Date} The selected date
24272 getValue : function(){
24277 focus : function(){
24279 this.update(this.activeDate);
24284 onRender : function(container, position){
24286 '<table cellspacing="0">',
24287 '<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>',
24288 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24289 var dn = this.dayNames;
24290 for(var i = 0; i < 7; i++){
24291 var d = this.startDay+i;
24295 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24297 m[m.length] = "</tr></thead><tbody><tr>";
24298 for(var i = 0; i < 42; i++) {
24299 if(i % 7 == 0 && i != 0){
24300 m[m.length] = "</tr><tr>";
24302 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24304 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24305 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24307 var el = document.createElement("div");
24308 el.className = "x-date-picker";
24309 el.innerHTML = m.join("");
24311 container.dom.insertBefore(el, position);
24313 this.el = Roo.get(el);
24314 this.eventEl = Roo.get(el.firstChild);
24316 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24317 handler: this.showPrevMonth,
24319 preventDefault:true,
24323 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24324 handler: this.showNextMonth,
24326 preventDefault:true,
24330 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24332 this.monthPicker = this.el.down('div.x-date-mp');
24333 this.monthPicker.enableDisplayMode('block');
24335 var kn = new Roo.KeyNav(this.eventEl, {
24336 "left" : function(e){
24338 this.showPrevMonth() :
24339 this.update(this.activeDate.add("d", -1));
24342 "right" : function(e){
24344 this.showNextMonth() :
24345 this.update(this.activeDate.add("d", 1));
24348 "up" : function(e){
24350 this.showNextYear() :
24351 this.update(this.activeDate.add("d", -7));
24354 "down" : function(e){
24356 this.showPrevYear() :
24357 this.update(this.activeDate.add("d", 7));
24360 "pageUp" : function(e){
24361 this.showNextMonth();
24364 "pageDown" : function(e){
24365 this.showPrevMonth();
24368 "enter" : function(e){
24369 e.stopPropagation();
24376 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24378 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24380 this.el.unselectable();
24382 this.cells = this.el.select("table.x-date-inner tbody td");
24383 this.textNodes = this.el.query("table.x-date-inner tbody span");
24385 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24387 tooltip: this.monthYearText
24390 this.mbtn.on('click', this.showMonthPicker, this);
24391 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24394 var today = (new Date()).dateFormat(this.format);
24396 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24398 text: String.format(this.todayText, today),
24399 tooltip: String.format(this.todayTip, today),
24400 handler: this.selectToday,
24404 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24407 if (this.showClear) {
24409 baseTb.add( new Roo.Toolbar.Fill());
24412 cls: 'x-btn-icon x-btn-clear',
24413 handler: function() {
24415 this.fireEvent("select", this, '');
24425 this.update(this.value);
24428 createMonthPicker : function(){
24429 if(!this.monthPicker.dom.firstChild){
24430 var buf = ['<table border="0" cellspacing="0">'];
24431 for(var i = 0; i < 6; i++){
24433 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24434 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24436 '<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>' :
24437 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24441 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24443 '</button><button type="button" class="x-date-mp-cancel">',
24445 '</button></td></tr>',
24448 this.monthPicker.update(buf.join(''));
24449 this.monthPicker.on('click', this.onMonthClick, this);
24450 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24452 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24453 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24455 this.mpMonths.each(function(m, a, i){
24458 m.dom.xmonth = 5 + Math.round(i * .5);
24460 m.dom.xmonth = Math.round((i-1) * .5);
24466 showMonthPicker : function(){
24467 this.createMonthPicker();
24468 var size = this.el.getSize();
24469 this.monthPicker.setSize(size);
24470 this.monthPicker.child('table').setSize(size);
24472 this.mpSelMonth = (this.activeDate || this.value).getMonth();
24473 this.updateMPMonth(this.mpSelMonth);
24474 this.mpSelYear = (this.activeDate || this.value).getFullYear();
24475 this.updateMPYear(this.mpSelYear);
24477 this.monthPicker.slideIn('t', {duration:.2});
24480 updateMPYear : function(y){
24482 var ys = this.mpYears.elements;
24483 for(var i = 1; i <= 10; i++){
24484 var td = ys[i-1], y2;
24486 y2 = y + Math.round(i * .5);
24487 td.firstChild.innerHTML = y2;
24490 y2 = y - (5-Math.round(i * .5));
24491 td.firstChild.innerHTML = y2;
24494 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
24498 updateMPMonth : function(sm){
24499 this.mpMonths.each(function(m, a, i){
24500 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
24504 selectMPMonth: function(m){
24508 onMonthClick : function(e, t){
24510 var el = new Roo.Element(t), pn;
24511 if(el.is('button.x-date-mp-cancel')){
24512 this.hideMonthPicker();
24514 else if(el.is('button.x-date-mp-ok')){
24515 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24516 this.hideMonthPicker();
24518 else if(pn = el.up('td.x-date-mp-month', 2)){
24519 this.mpMonths.removeClass('x-date-mp-sel');
24520 pn.addClass('x-date-mp-sel');
24521 this.mpSelMonth = pn.dom.xmonth;
24523 else if(pn = el.up('td.x-date-mp-year', 2)){
24524 this.mpYears.removeClass('x-date-mp-sel');
24525 pn.addClass('x-date-mp-sel');
24526 this.mpSelYear = pn.dom.xyear;
24528 else if(el.is('a.x-date-mp-prev')){
24529 this.updateMPYear(this.mpyear-10);
24531 else if(el.is('a.x-date-mp-next')){
24532 this.updateMPYear(this.mpyear+10);
24536 onMonthDblClick : function(e, t){
24538 var el = new Roo.Element(t), pn;
24539 if(pn = el.up('td.x-date-mp-month', 2)){
24540 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
24541 this.hideMonthPicker();
24543 else if(pn = el.up('td.x-date-mp-year', 2)){
24544 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
24545 this.hideMonthPicker();
24549 hideMonthPicker : function(disableAnim){
24550 if(this.monthPicker){
24551 if(disableAnim === true){
24552 this.monthPicker.hide();
24554 this.monthPicker.slideOut('t', {duration:.2});
24560 showPrevMonth : function(e){
24561 this.update(this.activeDate.add("mo", -1));
24565 showNextMonth : function(e){
24566 this.update(this.activeDate.add("mo", 1));
24570 showPrevYear : function(){
24571 this.update(this.activeDate.add("y", -1));
24575 showNextYear : function(){
24576 this.update(this.activeDate.add("y", 1));
24580 handleMouseWheel : function(e){
24581 var delta = e.getWheelDelta();
24583 this.showPrevMonth();
24585 } else if(delta < 0){
24586 this.showNextMonth();
24592 handleDateClick : function(e, t){
24594 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
24595 this.setValue(new Date(t.dateValue));
24596 this.fireEvent("select", this, this.value);
24601 selectToday : function(){
24602 this.setValue(new Date().clearTime());
24603 this.fireEvent("select", this, this.value);
24607 update : function(date){
24608 var vd = this.activeDate;
24609 this.activeDate = date;
24611 var t = date.getTime();
24612 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
24613 this.cells.removeClass("x-date-selected");
24614 this.cells.each(function(c){
24615 if(c.dom.firstChild.dateValue == t){
24616 c.addClass("x-date-selected");
24617 setTimeout(function(){
24618 try{c.dom.firstChild.focus();}catch(e){}
24626 var days = date.getDaysInMonth();
24627 var firstOfMonth = date.getFirstDateOfMonth();
24628 var startingPos = firstOfMonth.getDay()-this.startDay;
24630 if(startingPos <= this.startDay){
24634 var pm = date.add("mo", -1);
24635 var prevStart = pm.getDaysInMonth()-startingPos;
24637 var cells = this.cells.elements;
24638 var textEls = this.textNodes;
24639 days += startingPos;
24641 // convert everything to numbers so it's fast
24642 var day = 86400000;
24643 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
24644 var today = new Date().clearTime().getTime();
24645 var sel = date.clearTime().getTime();
24646 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
24647 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
24648 var ddMatch = this.disabledDatesRE;
24649 var ddText = this.disabledDatesText;
24650 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
24651 var ddaysText = this.disabledDaysText;
24652 var format = this.format;
24654 var setCellClass = function(cal, cell){
24656 var t = d.getTime();
24657 cell.firstChild.dateValue = t;
24659 cell.className += " x-date-today";
24660 cell.title = cal.todayText;
24663 cell.className += " x-date-selected";
24664 setTimeout(function(){
24665 try{cell.firstChild.focus();}catch(e){}
24670 cell.className = " x-date-disabled";
24671 cell.title = cal.minText;
24675 cell.className = " x-date-disabled";
24676 cell.title = cal.maxText;
24680 if(ddays.indexOf(d.getDay()) != -1){
24681 cell.title = ddaysText;
24682 cell.className = " x-date-disabled";
24685 if(ddMatch && format){
24686 var fvalue = d.dateFormat(format);
24687 if(ddMatch.test(fvalue)){
24688 cell.title = ddText.replace("%0", fvalue);
24689 cell.className = " x-date-disabled";
24695 for(; i < startingPos; i++) {
24696 textEls[i].innerHTML = (++prevStart);
24697 d.setDate(d.getDate()+1);
24698 cells[i].className = "x-date-prevday";
24699 setCellClass(this, cells[i]);
24701 for(; i < days; i++){
24702 intDay = i - startingPos + 1;
24703 textEls[i].innerHTML = (intDay);
24704 d.setDate(d.getDate()+1);
24705 cells[i].className = "x-date-active";
24706 setCellClass(this, cells[i]);
24709 for(; i < 42; i++) {
24710 textEls[i].innerHTML = (++extraDays);
24711 d.setDate(d.getDate()+1);
24712 cells[i].className = "x-date-nextday";
24713 setCellClass(this, cells[i]);
24716 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
24718 if(!this.internalRender){
24719 var main = this.el.dom.firstChild;
24720 var w = main.offsetWidth;
24721 this.el.setWidth(w + this.el.getBorderWidth("lr"));
24722 Roo.fly(main).setWidth(w);
24723 this.internalRender = true;
24724 // opera does not respect the auto grow header center column
24725 // then, after it gets a width opera refuses to recalculate
24726 // without a second pass
24727 if(Roo.isOpera && !this.secondPass){
24728 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
24729 this.secondPass = true;
24730 this.update.defer(10, this, [date]);
24736 * Ext JS Library 1.1.1
24737 * Copyright(c) 2006-2007, Ext JS, LLC.
24739 * Originally Released Under LGPL - original licence link has changed is not relivant.
24742 * <script type="text/javascript">
24745 * @class Roo.TabPanel
24746 * @extends Roo.util.Observable
24747 * A lightweight tab container.
24751 // basic tabs 1, built from existing content
24752 var tabs = new Roo.TabPanel("tabs1");
24753 tabs.addTab("script", "View Script");
24754 tabs.addTab("markup", "View Markup");
24755 tabs.activate("script");
24757 // more advanced tabs, built from javascript
24758 var jtabs = new Roo.TabPanel("jtabs");
24759 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
24761 // set up the UpdateManager
24762 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
24763 var updater = tab2.getUpdateManager();
24764 updater.setDefaultUrl("ajax1.htm");
24765 tab2.on('activate', updater.refresh, updater, true);
24767 // Use setUrl for Ajax loading
24768 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
24769 tab3.setUrl("ajax2.htm", null, true);
24772 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
24775 jtabs.activate("jtabs-1");
24778 * Create a new TabPanel.
24779 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
24780 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
24782 Roo.TabPanel = function(container, config){
24784 * The container element for this TabPanel.
24785 * @type Roo.Element
24787 this.el = Roo.get(container, true);
24789 if(typeof config == "boolean"){
24790 this.tabPosition = config ? "bottom" : "top";
24792 Roo.apply(this, config);
24795 if(this.tabPosition == "bottom"){
24796 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24797 this.el.addClass("x-tabs-bottom");
24799 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
24800 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
24801 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
24803 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
24805 if(this.tabPosition != "bottom"){
24806 /** The body element that contains {@link Roo.TabPanelItem} bodies.
24807 * @type Roo.Element
24809 this.bodyEl = Roo.get(this.createBody(this.el.dom));
24810 this.el.addClass("x-tabs-top");
24814 this.bodyEl.setStyle("position", "relative");
24816 this.active = null;
24817 this.activateDelegate = this.activate.createDelegate(this);
24822 * Fires when the active tab changes
24823 * @param {Roo.TabPanel} this
24824 * @param {Roo.TabPanelItem} activePanel The new active tab
24828 * @event beforetabchange
24829 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
24830 * @param {Roo.TabPanel} this
24831 * @param {Object} e Set cancel to true on this object to cancel the tab change
24832 * @param {Roo.TabPanelItem} tab The tab being changed to
24834 "beforetabchange" : true
24837 Roo.EventManager.onWindowResize(this.onResize, this);
24838 this.cpad = this.el.getPadding("lr");
24839 this.hiddenCount = 0;
24841 Roo.TabPanel.superclass.constructor.call(this);
24844 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
24846 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
24848 tabPosition : "top",
24850 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
24852 currentTabWidth : 0,
24854 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
24858 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
24862 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
24864 preferredTabWidth : 175,
24866 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
24868 resizeTabs : false,
24870 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
24872 monitorResize : true,
24875 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
24876 * @param {String} id The id of the div to use <b>or create</b>
24877 * @param {String} text The text for the tab
24878 * @param {String} content (optional) Content to put in the TabPanelItem body
24879 * @param {Boolean} closable (optional) True to create a close icon on the tab
24880 * @return {Roo.TabPanelItem} The created TabPanelItem
24882 addTab : function(id, text, content, closable){
24883 var item = new Roo.TabPanelItem(this, id, text, closable);
24884 this.addTabItem(item);
24886 item.setContent(content);
24892 * Returns the {@link Roo.TabPanelItem} with the specified id/index
24893 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
24894 * @return {Roo.TabPanelItem}
24896 getTab : function(id){
24897 return this.items[id];
24901 * Hides the {@link Roo.TabPanelItem} with the specified id/index
24902 * @param {String/Number} id The id or index of the TabPanelItem to hide.
24904 hideTab : function(id){
24905 var t = this.items[id];
24908 this.hiddenCount++;
24909 this.autoSizeTabs();
24914 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
24915 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
24917 unhideTab : function(id){
24918 var t = this.items[id];
24920 t.setHidden(false);
24921 this.hiddenCount--;
24922 this.autoSizeTabs();
24927 * Adds an existing {@link Roo.TabPanelItem}.
24928 * @param {Roo.TabPanelItem} item The TabPanelItem to add
24930 addTabItem : function(item){
24931 this.items[item.id] = item;
24932 this.items.push(item);
24933 if(this.resizeTabs){
24934 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
24935 this.autoSizeTabs();
24942 * Removes a {@link Roo.TabPanelItem}.
24943 * @param {String/Number} id The id or index of the TabPanelItem to remove.
24945 removeTab : function(id){
24946 var items = this.items;
24947 var tab = items[id];
24949 var index = items.indexOf(tab);
24950 if(this.active == tab && items.length > 1){
24951 var newTab = this.getNextAvailable(index);
24952 if(newTab)newTab.activate();
24954 this.stripEl.dom.removeChild(tab.pnode.dom);
24955 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
24956 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
24958 items.splice(index, 1);
24959 delete this.items[tab.id];
24960 tab.fireEvent("close", tab);
24961 tab.purgeListeners();
24962 this.autoSizeTabs();
24965 getNextAvailable : function(start){
24966 var items = this.items;
24968 // look for a next tab that will slide over to
24969 // replace the one being removed
24970 while(index < items.length){
24971 var item = items[++index];
24972 if(item && !item.isHidden()){
24976 // if one isn't found select the previous tab (on the left)
24979 var item = items[--index];
24980 if(item && !item.isHidden()){
24988 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
24989 * @param {String/Number} id The id or index of the TabPanelItem to disable.
24991 disableTab : function(id){
24992 var tab = this.items[id];
24993 if(tab && this.active != tab){
24999 * Enables a {@link Roo.TabPanelItem} that is disabled.
25000 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25002 enableTab : function(id){
25003 var tab = this.items[id];
25008 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25009 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25010 * @return {Roo.TabPanelItem} The TabPanelItem.
25012 activate : function(id){
25013 var tab = this.items[id];
25017 if(tab == this.active || tab.disabled){
25021 this.fireEvent("beforetabchange", this, e, tab);
25022 if(e.cancel !== true && !tab.disabled){
25024 this.active.hide();
25026 this.active = this.items[id];
25027 this.active.show();
25028 this.fireEvent("tabchange", this, this.active);
25034 * Gets the active {@link Roo.TabPanelItem}.
25035 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25037 getActiveTab : function(){
25038 return this.active;
25042 * Updates the tab body element to fit the height of the container element
25043 * for overflow scrolling
25044 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25046 syncHeight : function(targetHeight){
25047 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25048 var bm = this.bodyEl.getMargins();
25049 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25050 this.bodyEl.setHeight(newHeight);
25054 onResize : function(){
25055 if(this.monitorResize){
25056 this.autoSizeTabs();
25061 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25063 beginUpdate : function(){
25064 this.updating = true;
25068 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25070 endUpdate : function(){
25071 this.updating = false;
25072 this.autoSizeTabs();
25076 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25078 autoSizeTabs : function(){
25079 var count = this.items.length;
25080 var vcount = count - this.hiddenCount;
25081 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25082 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25083 var availWidth = Math.floor(w / vcount);
25084 var b = this.stripBody;
25085 if(b.getWidth() > w){
25086 var tabs = this.items;
25087 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25088 if(availWidth < this.minTabWidth){
25089 /*if(!this.sleft){ // incomplete scrolling code
25090 this.createScrollButtons();
25093 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25096 if(this.currentTabWidth < this.preferredTabWidth){
25097 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25103 * Returns the number of tabs in this TabPanel.
25106 getCount : function(){
25107 return this.items.length;
25111 * Resizes all the tabs to the passed width
25112 * @param {Number} The new width
25114 setTabWidth : function(width){
25115 this.currentTabWidth = width;
25116 for(var i = 0, len = this.items.length; i < len; i++) {
25117 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25122 * Destroys this TabPanel
25123 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25125 destroy : function(removeEl){
25126 Roo.EventManager.removeResizeListener(this.onResize, this);
25127 for(var i = 0, len = this.items.length; i < len; i++){
25128 this.items[i].purgeListeners();
25130 if(removeEl === true){
25131 this.el.update("");
25138 * @class Roo.TabPanelItem
25139 * @extends Roo.util.Observable
25140 * Represents an individual item (tab plus body) in a TabPanel.
25141 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25142 * @param {String} id The id of this TabPanelItem
25143 * @param {String} text The text for the tab of this TabPanelItem
25144 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25146 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25148 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25149 * @type Roo.TabPanel
25151 this.tabPanel = tabPanel;
25153 * The id for this TabPanelItem
25158 this.disabled = false;
25162 this.loaded = false;
25163 this.closable = closable;
25166 * The body element for this TabPanelItem.
25167 * @type Roo.Element
25169 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25170 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25171 this.bodyEl.setStyle("display", "block");
25172 this.bodyEl.setStyle("zoom", "1");
25175 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25177 this.el = Roo.get(els.el, true);
25178 this.inner = Roo.get(els.inner, true);
25179 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25180 this.pnode = Roo.get(els.el.parentNode, true);
25181 this.el.on("mousedown", this.onTabMouseDown, this);
25182 this.el.on("click", this.onTabClick, this);
25185 var c = Roo.get(els.close, true);
25186 c.dom.title = this.closeText;
25187 c.addClassOnOver("close-over");
25188 c.on("click", this.closeClick, this);
25194 * Fires when this tab becomes the active tab.
25195 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25196 * @param {Roo.TabPanelItem} this
25200 * @event beforeclose
25201 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25202 * @param {Roo.TabPanelItem} this
25203 * @param {Object} e Set cancel to true on this object to cancel the close.
25205 "beforeclose": true,
25208 * Fires when this tab is closed.
25209 * @param {Roo.TabPanelItem} this
25213 * @event deactivate
25214 * Fires when this tab is no longer the active tab.
25215 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25216 * @param {Roo.TabPanelItem} this
25218 "deactivate" : true
25220 this.hidden = false;
25222 Roo.TabPanelItem.superclass.constructor.call(this);
25225 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25226 purgeListeners : function(){
25227 Roo.util.Observable.prototype.purgeListeners.call(this);
25228 this.el.removeAllListeners();
25231 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25234 this.pnode.addClass("on");
25237 this.tabPanel.stripWrap.repaint();
25239 this.fireEvent("activate", this.tabPanel, this);
25243 * Returns true if this tab is the active tab.
25244 * @return {Boolean}
25246 isActive : function(){
25247 return this.tabPanel.getActiveTab() == this;
25251 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25254 this.pnode.removeClass("on");
25256 this.fireEvent("deactivate", this.tabPanel, this);
25259 hideAction : function(){
25260 this.bodyEl.hide();
25261 this.bodyEl.setStyle("position", "absolute");
25262 this.bodyEl.setLeft("-20000px");
25263 this.bodyEl.setTop("-20000px");
25266 showAction : function(){
25267 this.bodyEl.setStyle("position", "relative");
25268 this.bodyEl.setTop("");
25269 this.bodyEl.setLeft("");
25270 this.bodyEl.show();
25274 * Set the tooltip for the tab.
25275 * @param {String} tooltip The tab's tooltip
25277 setTooltip : function(text){
25278 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25279 this.textEl.dom.qtip = text;
25280 this.textEl.dom.removeAttribute('title');
25282 this.textEl.dom.title = text;
25286 onTabClick : function(e){
25287 e.preventDefault();
25288 this.tabPanel.activate(this.id);
25291 onTabMouseDown : function(e){
25292 e.preventDefault();
25293 this.tabPanel.activate(this.id);
25296 getWidth : function(){
25297 return this.inner.getWidth();
25300 setWidth : function(width){
25301 var iwidth = width - this.pnode.getPadding("lr");
25302 this.inner.setWidth(iwidth);
25303 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25304 this.pnode.setWidth(width);
25308 * Show or hide the tab
25309 * @param {Boolean} hidden True to hide or false to show.
25311 setHidden : function(hidden){
25312 this.hidden = hidden;
25313 this.pnode.setStyle("display", hidden ? "none" : "");
25317 * Returns true if this tab is "hidden"
25318 * @return {Boolean}
25320 isHidden : function(){
25321 return this.hidden;
25325 * Returns the text for this tab
25328 getText : function(){
25332 autoSize : function(){
25333 //this.el.beginMeasure();
25334 this.textEl.setWidth(1);
25335 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25336 //this.el.endMeasure();
25340 * Sets the text for the tab (Note: this also sets the tooltip text)
25341 * @param {String} text The tab's text and tooltip
25343 setText : function(text){
25345 this.textEl.update(text);
25346 this.setTooltip(text);
25347 if(!this.tabPanel.resizeTabs){
25352 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25354 activate : function(){
25355 this.tabPanel.activate(this.id);
25359 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25361 disable : function(){
25362 if(this.tabPanel.active != this){
25363 this.disabled = true;
25364 this.pnode.addClass("disabled");
25369 * Enables this TabPanelItem if it was previously disabled.
25371 enable : function(){
25372 this.disabled = false;
25373 this.pnode.removeClass("disabled");
25377 * Sets the content for this TabPanelItem.
25378 * @param {String} content The content
25379 * @param {Boolean} loadScripts true to look for and load scripts
25381 setContent : function(content, loadScripts){
25382 this.bodyEl.update(content, loadScripts);
25386 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25387 * @return {Roo.UpdateManager} The UpdateManager
25389 getUpdateManager : function(){
25390 return this.bodyEl.getUpdateManager();
25394 * Set a URL to be used to load the content for this TabPanelItem.
25395 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25396 * @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)
25397 * @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)
25398 * @return {Roo.UpdateManager} The UpdateManager
25400 setUrl : function(url, params, loadOnce){
25401 if(this.refreshDelegate){
25402 this.un('activate', this.refreshDelegate);
25404 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25405 this.on("activate", this.refreshDelegate);
25406 return this.bodyEl.getUpdateManager();
25410 _handleRefresh : function(url, params, loadOnce){
25411 if(!loadOnce || !this.loaded){
25412 var updater = this.bodyEl.getUpdateManager();
25413 updater.update(url, params, this._setLoaded.createDelegate(this));
25418 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25419 * Will fail silently if the setUrl method has not been called.
25420 * This does not activate the panel, just updates its content.
25422 refresh : function(){
25423 if(this.refreshDelegate){
25424 this.loaded = false;
25425 this.refreshDelegate();
25430 _setLoaded : function(){
25431 this.loaded = true;
25435 closeClick : function(e){
25438 this.fireEvent("beforeclose", this, o);
25439 if(o.cancel !== true){
25440 this.tabPanel.removeTab(this.id);
25444 * The text displayed in the tooltip for the close icon.
25447 closeText : "Close this tab"
25451 Roo.TabPanel.prototype.createStrip = function(container){
25452 var strip = document.createElement("div");
25453 strip.className = "x-tabs-wrap";
25454 container.appendChild(strip);
25458 Roo.TabPanel.prototype.createStripList = function(strip){
25459 // div wrapper for retard IE
25460 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>';
25461 return strip.firstChild.firstChild.firstChild.firstChild;
25464 Roo.TabPanel.prototype.createBody = function(container){
25465 var body = document.createElement("div");
25466 Roo.id(body, "tab-body");
25467 Roo.fly(body).addClass("x-tabs-body");
25468 container.appendChild(body);
25472 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
25473 var body = Roo.getDom(id);
25475 body = document.createElement("div");
25478 Roo.fly(body).addClass("x-tabs-item-body");
25479 bodyEl.insertBefore(body, bodyEl.firstChild);
25483 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
25484 var td = document.createElement("td");
25485 stripEl.appendChild(td);
25487 td.className = "x-tabs-closable";
25488 if(!this.closeTpl){
25489 this.closeTpl = new Roo.Template(
25490 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25491 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
25492 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
25495 var el = this.closeTpl.overwrite(td, {"text": text});
25496 var close = el.getElementsByTagName("div")[0];
25497 var inner = el.getElementsByTagName("em")[0];
25498 return {"el": el, "close": close, "inner": inner};
25501 this.tabTpl = new Roo.Template(
25502 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
25503 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
25506 var el = this.tabTpl.overwrite(td, {"text": text});
25507 var inner = el.getElementsByTagName("em")[0];
25508 return {"el": el, "inner": inner};
25512 * Ext JS Library 1.1.1
25513 * Copyright(c) 2006-2007, Ext JS, LLC.
25515 * Originally Released Under LGPL - original licence link has changed is not relivant.
25518 * <script type="text/javascript">
25522 * @class Roo.Button
25523 * @extends Roo.util.Observable
25524 * Simple Button class
25525 * @cfg {String} text The button text
25526 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
25527 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
25528 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
25529 * @cfg {Object} scope The scope of the handler
25530 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
25531 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
25532 * @cfg {Boolean} hidden True to start hidden (defaults to false)
25533 * @cfg {Boolean} disabled True to start disabled (defaults to false)
25534 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
25535 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
25536 applies if enableToggle = true)
25537 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
25538 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
25539 an {@link Roo.util.ClickRepeater} config object (defaults to false).
25541 * Create a new button
25542 * @param {Object} config The config object
25544 Roo.Button = function(renderTo, config)
25548 renderTo = config.renderTo || false;
25551 Roo.apply(this, config);
25555 * Fires when this button is clicked
25556 * @param {Button} this
25557 * @param {EventObject} e The click event
25562 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
25563 * @param {Button} this
25564 * @param {Boolean} pressed
25569 * Fires when the mouse hovers over the button
25570 * @param {Button} this
25571 * @param {Event} e The event object
25573 'mouseover' : true,
25576 * Fires when the mouse exits the button
25577 * @param {Button} this
25578 * @param {Event} e The event object
25583 * Fires when the button is rendered
25584 * @param {Button} this
25589 this.menu = Roo.menu.MenuMgr.get(this.menu);
25592 this.render(renderTo);
25595 Roo.util.Observable.call(this);
25598 Roo.extend(Roo.Button, Roo.util.Observable, {
25604 * Read-only. True if this button is hidden
25609 * Read-only. True if this button is disabled
25614 * Read-only. True if this button is pressed (only if enableToggle = true)
25620 * @cfg {Number} tabIndex
25621 * The DOM tabIndex for this button (defaults to undefined)
25623 tabIndex : undefined,
25626 * @cfg {Boolean} enableToggle
25627 * True to enable pressed/not pressed toggling (defaults to false)
25629 enableToggle: false,
25631 * @cfg {Mixed} menu
25632 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
25636 * @cfg {String} menuAlign
25637 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
25639 menuAlign : "tl-bl?",
25642 * @cfg {String} iconCls
25643 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
25645 iconCls : undefined,
25647 * @cfg {String} type
25648 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
25653 menuClassTarget: 'tr',
25656 * @cfg {String} clickEvent
25657 * The type of event to map to the button's event handler (defaults to 'click')
25659 clickEvent : 'click',
25662 * @cfg {Boolean} handleMouseEvents
25663 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
25665 handleMouseEvents : true,
25668 * @cfg {String} tooltipType
25669 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
25671 tooltipType : 'qtip',
25674 * @cfg {String} cls
25675 * A CSS class to apply to the button's main element.
25679 * @cfg {Roo.Template} template (Optional)
25680 * An {@link Roo.Template} with which to create the Button's main element. This Template must
25681 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
25682 * require code modifications if required elements (e.g. a button) aren't present.
25686 render : function(renderTo){
25688 if(this.hideParent){
25689 this.parentEl = Roo.get(renderTo);
25691 if(!this.dhconfig){
25692 if(!this.template){
25693 if(!Roo.Button.buttonTemplate){
25694 // hideous table template
25695 Roo.Button.buttonTemplate = new Roo.Template(
25696 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
25697 '<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>',
25698 "</tr></tbody></table>");
25700 this.template = Roo.Button.buttonTemplate;
25702 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
25703 var btnEl = btn.child("button:first");
25704 btnEl.on('focus', this.onFocus, this);
25705 btnEl.on('blur', this.onBlur, this);
25707 btn.addClass(this.cls);
25710 btnEl.setStyle('background-image', 'url(' +this.icon +')');
25713 btnEl.addClass(this.iconCls);
25715 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
25718 if(this.tabIndex !== undefined){
25719 btnEl.dom.tabIndex = this.tabIndex;
25722 if(typeof this.tooltip == 'object'){
25723 Roo.QuickTips.tips(Roo.apply({
25727 btnEl.dom[this.tooltipType] = this.tooltip;
25731 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
25735 this.el.dom.id = this.el.id = this.id;
25738 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
25739 this.menu.on("show", this.onMenuShow, this);
25740 this.menu.on("hide", this.onMenuHide, this);
25742 btn.addClass("x-btn");
25743 if(Roo.isIE && !Roo.isIE7){
25744 this.autoWidth.defer(1, this);
25748 if(this.handleMouseEvents){
25749 btn.on("mouseover", this.onMouseOver, this);
25750 btn.on("mouseout", this.onMouseOut, this);
25751 btn.on("mousedown", this.onMouseDown, this);
25753 btn.on(this.clickEvent, this.onClick, this);
25754 //btn.on("mouseup", this.onMouseUp, this);
25761 Roo.ButtonToggleMgr.register(this);
25763 this.el.addClass("x-btn-pressed");
25766 var repeater = new Roo.util.ClickRepeater(btn,
25767 typeof this.repeat == "object" ? this.repeat : {}
25769 repeater.on("click", this.onClick, this);
25771 this.fireEvent('render', this);
25775 * Returns the button's underlying element
25776 * @return {Roo.Element} The element
25778 getEl : function(){
25783 * Destroys this Button and removes any listeners.
25785 destroy : function(){
25786 Roo.ButtonToggleMgr.unregister(this);
25787 this.el.removeAllListeners();
25788 this.purgeListeners();
25793 autoWidth : function(){
25795 this.el.setWidth("auto");
25796 if(Roo.isIE7 && Roo.isStrict){
25797 var ib = this.el.child('button');
25798 if(ib && ib.getWidth() > 20){
25800 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
25805 this.el.beginMeasure();
25807 if(this.el.getWidth() < this.minWidth){
25808 this.el.setWidth(this.minWidth);
25811 this.el.endMeasure();
25818 * Assigns this button's click handler
25819 * @param {Function} handler The function to call when the button is clicked
25820 * @param {Object} scope (optional) Scope for the function passed in
25822 setHandler : function(handler, scope){
25823 this.handler = handler;
25824 this.scope = scope;
25828 * Sets this button's text
25829 * @param {String} text The button text
25831 setText : function(text){
25834 this.el.child("td.x-btn-center button.x-btn-text").update(text);
25840 * Gets the text for this button
25841 * @return {String} The button text
25843 getText : function(){
25851 this.hidden = false;
25853 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
25861 this.hidden = true;
25863 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
25868 * Convenience function for boolean show/hide
25869 * @param {Boolean} visible True to show, false to hide
25871 setVisible: function(visible){
25880 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
25881 * @param {Boolean} state (optional) Force a particular state
25883 toggle : function(state){
25884 state = state === undefined ? !this.pressed : state;
25885 if(state != this.pressed){
25887 this.el.addClass("x-btn-pressed");
25888 this.pressed = true;
25889 this.fireEvent("toggle", this, true);
25891 this.el.removeClass("x-btn-pressed");
25892 this.pressed = false;
25893 this.fireEvent("toggle", this, false);
25895 if(this.toggleHandler){
25896 this.toggleHandler.call(this.scope || this, this, state);
25904 focus : function(){
25905 this.el.child('button:first').focus();
25909 * Disable this button
25911 disable : function(){
25913 this.el.addClass("x-btn-disabled");
25915 this.disabled = true;
25919 * Enable this button
25921 enable : function(){
25923 this.el.removeClass("x-btn-disabled");
25925 this.disabled = false;
25929 * Convenience function for boolean enable/disable
25930 * @param {Boolean} enabled True to enable, false to disable
25932 setDisabled : function(v){
25933 this[v !== true ? "enable" : "disable"]();
25937 onClick : function(e){
25939 e.preventDefault();
25944 if(!this.disabled){
25945 if(this.enableToggle){
25948 if(this.menu && !this.menu.isVisible()){
25949 this.menu.show(this.el, this.menuAlign);
25951 this.fireEvent("click", this, e);
25953 this.el.removeClass("x-btn-over");
25954 this.handler.call(this.scope || this, this, e);
25959 onMouseOver : function(e){
25960 if(!this.disabled){
25961 this.el.addClass("x-btn-over");
25962 this.fireEvent('mouseover', this, e);
25966 onMouseOut : function(e){
25967 if(!e.within(this.el, true)){
25968 this.el.removeClass("x-btn-over");
25969 this.fireEvent('mouseout', this, e);
25973 onFocus : function(e){
25974 if(!this.disabled){
25975 this.el.addClass("x-btn-focus");
25979 onBlur : function(e){
25980 this.el.removeClass("x-btn-focus");
25983 onMouseDown : function(e){
25984 if(!this.disabled && e.button == 0){
25985 this.el.addClass("x-btn-click");
25986 Roo.get(document).on('mouseup', this.onMouseUp, this);
25990 onMouseUp : function(e){
25992 this.el.removeClass("x-btn-click");
25993 Roo.get(document).un('mouseup', this.onMouseUp, this);
25997 onMenuShow : function(e){
25998 this.el.addClass("x-btn-menu-active");
26001 onMenuHide : function(e){
26002 this.el.removeClass("x-btn-menu-active");
26006 // Private utility class used by Button
26007 Roo.ButtonToggleMgr = function(){
26010 function toggleGroup(btn, state){
26012 var g = groups[btn.toggleGroup];
26013 for(var i = 0, l = g.length; i < l; i++){
26015 g[i].toggle(false);
26022 register : function(btn){
26023 if(!btn.toggleGroup){
26026 var g = groups[btn.toggleGroup];
26028 g = groups[btn.toggleGroup] = [];
26031 btn.on("toggle", toggleGroup);
26034 unregister : function(btn){
26035 if(!btn.toggleGroup){
26038 var g = groups[btn.toggleGroup];
26041 btn.un("toggle", toggleGroup);
26047 * Ext JS Library 1.1.1
26048 * Copyright(c) 2006-2007, Ext JS, LLC.
26050 * Originally Released Under LGPL - original licence link has changed is not relivant.
26053 * <script type="text/javascript">
26057 * @class Roo.SplitButton
26058 * @extends Roo.Button
26059 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26060 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26061 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26062 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26063 * @cfg {String} arrowTooltip The title attribute of the arrow
26065 * Create a new menu button
26066 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26067 * @param {Object} config The config object
26069 Roo.SplitButton = function(renderTo, config){
26070 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26072 * @event arrowclick
26073 * Fires when this button's arrow is clicked
26074 * @param {SplitButton} this
26075 * @param {EventObject} e The click event
26077 this.addEvents({"arrowclick":true});
26080 Roo.extend(Roo.SplitButton, Roo.Button, {
26081 render : function(renderTo){
26082 // this is one sweet looking template!
26083 var tpl = new Roo.Template(
26084 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26085 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26086 '<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>',
26087 "</tbody></table></td><td>",
26088 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26089 '<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>',
26090 "</tbody></table></td></tr></table>"
26092 var btn = tpl.append(renderTo, [this.text, this.type], true);
26093 var btnEl = btn.child("button");
26095 btn.addClass(this.cls);
26098 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26101 btnEl.addClass(this.iconCls);
26103 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26107 if(this.handleMouseEvents){
26108 btn.on("mouseover", this.onMouseOver, this);
26109 btn.on("mouseout", this.onMouseOut, this);
26110 btn.on("mousedown", this.onMouseDown, this);
26111 btn.on("mouseup", this.onMouseUp, this);
26113 btn.on(this.clickEvent, this.onClick, this);
26115 if(typeof this.tooltip == 'object'){
26116 Roo.QuickTips.tips(Roo.apply({
26120 btnEl.dom[this.tooltipType] = this.tooltip;
26123 if(this.arrowTooltip){
26124 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26133 this.el.addClass("x-btn-pressed");
26135 if(Roo.isIE && !Roo.isIE7){
26136 this.autoWidth.defer(1, this);
26141 this.menu.on("show", this.onMenuShow, this);
26142 this.menu.on("hide", this.onMenuHide, this);
26144 this.fireEvent('render', this);
26148 autoWidth : function(){
26150 var tbl = this.el.child("table:first");
26151 var tbl2 = this.el.child("table:last");
26152 this.el.setWidth("auto");
26153 tbl.setWidth("auto");
26154 if(Roo.isIE7 && Roo.isStrict){
26155 var ib = this.el.child('button:first');
26156 if(ib && ib.getWidth() > 20){
26158 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26163 this.el.beginMeasure();
26165 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26166 tbl.setWidth(this.minWidth-tbl2.getWidth());
26169 this.el.endMeasure();
26172 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26176 * Sets this button's click handler
26177 * @param {Function} handler The function to call when the button is clicked
26178 * @param {Object} scope (optional) Scope for the function passed above
26180 setHandler : function(handler, scope){
26181 this.handler = handler;
26182 this.scope = scope;
26186 * Sets this button's arrow click handler
26187 * @param {Function} handler The function to call when the arrow is clicked
26188 * @param {Object} scope (optional) Scope for the function passed above
26190 setArrowHandler : function(handler, scope){
26191 this.arrowHandler = handler;
26192 this.scope = scope;
26198 focus : function(){
26200 this.el.child("button:first").focus();
26205 onClick : function(e){
26206 e.preventDefault();
26207 if(!this.disabled){
26208 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26209 if(this.menu && !this.menu.isVisible()){
26210 this.menu.show(this.el, this.menuAlign);
26212 this.fireEvent("arrowclick", this, e);
26213 if(this.arrowHandler){
26214 this.arrowHandler.call(this.scope || this, this, e);
26217 this.fireEvent("click", this, e);
26219 this.handler.call(this.scope || this, this, e);
26225 onMouseDown : function(e){
26226 if(!this.disabled){
26227 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26231 onMouseUp : function(e){
26232 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26237 // backwards compat
26238 Roo.MenuButton = Roo.SplitButton;/*
26240 * Ext JS Library 1.1.1
26241 * Copyright(c) 2006-2007, Ext JS, LLC.
26243 * Originally Released Under LGPL - original licence link has changed is not relivant.
26246 * <script type="text/javascript">
26250 * @class Roo.Toolbar
26251 * Basic Toolbar class.
26253 * Creates a new Toolbar
26254 * @param {Object} config The config object
26256 Roo.Toolbar = function(container, buttons, config)
26258 /// old consturctor format still supported..
26259 if(container instanceof Array){ // omit the container for later rendering
26260 buttons = container;
26264 if (typeof(container) == 'object' && container.xtype) {
26265 config = container;
26266 container = config.container;
26267 buttons = config.buttons; // not really - use items!!
26270 if (config && config.items) {
26271 xitems = config.items;
26272 delete config.items;
26274 Roo.apply(this, config);
26275 this.buttons = buttons;
26278 this.render(container);
26280 Roo.each(xitems, function(b) {
26286 Roo.Toolbar.prototype = {
26288 * @cfg {Roo.data.Store} items
26289 * array of button configs or elements to add
26293 * @cfg {String/HTMLElement/Element} container
26294 * The id or element that will contain the toolbar
26297 render : function(ct){
26298 this.el = Roo.get(ct);
26300 this.el.addClass(this.cls);
26302 // using a table allows for vertical alignment
26303 // 100% width is needed by Safari...
26304 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26305 this.tr = this.el.child("tr", true);
26307 this.items = new Roo.util.MixedCollection(false, function(o){
26308 return o.id || ("item" + (++autoId));
26311 this.add.apply(this, this.buttons);
26312 delete this.buttons;
26317 * Adds element(s) to the toolbar -- this function takes a variable number of
26318 * arguments of mixed type and adds them to the toolbar.
26319 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26321 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26322 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26323 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26324 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26325 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26326 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26327 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26328 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26329 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26331 * @param {Mixed} arg2
26332 * @param {Mixed} etc.
26335 var a = arguments, l = a.length;
26336 for(var i = 0; i < l; i++){
26341 _add : function(el) {
26344 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26347 if (el.applyTo){ // some kind of form field
26348 return this.addField(el);
26350 if (el.render){ // some kind of Toolbar.Item
26351 return this.addItem(el);
26353 if (typeof el == "string"){ // string
26354 if(el == "separator" || el == "-"){
26355 return this.addSeparator();
26358 return this.addSpacer();
26361 return this.addFill();
26363 return this.addText(el);
26366 if(el.tagName){ // element
26367 return this.addElement(el);
26369 if(typeof el == "object"){ // must be button config?
26370 return this.addButton(el);
26372 // and now what?!?!
26378 * Add an Xtype element
26379 * @param {Object} xtype Xtype Object
26380 * @return {Object} created Object
26382 addxtype : function(e){
26383 return this.add(e);
26387 * Returns the Element for this toolbar.
26388 * @return {Roo.Element}
26390 getEl : function(){
26396 * @return {Roo.Toolbar.Item} The separator item
26398 addSeparator : function(){
26399 return this.addItem(new Roo.Toolbar.Separator());
26403 * Adds a spacer element
26404 * @return {Roo.Toolbar.Spacer} The spacer item
26406 addSpacer : function(){
26407 return this.addItem(new Roo.Toolbar.Spacer());
26411 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26412 * @return {Roo.Toolbar.Fill} The fill item
26414 addFill : function(){
26415 return this.addItem(new Roo.Toolbar.Fill());
26419 * Adds any standard HTML element to the toolbar
26420 * @param {String/HTMLElement/Element} el The element or id of the element to add
26421 * @return {Roo.Toolbar.Item} The element's item
26423 addElement : function(el){
26424 return this.addItem(new Roo.Toolbar.Item(el));
26427 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26428 * @type Roo.util.MixedCollection
26433 * Adds any Toolbar.Item or subclass
26434 * @param {Roo.Toolbar.Item} item
26435 * @return {Roo.Toolbar.Item} The item
26437 addItem : function(item){
26438 var td = this.nextBlock();
26440 this.items.add(item);
26445 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
26446 * @param {Object/Array} config A button config or array of configs
26447 * @return {Roo.Toolbar.Button/Array}
26449 addButton : function(config){
26450 if(config instanceof Array){
26452 for(var i = 0, len = config.length; i < len; i++) {
26453 buttons.push(this.addButton(config[i]));
26458 if(!(config instanceof Roo.Toolbar.Button)){
26460 new Roo.Toolbar.SplitButton(config) :
26461 new Roo.Toolbar.Button(config);
26463 var td = this.nextBlock();
26470 * Adds text to the toolbar
26471 * @param {String} text The text to add
26472 * @return {Roo.Toolbar.Item} The element's item
26474 addText : function(text){
26475 return this.addItem(new Roo.Toolbar.TextItem(text));
26479 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
26480 * @param {Number} index The index where the item is to be inserted
26481 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
26482 * @return {Roo.Toolbar.Button/Item}
26484 insertButton : function(index, item){
26485 if(item instanceof Array){
26487 for(var i = 0, len = item.length; i < len; i++) {
26488 buttons.push(this.insertButton(index + i, item[i]));
26492 if (!(item instanceof Roo.Toolbar.Button)){
26493 item = new Roo.Toolbar.Button(item);
26495 var td = document.createElement("td");
26496 this.tr.insertBefore(td, this.tr.childNodes[index]);
26498 this.items.insert(index, item);
26503 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
26504 * @param {Object} config
26505 * @return {Roo.Toolbar.Item} The element's item
26507 addDom : function(config, returnEl){
26508 var td = this.nextBlock();
26509 Roo.DomHelper.overwrite(td, config);
26510 var ti = new Roo.Toolbar.Item(td.firstChild);
26512 this.items.add(ti);
26517 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
26518 * @type Roo.util.MixedCollection
26523 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
26524 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
26525 * @param {Roo.form.Field} field
26526 * @return {Roo.ToolbarItem}
26530 addField : function(field) {
26531 if (!this.fields) {
26533 this.fields = new Roo.util.MixedCollection(false, function(o){
26534 return o.id || ("item" + (++autoId));
26539 var td = this.nextBlock();
26541 var ti = new Roo.Toolbar.Item(td.firstChild);
26543 this.items.add(ti);
26544 this.fields.add(field);
26555 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
26556 this.el.child('div').hide();
26564 this.el.child('div').show();
26568 nextBlock : function(){
26569 var td = document.createElement("td");
26570 this.tr.appendChild(td);
26575 destroy : function(){
26576 if(this.items){ // rendered?
26577 Roo.destroy.apply(Roo, this.items.items);
26579 if(this.fields){ // rendered?
26580 Roo.destroy.apply(Roo, this.fields.items);
26582 Roo.Element.uncache(this.el, this.tr);
26587 * @class Roo.Toolbar.Item
26588 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
26590 * Creates a new Item
26591 * @param {HTMLElement} el
26593 Roo.Toolbar.Item = function(el){
26594 this.el = Roo.getDom(el);
26595 this.id = Roo.id(this.el);
26596 this.hidden = false;
26599 Roo.Toolbar.Item.prototype = {
26602 * Get this item's HTML Element
26603 * @return {HTMLElement}
26605 getEl : function(){
26610 render : function(td){
26612 td.appendChild(this.el);
26616 * Removes and destroys this item.
26618 destroy : function(){
26619 this.td.parentNode.removeChild(this.td);
26626 this.hidden = false;
26627 this.td.style.display = "";
26634 this.hidden = true;
26635 this.td.style.display = "none";
26639 * Convenience function for boolean show/hide.
26640 * @param {Boolean} visible true to show/false to hide
26642 setVisible: function(visible){
26651 * Try to focus this item.
26653 focus : function(){
26654 Roo.fly(this.el).focus();
26658 * Disables this item.
26660 disable : function(){
26661 Roo.fly(this.td).addClass("x-item-disabled");
26662 this.disabled = true;
26663 this.el.disabled = true;
26667 * Enables this item.
26669 enable : function(){
26670 Roo.fly(this.td).removeClass("x-item-disabled");
26671 this.disabled = false;
26672 this.el.disabled = false;
26678 * @class Roo.Toolbar.Separator
26679 * @extends Roo.Toolbar.Item
26680 * A simple toolbar separator class
26682 * Creates a new Separator
26684 Roo.Toolbar.Separator = function(){
26685 var s = document.createElement("span");
26686 s.className = "ytb-sep";
26687 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
26689 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
26690 enable:Roo.emptyFn,
26691 disable:Roo.emptyFn,
26696 * @class Roo.Toolbar.Spacer
26697 * @extends Roo.Toolbar.Item
26698 * A simple element that adds extra horizontal space to a toolbar.
26700 * Creates a new Spacer
26702 Roo.Toolbar.Spacer = function(){
26703 var s = document.createElement("div");
26704 s.className = "ytb-spacer";
26705 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
26707 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
26708 enable:Roo.emptyFn,
26709 disable:Roo.emptyFn,
26714 * @class Roo.Toolbar.Fill
26715 * @extends Roo.Toolbar.Spacer
26716 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
26718 * Creates a new Spacer
26720 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
26722 render : function(td){
26723 td.style.width = '100%';
26724 Roo.Toolbar.Fill.superclass.render.call(this, td);
26729 * @class Roo.Toolbar.TextItem
26730 * @extends Roo.Toolbar.Item
26731 * A simple class that renders text directly into a toolbar.
26733 * Creates a new TextItem
26734 * @param {String} text
26736 Roo.Toolbar.TextItem = function(text){
26737 if (typeof(text) == 'object') {
26740 var s = document.createElement("span");
26741 s.className = "ytb-text";
26742 s.innerHTML = text;
26743 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
26745 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
26746 enable:Roo.emptyFn,
26747 disable:Roo.emptyFn,
26752 * @class Roo.Toolbar.Button
26753 * @extends Roo.Button
26754 * A button that renders into a toolbar.
26756 * Creates a new Button
26757 * @param {Object} config A standard {@link Roo.Button} config object
26759 Roo.Toolbar.Button = function(config){
26760 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
26762 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
26763 render : function(td){
26765 Roo.Toolbar.Button.superclass.render.call(this, td);
26769 * Removes and destroys this button
26771 destroy : function(){
26772 Roo.Toolbar.Button.superclass.destroy.call(this);
26773 this.td.parentNode.removeChild(this.td);
26777 * Shows this button
26780 this.hidden = false;
26781 this.td.style.display = "";
26785 * Hides this button
26788 this.hidden = true;
26789 this.td.style.display = "none";
26793 * Disables this item
26795 disable : function(){
26796 Roo.fly(this.td).addClass("x-item-disabled");
26797 this.disabled = true;
26801 * Enables this item
26803 enable : function(){
26804 Roo.fly(this.td).removeClass("x-item-disabled");
26805 this.disabled = false;
26808 // backwards compat
26809 Roo.ToolbarButton = Roo.Toolbar.Button;
26812 * @class Roo.Toolbar.SplitButton
26813 * @extends Roo.SplitButton
26814 * A menu button that renders into a toolbar.
26816 * Creates a new SplitButton
26817 * @param {Object} config A standard {@link Roo.SplitButton} config object
26819 Roo.Toolbar.SplitButton = function(config){
26820 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
26822 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
26823 render : function(td){
26825 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
26829 * Removes and destroys this button
26831 destroy : function(){
26832 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
26833 this.td.parentNode.removeChild(this.td);
26837 * Shows this button
26840 this.hidden = false;
26841 this.td.style.display = "";
26845 * Hides this button
26848 this.hidden = true;
26849 this.td.style.display = "none";
26853 // backwards compat
26854 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
26856 * Ext JS Library 1.1.1
26857 * Copyright(c) 2006-2007, Ext JS, LLC.
26859 * Originally Released Under LGPL - original licence link has changed is not relivant.
26862 * <script type="text/javascript">
26866 * @class Roo.PagingToolbar
26867 * @extends Roo.Toolbar
26868 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26870 * Create a new PagingToolbar
26871 * @param {Object} config The config object
26873 Roo.PagingToolbar = function(el, ds, config)
26875 // old args format still supported... - xtype is prefered..
26876 if (typeof(el) == 'object' && el.xtype) {
26877 // created from xtype...
26879 ds = el.dataSource;
26880 el = config.container;
26884 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
26887 this.renderButtons(this.el);
26891 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
26893 * @cfg {Roo.data.Store} dataSource
26894 * The underlying data store providing the paged data
26897 * @cfg {String/HTMLElement/Element} container
26898 * container The id or element that will contain the toolbar
26901 * @cfg {Boolean} displayInfo
26902 * True to display the displayMsg (defaults to false)
26905 * @cfg {Number} pageSize
26906 * The number of records to display per page (defaults to 20)
26910 * @cfg {String} displayMsg
26911 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26913 displayMsg : 'Displaying {0} - {1} of {2}',
26915 * @cfg {String} emptyMsg
26916 * The message to display when no records are found (defaults to "No data to display")
26918 emptyMsg : 'No data to display',
26920 * Customizable piece of the default paging text (defaults to "Page")
26923 beforePageText : "Page",
26925 * Customizable piece of the default paging text (defaults to "of %0")
26928 afterPageText : "of {0}",
26930 * Customizable piece of the default paging text (defaults to "First Page")
26933 firstText : "First Page",
26935 * Customizable piece of the default paging text (defaults to "Previous Page")
26938 prevText : "Previous Page",
26940 * Customizable piece of the default paging text (defaults to "Next Page")
26943 nextText : "Next Page",
26945 * Customizable piece of the default paging text (defaults to "Last Page")
26948 lastText : "Last Page",
26950 * Customizable piece of the default paging text (defaults to "Refresh")
26953 refreshText : "Refresh",
26956 renderButtons : function(el){
26957 Roo.PagingToolbar.superclass.render.call(this, el);
26958 this.first = this.addButton({
26959 tooltip: this.firstText,
26960 cls: "x-btn-icon x-grid-page-first",
26962 handler: this.onClick.createDelegate(this, ["first"])
26964 this.prev = this.addButton({
26965 tooltip: this.prevText,
26966 cls: "x-btn-icon x-grid-page-prev",
26968 handler: this.onClick.createDelegate(this, ["prev"])
26970 this.addSeparator();
26971 this.add(this.beforePageText);
26972 this.field = Roo.get(this.addDom({
26977 cls: "x-grid-page-number"
26979 this.field.on("keydown", this.onPagingKeydown, this);
26980 this.field.on("focus", function(){this.dom.select();});
26981 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
26982 this.field.setHeight(18);
26983 this.addSeparator();
26984 this.next = this.addButton({
26985 tooltip: this.nextText,
26986 cls: "x-btn-icon x-grid-page-next",
26988 handler: this.onClick.createDelegate(this, ["next"])
26990 this.last = this.addButton({
26991 tooltip: this.lastText,
26992 cls: "x-btn-icon x-grid-page-last",
26994 handler: this.onClick.createDelegate(this, ["last"])
26996 this.addSeparator();
26997 this.loading = this.addButton({
26998 tooltip: this.refreshText,
26999 cls: "x-btn-icon x-grid-loading",
27000 handler: this.onClick.createDelegate(this, ["refresh"])
27003 if(this.displayInfo){
27004 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27009 updateInfo : function(){
27010 if(this.displayEl){
27011 var count = this.ds.getCount();
27012 var msg = count == 0 ?
27016 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27018 this.displayEl.update(msg);
27023 onLoad : function(ds, r, o){
27024 this.cursor = o.params ? o.params.start : 0;
27025 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27027 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27028 this.field.dom.value = ap;
27029 this.first.setDisabled(ap == 1);
27030 this.prev.setDisabled(ap == 1);
27031 this.next.setDisabled(ap == ps);
27032 this.last.setDisabled(ap == ps);
27033 this.loading.enable();
27038 getPageData : function(){
27039 var total = this.ds.getTotalCount();
27042 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27043 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27048 onLoadError : function(){
27049 this.loading.enable();
27053 onPagingKeydown : function(e){
27054 var k = e.getKey();
27055 var d = this.getPageData();
27057 var v = this.field.dom.value, pageNum;
27058 if(!v || isNaN(pageNum = parseInt(v, 10))){
27059 this.field.dom.value = d.activePage;
27062 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27063 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27066 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))
27068 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27069 this.field.dom.value = pageNum;
27070 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27073 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27075 var v = this.field.dom.value, pageNum;
27076 var increment = (e.shiftKey) ? 10 : 1;
27077 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27079 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27080 this.field.dom.value = d.activePage;
27083 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27085 this.field.dom.value = parseInt(v, 10) + increment;
27086 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27087 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27094 beforeLoad : function(){
27096 this.loading.disable();
27101 onClick : function(which){
27105 ds.load({params:{start: 0, limit: this.pageSize}});
27108 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27111 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27114 var total = ds.getTotalCount();
27115 var extra = total % this.pageSize;
27116 var lastStart = extra ? (total - extra) : total-this.pageSize;
27117 ds.load({params:{start: lastStart, limit: this.pageSize}});
27120 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27126 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27127 * @param {Roo.data.Store} store The data store to unbind
27129 unbind : function(ds){
27130 ds.un("beforeload", this.beforeLoad, this);
27131 ds.un("load", this.onLoad, this);
27132 ds.un("loadexception", this.onLoadError, this);
27133 ds.un("remove", this.updateInfo, this);
27134 ds.un("add", this.updateInfo, this);
27135 this.ds = undefined;
27139 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27140 * @param {Roo.data.Store} store The data store to bind
27142 bind : function(ds){
27143 ds.on("beforeload", this.beforeLoad, this);
27144 ds.on("load", this.onLoad, this);
27145 ds.on("loadexception", this.onLoadError, this);
27146 ds.on("remove", this.updateInfo, this);
27147 ds.on("add", this.updateInfo, this);
27152 * Ext JS Library 1.1.1
27153 * Copyright(c) 2006-2007, Ext JS, LLC.
27155 * Originally Released Under LGPL - original licence link has changed is not relivant.
27158 * <script type="text/javascript">
27162 * @class Roo.Resizable
27163 * @extends Roo.util.Observable
27164 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27165 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27166 * 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
27167 * the element will be wrapped for you automatically.</p>
27168 * <p>Here is the list of valid resize handles:</p>
27171 ------ -------------------
27182 * <p>Here's an example showing the creation of a typical Resizable:</p>
27184 var resizer = new Roo.Resizable("element-id", {
27192 resizer.on("resize", myHandler);
27194 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27195 * resizer.east.setDisplayed(false);</p>
27196 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27197 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27198 * resize operation's new size (defaults to [0, 0])
27199 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27200 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27201 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27202 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27203 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27204 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27205 * @cfg {Number} width The width of the element in pixels (defaults to null)
27206 * @cfg {Number} height The height of the element in pixels (defaults to null)
27207 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27208 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27209 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27210 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27211 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27212 * in favor of the handles config option (defaults to false)
27213 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27214 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27215 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27216 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27217 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27218 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27219 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27220 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27221 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27222 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27223 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27225 * Create a new resizable component
27226 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27227 * @param {Object} config configuration options
27229 Roo.Resizable = function(el, config){
27230 this.el = Roo.get(el);
27232 if(config && config.wrap){
27233 config.resizeChild = this.el;
27234 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27235 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27236 this.el.setStyle("overflow", "hidden");
27237 this.el.setPositioning(config.resizeChild.getPositioning());
27238 config.resizeChild.clearPositioning();
27239 if(!config.width || !config.height){
27240 var csize = config.resizeChild.getSize();
27241 this.el.setSize(csize.width, csize.height);
27243 if(config.pinned && !config.adjustments){
27244 config.adjustments = "auto";
27248 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27249 this.proxy.unselectable();
27250 this.proxy.enableDisplayMode('block');
27252 Roo.apply(this, config);
27255 this.disableTrackOver = true;
27256 this.el.addClass("x-resizable-pinned");
27258 // if the element isn't positioned, make it relative
27259 var position = this.el.getStyle("position");
27260 if(position != "absolute" && position != "fixed"){
27261 this.el.setStyle("position", "relative");
27263 if(!this.handles){ // no handles passed, must be legacy style
27264 this.handles = 's,e,se';
27265 if(this.multiDirectional){
27266 this.handles += ',n,w';
27269 if(this.handles == "all"){
27270 this.handles = "n s e w ne nw se sw";
27272 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27273 var ps = Roo.Resizable.positions;
27274 for(var i = 0, len = hs.length; i < len; i++){
27275 if(hs[i] && ps[hs[i]]){
27276 var pos = ps[hs[i]];
27277 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27281 this.corner = this.southeast;
27283 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1){
27284 this.updateBox = true;
27287 this.activeHandle = null;
27289 if(this.resizeChild){
27290 if(typeof this.resizeChild == "boolean"){
27291 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27293 this.resizeChild = Roo.get(this.resizeChild, true);
27297 if(this.adjustments == "auto"){
27298 var rc = this.resizeChild;
27299 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27300 if(rc && (hw || hn)){
27301 rc.position("relative");
27302 rc.setLeft(hw ? hw.el.getWidth() : 0);
27303 rc.setTop(hn ? hn.el.getHeight() : 0);
27305 this.adjustments = [
27306 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27307 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27311 if(this.draggable){
27312 this.dd = this.dynamic ?
27313 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27314 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27320 * @event beforeresize
27321 * Fired before resize is allowed. Set enabled to false to cancel resize.
27322 * @param {Roo.Resizable} this
27323 * @param {Roo.EventObject} e The mousedown event
27325 "beforeresize" : true,
27328 * Fired after a resize.
27329 * @param {Roo.Resizable} this
27330 * @param {Number} width The new width
27331 * @param {Number} height The new height
27332 * @param {Roo.EventObject} e The mouseup event
27337 if(this.width !== null && this.height !== null){
27338 this.resizeTo(this.width, this.height);
27340 this.updateChildSize();
27343 this.el.dom.style.zoom = 1;
27345 Roo.Resizable.superclass.constructor.call(this);
27348 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27349 resizeChild : false,
27350 adjustments : [0, 0],
27360 multiDirectional : false,
27361 disableTrackOver : false,
27362 easing : 'easeOutStrong',
27363 widthIncrement : 0,
27364 heightIncrement : 0,
27368 preserveRatio : false,
27369 transparent: false,
27375 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27377 constrainTo: undefined,
27379 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27381 resizeRegion: undefined,
27385 * Perform a manual resize
27386 * @param {Number} width
27387 * @param {Number} height
27389 resizeTo : function(width, height){
27390 this.el.setSize(width, height);
27391 this.updateChildSize();
27392 this.fireEvent("resize", this, width, height, null);
27396 startSizing : function(e, handle){
27397 this.fireEvent("beforeresize", this, e);
27398 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27401 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27402 this.overlay.unselectable();
27403 this.overlay.enableDisplayMode("block");
27404 this.overlay.on("mousemove", this.onMouseMove, this);
27405 this.overlay.on("mouseup", this.onMouseUp, this);
27407 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27409 this.resizing = true;
27410 this.startBox = this.el.getBox();
27411 this.startPoint = e.getXY();
27412 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27413 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27415 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27416 this.overlay.show();
27418 if(this.constrainTo) {
27419 var ct = Roo.get(this.constrainTo);
27420 this.resizeRegion = ct.getRegion().adjust(
27421 ct.getFrameWidth('t'),
27422 ct.getFrameWidth('l'),
27423 -ct.getFrameWidth('b'),
27424 -ct.getFrameWidth('r')
27428 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
27430 this.proxy.setBox(this.startBox);
27432 this.proxy.setStyle('visibility', 'visible');
27438 onMouseDown : function(handle, e){
27441 this.activeHandle = handle;
27442 this.startSizing(e, handle);
27447 onMouseUp : function(e){
27448 var size = this.resizeElement();
27449 this.resizing = false;
27451 this.overlay.hide();
27453 this.fireEvent("resize", this, size.width, size.height, e);
27457 updateChildSize : function(){
27458 if(this.resizeChild){
27460 var child = this.resizeChild;
27461 var adj = this.adjustments;
27462 if(el.dom.offsetWidth){
27463 var b = el.getSize(true);
27464 child.setSize(b.width+adj[0], b.height+adj[1]);
27466 // Second call here for IE
27467 // The first call enables instant resizing and
27468 // the second call corrects scroll bars if they
27471 setTimeout(function(){
27472 if(el.dom.offsetWidth){
27473 var b = el.getSize(true);
27474 child.setSize(b.width+adj[0], b.height+adj[1]);
27482 snap : function(value, inc, min){
27483 if(!inc || !value) return value;
27484 var newValue = value;
27485 var m = value % inc;
27488 newValue = value + (inc-m);
27490 newValue = value - m;
27493 return Math.max(min, newValue);
27497 resizeElement : function(){
27498 var box = this.proxy.getBox();
27499 if(this.updateBox){
27500 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
27502 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
27504 this.updateChildSize();
27512 constrain : function(v, diff, m, mx){
27515 }else if(v - diff > mx){
27522 onMouseMove : function(e){
27524 try{// try catch so if something goes wrong the user doesn't get hung
27526 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
27530 //var curXY = this.startPoint;
27531 var curSize = this.curSize || this.startBox;
27532 var x = this.startBox.x, y = this.startBox.y;
27533 var ox = x, oy = y;
27534 var w = curSize.width, h = curSize.height;
27535 var ow = w, oh = h;
27536 var mw = this.minWidth, mh = this.minHeight;
27537 var mxw = this.maxWidth, mxh = this.maxHeight;
27538 var wi = this.widthIncrement;
27539 var hi = this.heightIncrement;
27541 var eventXY = e.getXY();
27542 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
27543 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
27545 var pos = this.activeHandle.position;
27550 w = Math.min(Math.max(mw, w), mxw);
27554 h = Math.min(Math.max(mh, h), mxh);
27559 w = Math.min(Math.max(mw, w), mxw);
27560 h = Math.min(Math.max(mh, h), mxh);
27563 diffY = this.constrain(h, diffY, mh, mxh);
27568 diffX = this.constrain(w, diffX, mw, mxw);
27574 w = Math.min(Math.max(mw, w), mxw);
27575 diffY = this.constrain(h, diffY, mh, mxh);
27580 diffX = this.constrain(w, diffX, mw, mxw);
27581 diffY = this.constrain(h, diffY, mh, mxh);
27588 diffX = this.constrain(w, diffX, mw, mxw);
27590 h = Math.min(Math.max(mh, h), mxh);
27596 var sw = this.snap(w, wi, mw);
27597 var sh = this.snap(h, hi, mh);
27598 if(sw != w || sh != h){
27621 if(this.preserveRatio){
27626 h = Math.min(Math.max(mh, h), mxh);
27631 w = Math.min(Math.max(mw, w), mxw);
27636 w = Math.min(Math.max(mw, w), mxw);
27642 w = Math.min(Math.max(mw, w), mxw);
27648 h = Math.min(Math.max(mh, h), mxh);
27656 h = Math.min(Math.max(mh, h), mxh);
27666 h = Math.min(Math.max(mh, h), mxh);
27674 this.proxy.setBounds(x, y, w, h);
27676 this.resizeElement();
27683 handleOver : function(){
27685 this.el.addClass("x-resizable-over");
27690 handleOut : function(){
27691 if(!this.resizing){
27692 this.el.removeClass("x-resizable-over");
27697 * Returns the element this component is bound to.
27698 * @return {Roo.Element}
27700 getEl : function(){
27705 * Returns the resizeChild element (or null).
27706 * @return {Roo.Element}
27708 getResizeChild : function(){
27709 return this.resizeChild;
27713 * Destroys this resizable. If the element was wrapped and
27714 * removeEl is not true then the element remains.
27715 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
27717 destroy : function(removeEl){
27718 this.proxy.remove();
27720 this.overlay.removeAllListeners();
27721 this.overlay.remove();
27723 var ps = Roo.Resizable.positions;
27725 if(typeof ps[k] != "function" && this[ps[k]]){
27726 var h = this[ps[k]];
27727 h.el.removeAllListeners();
27732 this.el.update("");
27739 // hash to map config positions to true positions
27740 Roo.Resizable.positions = {
27741 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast"
27745 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
27747 // only initialize the template if resizable is used
27748 var tpl = Roo.DomHelper.createTemplate(
27749 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
27752 Roo.Resizable.Handle.prototype.tpl = tpl;
27754 this.position = pos;
27756 this.el = this.tpl.append(rz.el.dom, [this.position], true);
27757 this.el.unselectable();
27759 this.el.setOpacity(0);
27761 this.el.on("mousedown", this.onMouseDown, this);
27762 if(!disableTrackOver){
27763 this.el.on("mouseover", this.onMouseOver, this);
27764 this.el.on("mouseout", this.onMouseOut, this);
27769 Roo.Resizable.Handle.prototype = {
27770 afterResize : function(rz){
27774 onMouseDown : function(e){
27775 this.rz.onMouseDown(this, e);
27778 onMouseOver : function(e){
27779 this.rz.handleOver(this, e);
27782 onMouseOut : function(e){
27783 this.rz.handleOut(this, e);
27787 * Ext JS Library 1.1.1
27788 * Copyright(c) 2006-2007, Ext JS, LLC.
27790 * Originally Released Under LGPL - original licence link has changed is not relivant.
27793 * <script type="text/javascript">
27797 * @class Roo.Editor
27798 * @extends Roo.Component
27799 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
27801 * Create a new Editor
27802 * @param {Roo.form.Field} field The Field object (or descendant)
27803 * @param {Object} config The config object
27805 Roo.Editor = function(field, config){
27806 Roo.Editor.superclass.constructor.call(this, config);
27807 this.field = field;
27810 * @event beforestartedit
27811 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
27812 * false from the handler of this event.
27813 * @param {Editor} this
27814 * @param {Roo.Element} boundEl The underlying element bound to this editor
27815 * @param {Mixed} value The field value being set
27817 "beforestartedit" : true,
27820 * Fires when this editor is displayed
27821 * @param {Roo.Element} boundEl The underlying element bound to this editor
27822 * @param {Mixed} value The starting field value
27824 "startedit" : true,
27826 * @event beforecomplete
27827 * Fires after a change has been made to the field, but before the change is reflected in the underlying
27828 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
27829 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
27830 * event will not fire since no edit actually occurred.
27831 * @param {Editor} this
27832 * @param {Mixed} value The current field value
27833 * @param {Mixed} startValue The original field value
27835 "beforecomplete" : true,
27838 * Fires after editing is complete and any changed value has been written to the underlying field.
27839 * @param {Editor} this
27840 * @param {Mixed} value The current field value
27841 * @param {Mixed} startValue The original field value
27845 * @event specialkey
27846 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
27847 * {@link Roo.EventObject#getKey} to determine which key was pressed.
27848 * @param {Roo.form.Field} this
27849 * @param {Roo.EventObject} e The event object
27851 "specialkey" : true
27855 Roo.extend(Roo.Editor, Roo.Component, {
27857 * @cfg {Boolean/String} autosize
27858 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
27859 * or "height" to adopt the height only (defaults to false)
27862 * @cfg {Boolean} revertInvalid
27863 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
27864 * validation fails (defaults to true)
27867 * @cfg {Boolean} ignoreNoChange
27868 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
27869 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
27870 * will never be ignored.
27873 * @cfg {Boolean} hideEl
27874 * False to keep the bound element visible while the editor is displayed (defaults to true)
27877 * @cfg {Mixed} value
27878 * The data value of the underlying field (defaults to "")
27882 * @cfg {String} alignment
27883 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
27887 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
27888 * for bottom-right shadow (defaults to "frame")
27892 * @cfg {Boolean} constrain True to constrain the editor to the viewport
27896 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
27898 completeOnEnter : false,
27900 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
27902 cancelOnEsc : false,
27904 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
27909 onRender : function(ct, position){
27910 this.el = new Roo.Layer({
27911 shadow: this.shadow,
27917 constrain: this.constrain
27919 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
27920 if(this.field.msgTarget != 'title'){
27921 this.field.msgTarget = 'qtip';
27923 this.field.render(this.el);
27925 this.field.el.dom.setAttribute('autocomplete', 'off');
27927 this.field.on("specialkey", this.onSpecialKey, this);
27928 if(this.swallowKeys){
27929 this.field.el.swallowEvent(['keydown','keypress']);
27932 this.field.on("blur", this.onBlur, this);
27933 if(this.field.grow){
27934 this.field.on("autosize", this.el.sync, this.el, {delay:1});
27938 onSpecialKey : function(field, e){
27939 if(this.completeOnEnter && e.getKey() == e.ENTER){
27941 this.completeEdit();
27942 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
27945 this.fireEvent('specialkey', field, e);
27950 * Starts the editing process and shows the editor.
27951 * @param {String/HTMLElement/Element} el The element to edit
27952 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
27953 * to the innerHTML of el.
27955 startEdit : function(el, value){
27957 this.completeEdit();
27959 this.boundEl = Roo.get(el);
27960 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
27961 if(!this.rendered){
27962 this.render(this.parentEl || document.body);
27964 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
27967 this.startValue = v;
27968 this.field.setValue(v);
27970 var sz = this.boundEl.getSize();
27971 switch(this.autoSize){
27973 this.setSize(sz.width, "");
27976 this.setSize("", sz.height);
27979 this.setSize(sz.width, sz.height);
27982 this.el.alignTo(this.boundEl, this.alignment);
27983 this.editing = true;
27985 Roo.QuickTips.disable();
27991 * Sets the height and width of this editor.
27992 * @param {Number} width The new width
27993 * @param {Number} height The new height
27995 setSize : function(w, h){
27996 this.field.setSize(w, h);
28003 * Realigns the editor to the bound field based on the current alignment config value.
28005 realign : function(){
28006 this.el.alignTo(this.boundEl, this.alignment);
28010 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28011 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28013 completeEdit : function(remainVisible){
28017 var v = this.getValue();
28018 if(this.revertInvalid !== false && !this.field.isValid()){
28019 v = this.startValue;
28020 this.cancelEdit(true);
28022 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28023 this.editing = false;
28027 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28028 this.editing = false;
28029 if(this.updateEl && this.boundEl){
28030 this.boundEl.update(v);
28032 if(remainVisible !== true){
28035 this.fireEvent("complete", this, v, this.startValue);
28040 onShow : function(){
28042 if(this.hideEl !== false){
28043 this.boundEl.hide();
28046 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28047 this.fixIEFocus = true;
28048 this.deferredFocus.defer(50, this);
28050 this.field.focus();
28052 this.fireEvent("startedit", this.boundEl, this.startValue);
28055 deferredFocus : function(){
28057 this.field.focus();
28062 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28063 * reverted to the original starting value.
28064 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28065 * cancel (defaults to false)
28067 cancelEdit : function(remainVisible){
28069 this.setValue(this.startValue);
28070 if(remainVisible !== true){
28077 onBlur : function(){
28078 if(this.allowBlur !== true && this.editing){
28079 this.completeEdit();
28084 onHide : function(){
28086 this.completeEdit();
28090 if(this.field.collapse){
28091 this.field.collapse();
28094 if(this.hideEl !== false){
28095 this.boundEl.show();
28098 Roo.QuickTips.enable();
28103 * Sets the data value of the editor
28104 * @param {Mixed} value Any valid value supported by the underlying field
28106 setValue : function(v){
28107 this.field.setValue(v);
28111 * Gets the data value of the editor
28112 * @return {Mixed} The data value
28114 getValue : function(){
28115 return this.field.getValue();
28119 * Ext JS Library 1.1.1
28120 * Copyright(c) 2006-2007, Ext JS, LLC.
28122 * Originally Released Under LGPL - original licence link has changed is not relivant.
28125 * <script type="text/javascript">
28129 * @class Roo.BasicDialog
28130 * @extends Roo.util.Observable
28131 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28133 var dlg = new Roo.BasicDialog("my-dlg", {
28142 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28143 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28144 dlg.addButton('Cancel', dlg.hide, dlg);
28147 <b>A Dialog should always be a direct child of the body element.</b>
28148 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28149 * @cfg {String} title Default text to display in the title bar (defaults to null)
28150 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28151 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28152 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28153 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28154 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28155 * (defaults to null with no animation)
28156 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28157 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28158 * property for valid values (defaults to 'all')
28159 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28160 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28161 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28162 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28163 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28164 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28165 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28166 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28167 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28168 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28169 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28170 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28171 * draggable = true (defaults to false)
28172 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28173 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28174 * shadow (defaults to false)
28175 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28176 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28177 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28178 * @cfg {Array} buttons Array of buttons
28179 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28181 * Create a new BasicDialog.
28182 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28183 * @param {Object} config Configuration options
28185 Roo.BasicDialog = function(el, config){
28186 this.el = Roo.get(el);
28187 var dh = Roo.DomHelper;
28188 if(!this.el && config && config.autoCreate){
28189 if(typeof config.autoCreate == "object"){
28190 if(!config.autoCreate.id){
28191 config.autoCreate.id = el;
28193 this.el = dh.append(document.body,
28194 config.autoCreate, true);
28196 this.el = dh.append(document.body,
28197 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28201 el.setDisplayed(true);
28202 el.hide = this.hideAction;
28204 el.addClass("x-dlg");
28206 Roo.apply(this, config);
28208 this.proxy = el.createProxy("x-dlg-proxy");
28209 this.proxy.hide = this.hideAction;
28210 this.proxy.setOpacity(.5);
28214 el.setWidth(config.width);
28217 el.setHeight(config.height);
28219 this.size = el.getSize();
28220 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28221 this.xy = [config.x,config.y];
28223 this.xy = el.getCenterXY(true);
28225 /** The header element @type Roo.Element */
28226 this.header = el.child("> .x-dlg-hd");
28227 /** The body element @type Roo.Element */
28228 this.body = el.child("> .x-dlg-bd");
28229 /** The footer element @type Roo.Element */
28230 this.footer = el.child("> .x-dlg-ft");
28233 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28236 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28239 this.header.unselectable();
28241 this.header.update(this.title);
28243 // this element allows the dialog to be focused for keyboard event
28244 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28245 this.focusEl.swallowEvent("click", true);
28247 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28249 // wrap the body and footer for special rendering
28250 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28252 this.bwrap.dom.appendChild(this.footer.dom);
28255 this.bg = this.el.createChild({
28256 tag: "div", cls:"x-dlg-bg",
28257 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28259 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28262 if(this.autoScroll !== false && !this.autoTabs){
28263 this.body.setStyle("overflow", "auto");
28266 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28268 if(this.closable !== false){
28269 this.el.addClass("x-dlg-closable");
28270 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28271 this.close.on("click", this.closeClick, this);
28272 this.close.addClassOnOver("x-dlg-close-over");
28274 if(this.collapsible !== false){
28275 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28276 this.collapseBtn.on("click", this.collapseClick, this);
28277 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28278 this.header.on("dblclick", this.collapseClick, this);
28280 if(this.resizable !== false){
28281 this.el.addClass("x-dlg-resizable");
28282 this.resizer = new Roo.Resizable(el, {
28283 minWidth: this.minWidth || 80,
28284 minHeight:this.minHeight || 80,
28285 handles: this.resizeHandles || "all",
28288 this.resizer.on("beforeresize", this.beforeResize, this);
28289 this.resizer.on("resize", this.onResize, this);
28291 if(this.draggable !== false){
28292 el.addClass("x-dlg-draggable");
28293 if (!this.proxyDrag) {
28294 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28297 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28299 dd.setHandleElId(this.header.id);
28300 dd.endDrag = this.endMove.createDelegate(this);
28301 dd.startDrag = this.startMove.createDelegate(this);
28302 dd.onDrag = this.onDrag.createDelegate(this);
28307 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28308 this.mask.enableDisplayMode("block");
28310 this.el.addClass("x-dlg-modal");
28313 this.shadow = new Roo.Shadow({
28314 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28315 offset : this.shadowOffset
28318 this.shadowOffset = 0;
28320 if(Roo.useShims && this.shim !== false){
28321 this.shim = this.el.createShim();
28322 this.shim.hide = this.hideAction;
28330 if (this.buttons) {
28331 var bts= this.buttons;
28333 Roo.each(bts, function(b) {
28342 * Fires when a key is pressed
28343 * @param {Roo.BasicDialog} this
28344 * @param {Roo.EventObject} e
28349 * Fires when this dialog is moved by the user.
28350 * @param {Roo.BasicDialog} this
28351 * @param {Number} x The new page X
28352 * @param {Number} y The new page Y
28357 * Fires when this dialog is resized by the user.
28358 * @param {Roo.BasicDialog} this
28359 * @param {Number} width The new width
28360 * @param {Number} height The new height
28364 * @event beforehide
28365 * Fires before this dialog is hidden.
28366 * @param {Roo.BasicDialog} this
28368 "beforehide" : true,
28371 * Fires when this dialog is hidden.
28372 * @param {Roo.BasicDialog} this
28376 * @event beforeshow
28377 * Fires before this dialog is shown.
28378 * @param {Roo.BasicDialog} this
28380 "beforeshow" : true,
28383 * Fires when this dialog is shown.
28384 * @param {Roo.BasicDialog} this
28388 el.on("keydown", this.onKeyDown, this);
28389 el.on("mousedown", this.toFront, this);
28390 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
28392 Roo.DialogManager.register(this);
28393 Roo.BasicDialog.superclass.constructor.call(this);
28396 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
28397 shadowOffset: Roo.isIE ? 6 : 5,
28400 minButtonWidth: 75,
28401 defaultButton: null,
28402 buttonAlign: "right",
28407 * Sets the dialog title text
28408 * @param {String} text The title text to display
28409 * @return {Roo.BasicDialog} this
28411 setTitle : function(text){
28412 this.header.update(text);
28417 closeClick : function(){
28422 collapseClick : function(){
28423 this[this.collapsed ? "expand" : "collapse"]();
28427 * Collapses the dialog to its minimized state (only the title bar is visible).
28428 * Equivalent to the user clicking the collapse dialog button.
28430 collapse : function(){
28431 if(!this.collapsed){
28432 this.collapsed = true;
28433 this.el.addClass("x-dlg-collapsed");
28434 this.restoreHeight = this.el.getHeight();
28435 this.resizeTo(this.el.getWidth(), this.header.getHeight());
28440 * Expands a collapsed dialog back to its normal state. Equivalent to the user
28441 * clicking the expand dialog button.
28443 expand : function(){
28444 if(this.collapsed){
28445 this.collapsed = false;
28446 this.el.removeClass("x-dlg-collapsed");
28447 this.resizeTo(this.el.getWidth(), this.restoreHeight);
28452 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
28453 * @return {Roo.TabPanel} The tabs component
28455 initTabs : function(){
28456 var tabs = this.getTabs();
28457 while(tabs.getTab(0)){
28460 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
28462 tabs.addTab(Roo.id(dom), dom.title);
28470 beforeResize : function(){
28471 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
28475 onResize : function(){
28476 this.refreshSize();
28477 this.syncBodyHeight();
28478 this.adjustAssets();
28480 this.fireEvent("resize", this, this.size.width, this.size.height);
28484 onKeyDown : function(e){
28485 if(this.isVisible()){
28486 this.fireEvent("keydown", this, e);
28491 * Resizes the dialog.
28492 * @param {Number} width
28493 * @param {Number} height
28494 * @return {Roo.BasicDialog} this
28496 resizeTo : function(width, height){
28497 this.el.setSize(width, height);
28498 this.size = {width: width, height: height};
28499 this.syncBodyHeight();
28500 if(this.fixedcenter){
28503 if(this.isVisible()){
28504 this.constrainXY();
28505 this.adjustAssets();
28507 this.fireEvent("resize", this, width, height);
28513 * Resizes the dialog to fit the specified content size.
28514 * @param {Number} width
28515 * @param {Number} height
28516 * @return {Roo.BasicDialog} this
28518 setContentSize : function(w, h){
28519 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
28520 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
28521 //if(!this.el.isBorderBox()){
28522 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
28523 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
28526 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
28527 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
28529 this.resizeTo(w, h);
28534 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
28535 * executed in response to a particular key being pressed while the dialog is active.
28536 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
28537 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
28538 * @param {Function} fn The function to call
28539 * @param {Object} scope (optional) The scope of the function
28540 * @return {Roo.BasicDialog} this
28542 addKeyListener : function(key, fn, scope){
28543 var keyCode, shift, ctrl, alt;
28544 if(typeof key == "object" && !(key instanceof Array)){
28545 keyCode = key["key"];
28546 shift = key["shift"];
28547 ctrl = key["ctrl"];
28552 var handler = function(dlg, e){
28553 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
28554 var k = e.getKey();
28555 if(keyCode instanceof Array){
28556 for(var i = 0, len = keyCode.length; i < len; i++){
28557 if(keyCode[i] == k){
28558 fn.call(scope || window, dlg, k, e);
28564 fn.call(scope || window, dlg, k, e);
28569 this.on("keydown", handler);
28574 * Returns the TabPanel component (creates it if it doesn't exist).
28575 * Note: If you wish to simply check for the existence of tabs without creating them,
28576 * check for a null 'tabs' property.
28577 * @return {Roo.TabPanel} The tabs component
28579 getTabs : function(){
28581 this.el.addClass("x-dlg-auto-tabs");
28582 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
28583 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
28589 * Adds a button to the footer section of the dialog.
28590 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28591 * object or a valid Roo.DomHelper element config
28592 * @param {Function} handler The function called when the button is clicked
28593 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
28594 * @return {Roo.Button} The new button
28596 addButton : function(config, handler, scope){
28597 var dh = Roo.DomHelper;
28599 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
28601 if(!this.btnContainer){
28602 var tb = this.footer.createChild({
28604 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
28605 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28607 this.btnContainer = tb.firstChild.firstChild.firstChild;
28612 minWidth: this.minButtonWidth,
28615 if(typeof config == "string"){
28616 bconfig.text = config;
28619 bconfig.dhconfig = config;
28621 Roo.apply(bconfig, config);
28625 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
28626 bconfig.position = Math.max(0, bconfig.position);
28627 fc = this.btnContainer.childNodes[bconfig.position];
28630 var btn = new Roo.Button(
28632 this.btnContainer.insertBefore(document.createElement("td"),fc)
28633 : this.btnContainer.appendChild(document.createElement("td")),
28634 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
28637 this.syncBodyHeight();
28640 * Array of all the buttons that have been added to this dialog via addButton
28645 this.buttons.push(btn);
28650 * Sets the default button to be focused when the dialog is displayed.
28651 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
28652 * @return {Roo.BasicDialog} this
28654 setDefaultButton : function(btn){
28655 this.defaultButton = btn;
28660 getHeaderFooterHeight : function(safe){
28663 height += this.header.getHeight();
28666 var fm = this.footer.getMargins();
28667 height += (this.footer.getHeight()+fm.top+fm.bottom);
28669 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
28670 height += this.centerBg.getPadding("tb");
28675 syncBodyHeight : function(){
28676 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
28677 var height = this.size.height - this.getHeaderFooterHeight(false);
28678 bd.setHeight(height-bd.getMargins("tb"));
28679 var hh = this.header.getHeight();
28680 var h = this.size.height-hh;
28682 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
28683 bw.setHeight(h-cb.getPadding("tb"));
28684 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
28685 bd.setWidth(bw.getWidth(true));
28687 this.tabs.syncHeight();
28689 this.tabs.el.repaint();
28695 * Restores the previous state of the dialog if Roo.state is configured.
28696 * @return {Roo.BasicDialog} this
28698 restoreState : function(){
28699 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
28700 if(box && box.width){
28701 this.xy = [box.x, box.y];
28702 this.resizeTo(box.width, box.height);
28708 beforeShow : function(){
28710 if(this.fixedcenter){
28711 this.xy = this.el.getCenterXY(true);
28714 Roo.get(document.body).addClass("x-body-masked");
28715 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28718 this.constrainXY();
28722 animShow : function(){
28723 var b = Roo.get(this.animateTarget, true).getBox();
28724 this.proxy.setSize(b.width, b.height);
28725 this.proxy.setLocation(b.x, b.y);
28727 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
28728 true, .35, this.showEl.createDelegate(this));
28732 * Shows the dialog.
28733 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
28734 * @return {Roo.BasicDialog} this
28736 show : function(animateTarget){
28737 if (this.fireEvent("beforeshow", this) === false){
28740 if(this.syncHeightBeforeShow){
28741 this.syncBodyHeight();
28742 }else if(this.firstShow){
28743 this.firstShow = false;
28744 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
28746 this.animateTarget = animateTarget || this.animateTarget;
28747 if(!this.el.isVisible()){
28749 if(this.animateTarget){
28759 showEl : function(){
28761 this.el.setXY(this.xy);
28763 this.adjustAssets(true);
28766 // IE peekaboo bug - fix found by Dave Fenwick
28770 this.fireEvent("show", this);
28774 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
28775 * dialog itself will receive focus.
28777 focus : function(){
28778 if(this.defaultButton){
28779 this.defaultButton.focus();
28781 this.focusEl.focus();
28786 constrainXY : function(){
28787 if(this.constraintoviewport !== false){
28788 if(!this.viewSize){
28789 if(this.container){
28790 var s = this.container.getSize();
28791 this.viewSize = [s.width, s.height];
28793 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
28796 var s = Roo.get(this.container||document).getScroll();
28798 var x = this.xy[0], y = this.xy[1];
28799 var w = this.size.width, h = this.size.height;
28800 var vw = this.viewSize[0], vh = this.viewSize[1];
28801 // only move it if it needs it
28803 // first validate right/bottom
28804 if(x + w > vw+s.left){
28808 if(y + h > vh+s.top){
28812 // then make sure top/left isn't negative
28824 if(this.isVisible()){
28825 this.el.setLocation(x, y);
28826 this.adjustAssets();
28833 onDrag : function(){
28834 if(!this.proxyDrag){
28835 this.xy = this.el.getXY();
28836 this.adjustAssets();
28841 adjustAssets : function(doShow){
28842 var x = this.xy[0], y = this.xy[1];
28843 var w = this.size.width, h = this.size.height;
28844 if(doShow === true){
28846 this.shadow.show(this.el);
28852 if(this.shadow && this.shadow.isVisible()){
28853 this.shadow.show(this.el);
28855 if(this.shim && this.shim.isVisible()){
28856 this.shim.setBounds(x, y, w, h);
28861 adjustViewport : function(w, h){
28863 w = Roo.lib.Dom.getViewWidth();
28864 h = Roo.lib.Dom.getViewHeight();
28867 this.viewSize = [w, h];
28868 if(this.modal && this.mask.isVisible()){
28869 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
28870 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28872 if(this.isVisible()){
28873 this.constrainXY();
28878 * Destroys this dialog and all its supporting elements (including any tabs, shim,
28879 * shadow, proxy, mask, etc.) Also removes all event listeners.
28880 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28882 destroy : function(removeEl){
28883 if(this.isVisible()){
28884 this.animateTarget = null;
28887 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
28889 this.tabs.destroy(removeEl);
28902 for(var i = 0, len = this.buttons.length; i < len; i++){
28903 this.buttons[i].destroy();
28906 this.el.removeAllListeners();
28907 if(removeEl === true){
28908 this.el.update("");
28911 Roo.DialogManager.unregister(this);
28915 startMove : function(){
28916 if(this.proxyDrag){
28919 if(this.constraintoviewport !== false){
28920 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
28925 endMove : function(){
28926 if(!this.proxyDrag){
28927 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
28929 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
28932 this.refreshSize();
28933 this.adjustAssets();
28935 this.fireEvent("move", this, this.xy[0], this.xy[1]);
28939 * Brings this dialog to the front of any other visible dialogs
28940 * @return {Roo.BasicDialog} this
28942 toFront : function(){
28943 Roo.DialogManager.bringToFront(this);
28948 * Sends this dialog to the back (under) of any other visible dialogs
28949 * @return {Roo.BasicDialog} this
28951 toBack : function(){
28952 Roo.DialogManager.sendToBack(this);
28957 * Centers this dialog in the viewport
28958 * @return {Roo.BasicDialog} this
28960 center : function(){
28961 var xy = this.el.getCenterXY(true);
28962 this.moveTo(xy[0], xy[1]);
28967 * Moves the dialog's top-left corner to the specified point
28968 * @param {Number} x
28969 * @param {Number} y
28970 * @return {Roo.BasicDialog} this
28972 moveTo : function(x, y){
28974 if(this.isVisible()){
28975 this.el.setXY(this.xy);
28976 this.adjustAssets();
28982 * Aligns the dialog to the specified element
28983 * @param {String/HTMLElement/Roo.Element} element The element to align to.
28984 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
28985 * @param {Array} offsets (optional) Offset the positioning by [x, y]
28986 * @return {Roo.BasicDialog} this
28988 alignTo : function(element, position, offsets){
28989 this.xy = this.el.getAlignToXY(element, position, offsets);
28990 if(this.isVisible()){
28991 this.el.setXY(this.xy);
28992 this.adjustAssets();
28998 * Anchors an element to another element and realigns it when the window is resized.
28999 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29000 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29001 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29002 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29003 * is a number, it is used as the buffer delay (defaults to 50ms).
29004 * @return {Roo.BasicDialog} this
29006 anchorTo : function(el, alignment, offsets, monitorScroll){
29007 var action = function(){
29008 this.alignTo(el, alignment, offsets);
29010 Roo.EventManager.onWindowResize(action, this);
29011 var tm = typeof monitorScroll;
29012 if(tm != 'undefined'){
29013 Roo.EventManager.on(window, 'scroll', action, this,
29014 {buffer: tm == 'number' ? monitorScroll : 50});
29021 * Returns true if the dialog is visible
29022 * @return {Boolean}
29024 isVisible : function(){
29025 return this.el.isVisible();
29029 animHide : function(callback){
29030 var b = Roo.get(this.animateTarget).getBox();
29032 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29034 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29035 this.hideEl.createDelegate(this, [callback]));
29039 * Hides the dialog.
29040 * @param {Function} callback (optional) Function to call when the dialog is hidden
29041 * @return {Roo.BasicDialog} this
29043 hide : function(callback){
29044 if (this.fireEvent("beforehide", this) === false){
29048 this.shadow.hide();
29053 if(this.animateTarget){
29054 this.animHide(callback);
29057 this.hideEl(callback);
29063 hideEl : function(callback){
29067 Roo.get(document.body).removeClass("x-body-masked");
29069 this.fireEvent("hide", this);
29070 if(typeof callback == "function"){
29076 hideAction : function(){
29077 this.setLeft("-10000px");
29078 this.setTop("-10000px");
29079 this.setStyle("visibility", "hidden");
29083 refreshSize : function(){
29084 this.size = this.el.getSize();
29085 this.xy = this.el.getXY();
29086 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29090 // z-index is managed by the DialogManager and may be overwritten at any time
29091 setZIndex : function(index){
29093 this.mask.setStyle("z-index", index);
29096 this.shim.setStyle("z-index", ++index);
29099 this.shadow.setZIndex(++index);
29101 this.el.setStyle("z-index", ++index);
29103 this.proxy.setStyle("z-index", ++index);
29106 this.resizer.proxy.setStyle("z-index", ++index);
29109 this.lastZIndex = index;
29113 * Returns the element for this dialog
29114 * @return {Roo.Element} The underlying dialog Element
29116 getEl : function(){
29122 * @class Roo.DialogManager
29123 * Provides global access to BasicDialogs that have been created and
29124 * support for z-indexing (layering) multiple open dialogs.
29126 Roo.DialogManager = function(){
29128 var accessList = [];
29132 var sortDialogs = function(d1, d2){
29133 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29137 var orderDialogs = function(){
29138 accessList.sort(sortDialogs);
29139 var seed = Roo.DialogManager.zseed;
29140 for(var i = 0, len = accessList.length; i < len; i++){
29141 var dlg = accessList[i];
29143 dlg.setZIndex(seed + (i*10));
29150 * The starting z-index for BasicDialogs (defaults to 9000)
29151 * @type Number The z-index value
29156 register : function(dlg){
29157 list[dlg.id] = dlg;
29158 accessList.push(dlg);
29162 unregister : function(dlg){
29163 delete list[dlg.id];
29166 if(!accessList.indexOf){
29167 for( i = 0, len = accessList.length; i < len; i++){
29168 if(accessList[i] == dlg){
29169 accessList.splice(i, 1);
29174 i = accessList.indexOf(dlg);
29176 accessList.splice(i, 1);
29182 * Gets a registered dialog by id
29183 * @param {String/Object} id The id of the dialog or a dialog
29184 * @return {Roo.BasicDialog} this
29186 get : function(id){
29187 return typeof id == "object" ? id : list[id];
29191 * Brings the specified dialog to the front
29192 * @param {String/Object} dlg The id of the dialog or a dialog
29193 * @return {Roo.BasicDialog} this
29195 bringToFront : function(dlg){
29196 dlg = this.get(dlg);
29199 dlg._lastAccess = new Date().getTime();
29206 * Sends the specified dialog to the back
29207 * @param {String/Object} dlg The id of the dialog or a dialog
29208 * @return {Roo.BasicDialog} this
29210 sendToBack : function(dlg){
29211 dlg = this.get(dlg);
29212 dlg._lastAccess = -(new Date().getTime());
29218 * Hides all dialogs
29220 hideAll : function(){
29221 for(var id in list){
29222 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29231 * @class Roo.LayoutDialog
29232 * @extends Roo.BasicDialog
29233 * Dialog which provides adjustments for working with a layout in a Dialog.
29234 * Add your necessary layout config options to the dialog's config.<br>
29235 * Example usage (including a nested layout):
29238 dialog = new Roo.LayoutDialog("download-dlg", {
29247 // layout config merges with the dialog config
29249 tabPosition: "top",
29250 alwaysShowTabs: true
29253 dialog.addKeyListener(27, dialog.hide, dialog);
29254 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29255 dialog.addButton("Build It!", this.getDownload, this);
29257 // we can even add nested layouts
29258 var innerLayout = new Roo.BorderLayout("dl-inner", {
29268 innerLayout.beginUpdate();
29269 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29270 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29271 innerLayout.endUpdate(true);
29273 var layout = dialog.getLayout();
29274 layout.beginUpdate();
29275 layout.add("center", new Roo.ContentPanel("standard-panel",
29276 {title: "Download the Source", fitToFrame:true}));
29277 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29278 {title: "Build your own roo.js"}));
29279 layout.getRegion("center").showPanel(sp);
29280 layout.endUpdate();
29284 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29285 * @param {Object} config configuration options
29287 Roo.LayoutDialog = function(el, cfg){
29290 if (typeof(cfg) == 'undefined') {
29291 config = Roo.apply({}, el);
29292 el = Roo.get( document.documentElement || document.body).createChild();
29293 //config.autoCreate = true;
29297 config.autoTabs = false;
29298 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29299 this.body.setStyle({overflow:"hidden", position:"relative"});
29300 this.layout = new Roo.BorderLayout(this.body.dom, config);
29301 this.layout.monitorWindowResize = false;
29302 this.el.addClass("x-dlg-auto-layout");
29303 // fix case when center region overwrites center function
29304 this.center = Roo.BasicDialog.prototype.center;
29305 this.on("show", this.layout.layout, this.layout, true);
29306 if (config.items) {
29307 var xitems = config.items;
29308 delete config.items;
29309 Roo.each(xitems, this.addxtype, this);
29314 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29316 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29319 endUpdate : function(){
29320 this.layout.endUpdate();
29324 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29327 beginUpdate : function(){
29328 this.layout.beginUpdate();
29332 * Get the BorderLayout for this dialog
29333 * @return {Roo.BorderLayout}
29335 getLayout : function(){
29336 return this.layout;
29339 showEl : function(){
29340 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29342 this.layout.layout();
29347 // Use the syncHeightBeforeShow config option to control this automatically
29348 syncBodyHeight : function(){
29349 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29350 if(this.layout){this.layout.layout();}
29354 * Add an xtype element (actually adds to the layout.)
29355 * @return {Object} xdata xtype object data.
29358 addxtype : function(c) {
29359 return this.layout.addxtype(c);
29363 * Ext JS Library 1.1.1
29364 * Copyright(c) 2006-2007, Ext JS, LLC.
29366 * Originally Released Under LGPL - original licence link has changed is not relivant.
29369 * <script type="text/javascript">
29373 * @class Roo.MessageBox
29374 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29378 Roo.Msg.alert('Status', 'Changes saved successfully.');
29380 // Prompt for user data:
29381 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
29383 // process text value...
29387 // Show a dialog using config options:
29389 title:'Save Changes?',
29390 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
29391 buttons: Roo.Msg.YESNOCANCEL,
29398 Roo.MessageBox = function(){
29399 var dlg, opt, mask, waitTimer;
29400 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
29401 var buttons, activeTextEl, bwidth;
29404 var handleButton = function(button){
29406 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
29410 var handleHide = function(){
29411 if(opt && opt.cls){
29412 dlg.el.removeClass(opt.cls);
29415 Roo.TaskMgr.stop(waitTimer);
29421 var updateButtons = function(b){
29424 buttons["ok"].hide();
29425 buttons["cancel"].hide();
29426 buttons["yes"].hide();
29427 buttons["no"].hide();
29428 dlg.footer.dom.style.display = 'none';
29431 dlg.footer.dom.style.display = '';
29432 for(var k in buttons){
29433 if(typeof buttons[k] != "function"){
29436 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
29437 width += buttons[k].el.getWidth()+15;
29447 var handleEsc = function(d, k, e){
29448 if(opt && opt.closable !== false){
29458 * Returns a reference to the underlying {@link Roo.BasicDialog} element
29459 * @return {Roo.BasicDialog} The BasicDialog element
29461 getDialog : function(){
29463 dlg = new Roo.BasicDialog("x-msg-box", {
29468 constraintoviewport:false,
29470 collapsible : false,
29473 width:400, height:100,
29474 buttonAlign:"center",
29475 closeClick : function(){
29476 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
29477 handleButton("no");
29479 handleButton("cancel");
29483 dlg.on("hide", handleHide);
29485 dlg.addKeyListener(27, handleEsc);
29487 var bt = this.buttonText;
29488 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
29489 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
29490 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
29491 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
29492 bodyEl = dlg.body.createChild({
29494 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>'
29496 msgEl = bodyEl.dom.firstChild;
29497 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
29498 textboxEl.enableDisplayMode();
29499 textboxEl.addKeyListener([10,13], function(){
29500 if(dlg.isVisible() && opt && opt.buttons){
29501 if(opt.buttons.ok){
29502 handleButton("ok");
29503 }else if(opt.buttons.yes){
29504 handleButton("yes");
29508 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
29509 textareaEl.enableDisplayMode();
29510 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
29511 progressEl.enableDisplayMode();
29512 var pf = progressEl.dom.firstChild;
29514 pp = Roo.get(pf.firstChild);
29515 pp.setHeight(pf.offsetHeight);
29523 * Updates the message box body text
29524 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
29525 * the XHTML-compliant non-breaking space character '&#160;')
29526 * @return {Roo.MessageBox} This message box
29528 updateText : function(text){
29529 if(!dlg.isVisible() && !opt.width){
29530 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
29532 msgEl.innerHTML = text || ' ';
29533 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
29534 Math.max(opt.minWidth || this.minWidth, bwidth));
29536 activeTextEl.setWidth(w);
29538 if(dlg.isVisible()){
29539 dlg.fixedcenter = false;
29541 dlg.setContentSize(w, bodyEl.getHeight());
29542 if(dlg.isVisible()){
29543 dlg.fixedcenter = true;
29549 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
29550 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
29551 * @param {Number} value Any number between 0 and 1 (e.g., .5)
29552 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
29553 * @return {Roo.MessageBox} This message box
29555 updateProgress : function(value, text){
29557 this.updateText(text);
29559 if (pp) { // weird bug on my firefox - for some reason this is not defined
29560 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
29566 * Returns true if the message box is currently displayed
29567 * @return {Boolean} True if the message box is visible, else false
29569 isVisible : function(){
29570 return dlg && dlg.isVisible();
29574 * Hides the message box if it is displayed
29577 if(this.isVisible()){
29583 * Displays a new message box, or reinitializes an existing message box, based on the config options
29584 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
29585 * The following config object properties are supported:
29587 Property Type Description
29588 ---------- --------------- ------------------------------------------------------------------------------------
29589 animEl String/Element An id or Element from which the message box should animate as it opens and
29590 closes (defaults to undefined)
29591 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
29592 cancel:'Bar'}), or false to not show any buttons (defaults to false)
29593 closable Boolean False to hide the top-right close button (defaults to true). Note that
29594 progress and wait dialogs will ignore this property and always hide the
29595 close button as they can only be closed programmatically.
29596 cls String A custom CSS class to apply to the message box element
29597 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
29598 displayed (defaults to 75)
29599 fn Function A callback function to execute after closing the dialog. The arguments to the
29600 function will be btn (the name of the button that was clicked, if applicable,
29601 e.g. "ok"), and text (the value of the active text field, if applicable).
29602 Progress and wait dialogs will ignore this option since they do not respond to
29603 user actions and can only be closed programmatically, so any required function
29604 should be called by the same code after it closes the dialog.
29605 icon String A CSS class that provides a background image to be used as an icon for
29606 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
29607 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
29608 minWidth Number The minimum width in pixels of the message box (defaults to 100)
29609 modal Boolean False to allow user interaction with the page while the message box is
29610 displayed (defaults to true)
29611 msg String A string that will replace the existing message box body text (defaults
29612 to the XHTML-compliant non-breaking space character ' ')
29613 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
29614 progress Boolean True to display a progress bar (defaults to false)
29615 progressText String The text to display inside the progress bar if progress = true (defaults to '')
29616 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
29617 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
29618 title String The title text
29619 value String The string value to set into the active textbox element if displayed
29620 wait Boolean True to display a progress bar (defaults to false)
29621 width Number The width of the dialog in pixels
29628 msg: 'Please enter your address:',
29630 buttons: Roo.MessageBox.OKCANCEL,
29633 animEl: 'addAddressBtn'
29636 * @param {Object} config Configuration options
29637 * @return {Roo.MessageBox} This message box
29639 show : function(options){
29640 if(this.isVisible()){
29643 var d = this.getDialog();
29645 d.setTitle(opt.title || " ");
29646 d.close.setDisplayed(opt.closable !== false);
29647 activeTextEl = textboxEl;
29648 opt.prompt = opt.prompt || (opt.multiline ? true : false);
29653 textareaEl.setHeight(typeof opt.multiline == "number" ?
29654 opt.multiline : this.defaultTextHeight);
29655 activeTextEl = textareaEl;
29664 progressEl.setDisplayed(opt.progress === true);
29665 this.updateProgress(0);
29666 activeTextEl.dom.value = opt.value || "";
29668 dlg.setDefaultButton(activeTextEl);
29670 var bs = opt.buttons;
29673 db = buttons["ok"];
29674 }else if(bs && bs.yes){
29675 db = buttons["yes"];
29677 dlg.setDefaultButton(db);
29679 bwidth = updateButtons(opt.buttons);
29680 this.updateText(opt.msg);
29682 d.el.addClass(opt.cls);
29684 d.proxyDrag = opt.proxyDrag === true;
29685 d.modal = opt.modal !== false;
29686 d.mask = opt.modal !== false ? mask : false;
29687 if(!d.isVisible()){
29688 // force it to the end of the z-index stack so it gets a cursor in FF
29689 document.body.appendChild(dlg.el.dom);
29690 d.animateTarget = null;
29691 d.show(options.animEl);
29697 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
29698 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
29699 * and closing the message box when the process is complete.
29700 * @param {String} title The title bar text
29701 * @param {String} msg The message box body text
29702 * @return {Roo.MessageBox} This message box
29704 progress : function(title, msg){
29711 minWidth: this.minProgressWidth,
29718 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
29719 * If a callback function is passed it will be called after the user clicks the button, and the
29720 * id of the button that was clicked will be passed as the only parameter to the callback
29721 * (could also be the top-right close button).
29722 * @param {String} title The title bar text
29723 * @param {String} msg The message box body text
29724 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29725 * @param {Object} scope (optional) The scope of the callback function
29726 * @return {Roo.MessageBox} This message box
29728 alert : function(title, msg, fn, scope){
29741 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
29742 * interaction while waiting for a long-running process to complete that does not have defined intervals.
29743 * You are responsible for closing the message box when the process is complete.
29744 * @param {String} msg The message box body text
29745 * @param {String} title (optional) The title bar text
29746 * @return {Roo.MessageBox} This message box
29748 wait : function(msg, title){
29759 waitTimer = Roo.TaskMgr.start({
29761 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
29769 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
29770 * If a callback function is passed it will be called after the user clicks either button, and the id of the
29771 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
29772 * @param {String} title The title bar text
29773 * @param {String} msg The message box body text
29774 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29775 * @param {Object} scope (optional) The scope of the callback function
29776 * @return {Roo.MessageBox} This message box
29778 confirm : function(title, msg, fn, scope){
29782 buttons: this.YESNO,
29791 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
29792 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
29793 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
29794 * (could also be the top-right close button) and the text that was entered will be passed as the two
29795 * parameters to the callback.
29796 * @param {String} title The title bar text
29797 * @param {String} msg The message box body text
29798 * @param {Function} fn (optional) The callback function invoked after the message box is closed
29799 * @param {Object} scope (optional) The scope of the callback function
29800 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
29801 * property, or the height in pixels to create the textbox (defaults to false / single-line)
29802 * @return {Roo.MessageBox} This message box
29804 prompt : function(title, msg, fn, scope, multiline){
29808 buttons: this.OKCANCEL,
29813 multiline: multiline,
29820 * Button config that displays a single OK button
29825 * Button config that displays Yes and No buttons
29828 YESNO : {yes:true, no:true},
29830 * Button config that displays OK and Cancel buttons
29833 OKCANCEL : {ok:true, cancel:true},
29835 * Button config that displays Yes, No and Cancel buttons
29838 YESNOCANCEL : {yes:true, no:true, cancel:true},
29841 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
29844 defaultTextHeight : 75,
29846 * The maximum width in pixels of the message box (defaults to 600)
29851 * The minimum width in pixels of the message box (defaults to 100)
29856 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
29857 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
29860 minProgressWidth : 250,
29862 * An object containing the default button text strings that can be overriden for localized language support.
29863 * Supported properties are: ok, cancel, yes and no.
29864 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
29877 * Shorthand for {@link Roo.MessageBox}
29879 Roo.Msg = Roo.MessageBox;/*
29881 * Ext JS Library 1.1.1
29882 * Copyright(c) 2006-2007, Ext JS, LLC.
29884 * Originally Released Under LGPL - original licence link has changed is not relivant.
29887 * <script type="text/javascript">
29890 * @class Roo.QuickTips
29891 * Provides attractive and customizable tooltips for any element.
29894 Roo.QuickTips = function(){
29895 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
29896 var ce, bd, xy, dd;
29897 var visible = false, disabled = true, inited = false;
29898 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
29900 var onOver = function(e){
29904 var t = e.getTarget();
29905 if(!t || t.nodeType !== 1 || t == document || t == document.body){
29908 if(ce && t == ce.el){
29909 clearTimeout(hideProc);
29912 if(t && tagEls[t.id]){
29913 tagEls[t.id].el = t;
29914 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
29917 var ttp, et = Roo.fly(t);
29918 var ns = cfg.namespace;
29919 if(tm.interceptTitles && t.title){
29922 t.removeAttribute("title");
29923 e.preventDefault();
29925 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
29928 showProc = show.defer(tm.showDelay, tm, [{
29931 width: et.getAttributeNS(ns, cfg.width),
29932 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
29933 title: et.getAttributeNS(ns, cfg.title),
29934 cls: et.getAttributeNS(ns, cfg.cls)
29939 var onOut = function(e){
29940 clearTimeout(showProc);
29941 var t = e.getTarget();
29942 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
29943 hideProc = setTimeout(hide, tm.hideDelay);
29947 var onMove = function(e){
29953 if(tm.trackMouse && ce){
29958 var onDown = function(e){
29959 clearTimeout(showProc);
29960 clearTimeout(hideProc);
29962 if(tm.hideOnClick){
29965 tm.enable.defer(100, tm);
29970 var getPad = function(){
29971 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
29974 var show = function(o){
29978 clearTimeout(dismissProc);
29980 if(removeCls){ // in case manually hidden
29981 el.removeClass(removeCls);
29985 el.addClass(ce.cls);
29986 removeCls = ce.cls;
29989 tipTitle.update(ce.title);
29992 tipTitle.update('');
29995 el.dom.style.width = tm.maxWidth+'px';
29996 //tipBody.dom.style.width = '';
29997 tipBodyText.update(o.text);
29998 var p = getPad(), w = ce.width;
30000 var td = tipBodyText.dom;
30001 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30002 if(aw > tm.maxWidth){
30004 }else if(aw < tm.minWidth){
30010 //tipBody.setWidth(w);
30011 el.setWidth(parseInt(w, 10) + p);
30012 if(ce.autoHide === false){
30013 close.setDisplayed(true);
30018 close.setDisplayed(false);
30024 el.avoidY = xy[1]-18;
30029 el.setStyle("visibility", "visible");
30030 el.fadeIn({callback: afterShow});
30036 var afterShow = function(){
30040 if(tm.autoDismiss && ce.autoHide !== false){
30041 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30046 var hide = function(noanim){
30047 clearTimeout(dismissProc);
30048 clearTimeout(hideProc);
30050 if(el.isVisible()){
30052 if(noanim !== true && tm.animate){
30053 el.fadeOut({callback: afterHide});
30060 var afterHide = function(){
30063 el.removeClass(removeCls);
30070 * @cfg {Number} minWidth
30071 * The minimum width of the quick tip (defaults to 40)
30075 * @cfg {Number} maxWidth
30076 * The maximum width of the quick tip (defaults to 300)
30080 * @cfg {Boolean} interceptTitles
30081 * True to automatically use the element's DOM title value if available (defaults to false)
30083 interceptTitles : false,
30085 * @cfg {Boolean} trackMouse
30086 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30088 trackMouse : false,
30090 * @cfg {Boolean} hideOnClick
30091 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30093 hideOnClick : true,
30095 * @cfg {Number} showDelay
30096 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30100 * @cfg {Number} hideDelay
30101 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30105 * @cfg {Boolean} autoHide
30106 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30107 * Used in conjunction with hideDelay.
30112 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30113 * (defaults to true). Used in conjunction with autoDismissDelay.
30115 autoDismiss : true,
30118 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30120 autoDismissDelay : 5000,
30122 * @cfg {Boolean} animate
30123 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30128 * @cfg {String} title
30129 * Title text to display (defaults to ''). This can be any valid HTML markup.
30132 * @cfg {String} text
30133 * Body text to display (defaults to ''). This can be any valid HTML markup.
30136 * @cfg {String} cls
30137 * A CSS class to apply to the base quick tip element (defaults to '').
30140 * @cfg {Number} width
30141 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30142 * minWidth or maxWidth.
30146 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30147 * or display QuickTips in a page.
30150 tm = Roo.QuickTips;
30151 cfg = tm.tagConfig;
30153 if(!Roo.isReady){ // allow calling of init() before onReady
30154 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30157 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30158 el.fxDefaults = {stopFx: true};
30159 // maximum custom styling
30160 //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>');
30161 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>');
30162 tipTitle = el.child('h3');
30163 tipTitle.enableDisplayMode("block");
30164 tipBody = el.child('div.x-tip-bd');
30165 tipBodyText = el.child('div.x-tip-bd-inner');
30166 //bdLeft = el.child('div.x-tip-bd-left');
30167 //bdRight = el.child('div.x-tip-bd-right');
30168 close = el.child('div.x-tip-close');
30169 close.enableDisplayMode("block");
30170 close.on("click", hide);
30171 var d = Roo.get(document);
30172 d.on("mousedown", onDown);
30173 d.on("mouseover", onOver);
30174 d.on("mouseout", onOut);
30175 d.on("mousemove", onMove);
30176 esc = d.addKeyListener(27, hide);
30179 dd = el.initDD("default", null, {
30180 onDrag : function(){
30184 dd.setHandleElId(tipTitle.id);
30193 * Configures a new quick tip instance and assigns it to a target element. The following config options
30196 Property Type Description
30197 ---------- --------------------- ------------------------------------------------------------------------
30198 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30200 * @param {Object} config The config object
30202 register : function(config){
30203 var cs = config instanceof Array ? config : arguments;
30204 for(var i = 0, len = cs.length; i < len; i++) {
30206 var target = c.target;
30208 if(target instanceof Array){
30209 for(var j = 0, jlen = target.length; j < jlen; j++){
30210 tagEls[target[j]] = c;
30213 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30220 * Removes this quick tip from its element and destroys it.
30221 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30223 unregister : function(el){
30224 delete tagEls[Roo.id(el)];
30228 * Enable this quick tip.
30230 enable : function(){
30231 if(inited && disabled){
30233 if(locks.length < 1){
30240 * Disable this quick tip.
30242 disable : function(){
30244 clearTimeout(showProc);
30245 clearTimeout(hideProc);
30246 clearTimeout(dismissProc);
30254 * Returns true if the quick tip is enabled, else false.
30256 isEnabled : function(){
30263 attribute : "qtip",
30273 // backwards compat
30274 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30276 * Ext JS Library 1.1.1
30277 * Copyright(c) 2006-2007, Ext JS, LLC.
30279 * Originally Released Under LGPL - original licence link has changed is not relivant.
30282 * <script type="text/javascript">
30287 * @class Roo.tree.TreePanel
30288 * @extends Roo.data.Tree
30290 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30291 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30292 * @cfg {Boolean} enableDD true to enable drag and drop
30293 * @cfg {Boolean} enableDrag true to enable just drag
30294 * @cfg {Boolean} enableDrop true to enable just drop
30295 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30296 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30297 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30298 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30299 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30300 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30301 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30302 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30303 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30304 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30305 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30306 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30307 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30308 * @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>
30309 * @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>
30312 * @param {String/HTMLElement/Element} el The container element
30313 * @param {Object} config
30315 Roo.tree.TreePanel = function(el, config){
30317 var loader = false;
30319 root = config.root;
30320 delete config.root;
30322 if (config.loader) {
30323 loader = config.loader;
30324 delete config.loader;
30327 Roo.apply(this, config);
30328 Roo.tree.TreePanel.superclass.constructor.call(this);
30329 this.el = Roo.get(el);
30330 this.el.addClass('x-tree');
30331 //console.log(root);
30333 this.setRootNode( Roo.factory(root, Roo.tree));
30336 this.loader = Roo.factory(loader, Roo.tree);
30339 * Read-only. The id of the container element becomes this TreePanel's id.
30341 this.id = this.el.id;
30344 * @event beforeload
30345 * Fires before a node is loaded, return false to cancel
30346 * @param {Node} node The node being loaded
30348 "beforeload" : true,
30351 * Fires when a node is loaded
30352 * @param {Node} node The node that was loaded
30356 * @event textchange
30357 * Fires when the text for a node is changed
30358 * @param {Node} node The node
30359 * @param {String} text The new text
30360 * @param {String} oldText The old text
30362 "textchange" : true,
30364 * @event beforeexpand
30365 * Fires before a node is expanded, return false to cancel.
30366 * @param {Node} node The node
30367 * @param {Boolean} deep
30368 * @param {Boolean} anim
30370 "beforeexpand" : true,
30372 * @event beforecollapse
30373 * Fires before a node is collapsed, return false to cancel.
30374 * @param {Node} node The node
30375 * @param {Boolean} deep
30376 * @param {Boolean} anim
30378 "beforecollapse" : true,
30381 * Fires when a node is expanded
30382 * @param {Node} node The node
30386 * @event disabledchange
30387 * Fires when the disabled status of a node changes
30388 * @param {Node} node The node
30389 * @param {Boolean} disabled
30391 "disabledchange" : true,
30394 * Fires when a node is collapsed
30395 * @param {Node} node The node
30399 * @event beforeclick
30400 * Fires before click processing on a node. Return false to cancel the default action.
30401 * @param {Node} node The node
30402 * @param {Roo.EventObject} e The event object
30404 "beforeclick":true,
30406 * @event checkchange
30407 * Fires when a node with a checkbox's checked property changes
30408 * @param {Node} this This node
30409 * @param {Boolean} checked
30411 "checkchange":true,
30414 * Fires when a node is clicked
30415 * @param {Node} node The node
30416 * @param {Roo.EventObject} e The event object
30421 * Fires when a node is double clicked
30422 * @param {Node} node The node
30423 * @param {Roo.EventObject} e The event object
30427 * @event contextmenu
30428 * Fires when a node is right clicked
30429 * @param {Node} node The node
30430 * @param {Roo.EventObject} e The event object
30432 "contextmenu":true,
30434 * @event beforechildrenrendered
30435 * Fires right before the child nodes for a node are rendered
30436 * @param {Node} node The node
30438 "beforechildrenrendered":true,
30441 * Fires when a node starts being dragged
30442 * @param {Roo.tree.TreePanel} this
30443 * @param {Roo.tree.TreeNode} node
30444 * @param {event} e The raw browser event
30446 "startdrag" : true,
30449 * Fires when a drag operation is complete
30450 * @param {Roo.tree.TreePanel} this
30451 * @param {Roo.tree.TreeNode} node
30452 * @param {event} e The raw browser event
30457 * Fires when a dragged node is dropped on a valid DD target
30458 * @param {Roo.tree.TreePanel} this
30459 * @param {Roo.tree.TreeNode} node
30460 * @param {DD} dd The dd it was dropped on
30461 * @param {event} e The raw browser event
30465 * @event beforenodedrop
30466 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
30467 * passed to handlers has the following properties:<br />
30468 * <ul style="padding:5px;padding-left:16px;">
30469 * <li>tree - The TreePanel</li>
30470 * <li>target - The node being targeted for the drop</li>
30471 * <li>data - The drag data from the drag source</li>
30472 * <li>point - The point of the drop - append, above or below</li>
30473 * <li>source - The drag source</li>
30474 * <li>rawEvent - Raw mouse event</li>
30475 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
30476 * to be inserted by setting them on this object.</li>
30477 * <li>cancel - Set this to true to cancel the drop.</li>
30479 * @param {Object} dropEvent
30481 "beforenodedrop" : true,
30484 * Fires after a DD object is dropped on a node in this tree. The dropEvent
30485 * passed to handlers has the following properties:<br />
30486 * <ul style="padding:5px;padding-left:16px;">
30487 * <li>tree - The TreePanel</li>
30488 * <li>target - The node being targeted for the drop</li>
30489 * <li>data - The drag data from the drag source</li>
30490 * <li>point - The point of the drop - append, above or below</li>
30491 * <li>source - The drag source</li>
30492 * <li>rawEvent - Raw mouse event</li>
30493 * <li>dropNode - Dropped node(s).</li>
30495 * @param {Object} dropEvent
30499 * @event nodedragover
30500 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
30501 * passed to handlers has the following properties:<br />
30502 * <ul style="padding:5px;padding-left:16px;">
30503 * <li>tree - The TreePanel</li>
30504 * <li>target - The node being targeted for the drop</li>
30505 * <li>data - The drag data from the drag source</li>
30506 * <li>point - The point of the drop - append, above or below</li>
30507 * <li>source - The drag source</li>
30508 * <li>rawEvent - Raw mouse event</li>
30509 * <li>dropNode - Drop node(s) provided by the source.</li>
30510 * <li>cancel - Set this to true to signal drop not allowed.</li>
30512 * @param {Object} dragOverEvent
30514 "nodedragover" : true
30517 if(this.singleExpand){
30518 this.on("beforeexpand", this.restrictExpand, this);
30521 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
30522 rootVisible : true,
30523 animate: Roo.enableFx,
30526 hlDrop : Roo.enableFx,
30530 rendererTip: false,
30532 restrictExpand : function(node){
30533 var p = node.parentNode;
30535 if(p.expandedChild && p.expandedChild.parentNode == p){
30536 p.expandedChild.collapse();
30538 p.expandedChild = node;
30542 // private override
30543 setRootNode : function(node){
30544 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
30545 if(!this.rootVisible){
30546 node.ui = new Roo.tree.RootTreeNodeUI(node);
30552 * Returns the container element for this TreePanel
30554 getEl : function(){
30559 * Returns the default TreeLoader for this TreePanel
30561 getLoader : function(){
30562 return this.loader;
30568 expandAll : function(){
30569 this.root.expand(true);
30573 * Collapse all nodes
30575 collapseAll : function(){
30576 this.root.collapse(true);
30580 * Returns the selection model used by this TreePanel
30582 getSelectionModel : function(){
30583 if(!this.selModel){
30584 this.selModel = new Roo.tree.DefaultSelectionModel();
30586 return this.selModel;
30590 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
30591 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
30592 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
30595 getChecked : function(a, startNode){
30596 startNode = startNode || this.root;
30598 var f = function(){
30599 if(this.attributes.checked){
30600 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
30603 startNode.cascade(f);
30608 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30609 * @param {String} path
30610 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30611 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
30612 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
30614 expandPath : function(path, attr, callback){
30615 attr = attr || "id";
30616 var keys = path.split(this.pathSeparator);
30617 var curNode = this.root;
30618 if(curNode.attributes[attr] != keys[1]){ // invalid root
30620 callback(false, null);
30625 var f = function(){
30626 if(++index == keys.length){
30628 callback(true, curNode);
30632 var c = curNode.findChild(attr, keys[index]);
30635 callback(false, curNode);
30640 c.expand(false, false, f);
30642 curNode.expand(false, false, f);
30646 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
30647 * @param {String} path
30648 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
30649 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
30650 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
30652 selectPath : function(path, attr, callback){
30653 attr = attr || "id";
30654 var keys = path.split(this.pathSeparator);
30655 var v = keys.pop();
30656 if(keys.length > 0){
30657 var f = function(success, node){
30658 if(success && node){
30659 var n = node.findChild(attr, v);
30665 }else if(callback){
30666 callback(false, n);
30670 callback(false, n);
30674 this.expandPath(keys.join(this.pathSeparator), attr, f);
30676 this.root.select();
30678 callback(true, this.root);
30683 getTreeEl : function(){
30688 * Trigger rendering of this TreePanel
30690 render : function(){
30691 if (this.innerCt) {
30692 return this; // stop it rendering more than once!!
30695 this.innerCt = this.el.createChild({tag:"ul",
30696 cls:"x-tree-root-ct " +
30697 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
30699 if(this.containerScroll){
30700 Roo.dd.ScrollManager.register(this.el);
30702 if((this.enableDD || this.enableDrop) && !this.dropZone){
30704 * The dropZone used by this tree if drop is enabled
30705 * @type Roo.tree.TreeDropZone
30707 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
30708 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
30711 if((this.enableDD || this.enableDrag) && !this.dragZone){
30713 * The dragZone used by this tree if drag is enabled
30714 * @type Roo.tree.TreeDragZone
30716 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
30717 ddGroup: this.ddGroup || "TreeDD",
30718 scroll: this.ddScroll
30721 this.getSelectionModel().init(this);
30723 console.log("ROOT not set in tree");
30726 this.root.render();
30727 if(!this.rootVisible){
30728 this.root.renderChildren();
30734 * Ext JS Library 1.1.1
30735 * Copyright(c) 2006-2007, Ext JS, LLC.
30737 * Originally Released Under LGPL - original licence link has changed is not relivant.
30740 * <script type="text/javascript">
30745 * @class Roo.tree.DefaultSelectionModel
30746 * @extends Roo.util.Observable
30747 * The default single selection for a TreePanel.
30749 Roo.tree.DefaultSelectionModel = function(){
30750 this.selNode = null;
30754 * @event selectionchange
30755 * Fires when the selected node changes
30756 * @param {DefaultSelectionModel} this
30757 * @param {TreeNode} node the new selection
30759 "selectionchange" : true,
30762 * @event beforeselect
30763 * Fires before the selected node changes, return false to cancel the change
30764 * @param {DefaultSelectionModel} this
30765 * @param {TreeNode} node the new selection
30766 * @param {TreeNode} node the old selection
30768 "beforeselect" : true
30772 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
30773 init : function(tree){
30775 tree.getTreeEl().on("keydown", this.onKeyDown, this);
30776 tree.on("click", this.onNodeClick, this);
30779 onNodeClick : function(node, e){
30780 if (e.ctrlKey && this.selNode == node) {
30781 this.unselect(node);
30789 * @param {TreeNode} node The node to select
30790 * @return {TreeNode} The selected node
30792 select : function(node){
30793 var last = this.selNode;
30794 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
30796 last.ui.onSelectedChange(false);
30798 this.selNode = node;
30799 node.ui.onSelectedChange(true);
30800 this.fireEvent("selectionchange", this, node, last);
30807 * @param {TreeNode} node The node to unselect
30809 unselect : function(node){
30810 if(this.selNode == node){
30811 this.clearSelections();
30816 * Clear all selections
30818 clearSelections : function(){
30819 var n = this.selNode;
30821 n.ui.onSelectedChange(false);
30822 this.selNode = null;
30823 this.fireEvent("selectionchange", this, null);
30829 * Get the selected node
30830 * @return {TreeNode} The selected node
30832 getSelectedNode : function(){
30833 return this.selNode;
30837 * Returns true if the node is selected
30838 * @param {TreeNode} node The node to check
30839 * @return {Boolean}
30841 isSelected : function(node){
30842 return this.selNode == node;
30846 * Selects the node above the selected node in the tree, intelligently walking the nodes
30847 * @return TreeNode The new selection
30849 selectPrevious : function(){
30850 var s = this.selNode || this.lastSelNode;
30854 var ps = s.previousSibling;
30856 if(!ps.isExpanded() || ps.childNodes.length < 1){
30857 return this.select(ps);
30859 var lc = ps.lastChild;
30860 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
30863 return this.select(lc);
30865 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
30866 return this.select(s.parentNode);
30872 * Selects the node above the selected node in the tree, intelligently walking the nodes
30873 * @return TreeNode The new selection
30875 selectNext : function(){
30876 var s = this.selNode || this.lastSelNode;
30880 if(s.firstChild && s.isExpanded()){
30881 return this.select(s.firstChild);
30882 }else if(s.nextSibling){
30883 return this.select(s.nextSibling);
30884 }else if(s.parentNode){
30886 s.parentNode.bubble(function(){
30887 if(this.nextSibling){
30888 newS = this.getOwnerTree().selModel.select(this.nextSibling);
30897 onKeyDown : function(e){
30898 var s = this.selNode || this.lastSelNode;
30899 // undesirable, but required
30904 var k = e.getKey();
30912 this.selectPrevious();
30915 e.preventDefault();
30916 if(s.hasChildNodes()){
30917 if(!s.isExpanded()){
30919 }else if(s.firstChild){
30920 this.select(s.firstChild, e);
30925 e.preventDefault();
30926 if(s.hasChildNodes() && s.isExpanded()){
30928 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
30929 this.select(s.parentNode, e);
30937 * @class Roo.tree.MultiSelectionModel
30938 * @extends Roo.util.Observable
30939 * Multi selection for a TreePanel.
30941 Roo.tree.MultiSelectionModel = function(){
30942 this.selNodes = [];
30946 * @event selectionchange
30947 * Fires when the selected nodes change
30948 * @param {MultiSelectionModel} this
30949 * @param {Array} nodes Array of the selected nodes
30951 "selectionchange" : true
30955 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
30956 init : function(tree){
30958 tree.getTreeEl().on("keydown", this.onKeyDown, this);
30959 tree.on("click", this.onNodeClick, this);
30962 onNodeClick : function(node, e){
30963 this.select(node, e, e.ctrlKey);
30968 * @param {TreeNode} node The node to select
30969 * @param {EventObject} e (optional) An event associated with the selection
30970 * @param {Boolean} keepExisting True to retain existing selections
30971 * @return {TreeNode} The selected node
30973 select : function(node, e, keepExisting){
30974 if(keepExisting !== true){
30975 this.clearSelections(true);
30977 if(this.isSelected(node)){
30978 this.lastSelNode = node;
30981 this.selNodes.push(node);
30982 this.selMap[node.id] = node;
30983 this.lastSelNode = node;
30984 node.ui.onSelectedChange(true);
30985 this.fireEvent("selectionchange", this, this.selNodes);
30991 * @param {TreeNode} node The node to unselect
30993 unselect : function(node){
30994 if(this.selMap[node.id]){
30995 node.ui.onSelectedChange(false);
30996 var sn = this.selNodes;
30999 index = sn.indexOf(node);
31001 for(var i = 0, len = sn.length; i < len; i++){
31009 this.selNodes.splice(index, 1);
31011 delete this.selMap[node.id];
31012 this.fireEvent("selectionchange", this, this.selNodes);
31017 * Clear all selections
31019 clearSelections : function(suppressEvent){
31020 var sn = this.selNodes;
31022 for(var i = 0, len = sn.length; i < len; i++){
31023 sn[i].ui.onSelectedChange(false);
31025 this.selNodes = [];
31027 if(suppressEvent !== true){
31028 this.fireEvent("selectionchange", this, this.selNodes);
31034 * Returns true if the node is selected
31035 * @param {TreeNode} node The node to check
31036 * @return {Boolean}
31038 isSelected : function(node){
31039 return this.selMap[node.id] ? true : false;
31043 * Returns an array of the selected nodes
31046 getSelectedNodes : function(){
31047 return this.selNodes;
31050 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31052 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31054 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31057 * Ext JS Library 1.1.1
31058 * Copyright(c) 2006-2007, Ext JS, LLC.
31060 * Originally Released Under LGPL - original licence link has changed is not relivant.
31063 * <script type="text/javascript">
31067 * @class Roo.tree.TreeNode
31068 * @extends Roo.data.Node
31069 * @cfg {String} text The text for this node
31070 * @cfg {Boolean} expanded true to start the node expanded
31071 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31072 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31073 * @cfg {Boolean} disabled true to start the node disabled
31074 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31075 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31076 * @cfg {String} cls A css class to be added to the node
31077 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31078 * @cfg {String} href URL of the link used for the node (defaults to #)
31079 * @cfg {String} hrefTarget target frame for the link
31080 * @cfg {String} qtip An Ext QuickTip for the node
31081 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31082 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31083 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31084 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31085 * (defaults to undefined with no checkbox rendered)
31087 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31089 Roo.tree.TreeNode = function(attributes){
31090 attributes = attributes || {};
31091 if(typeof attributes == "string"){
31092 attributes = {text: attributes};
31094 this.childrenRendered = false;
31095 this.rendered = false;
31096 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31097 this.expanded = attributes.expanded === true;
31098 this.isTarget = attributes.isTarget !== false;
31099 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31100 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31103 * Read-only. The text for this node. To change it use setText().
31106 this.text = attributes.text;
31108 * True if this node is disabled.
31111 this.disabled = attributes.disabled === true;
31115 * @event textchange
31116 * Fires when the text for this node is changed
31117 * @param {Node} this This node
31118 * @param {String} text The new text
31119 * @param {String} oldText The old text
31121 "textchange" : true,
31123 * @event beforeexpand
31124 * Fires before this node is expanded, return false to cancel.
31125 * @param {Node} this This node
31126 * @param {Boolean} deep
31127 * @param {Boolean} anim
31129 "beforeexpand" : true,
31131 * @event beforecollapse
31132 * Fires before this node is collapsed, return false to cancel.
31133 * @param {Node} this This node
31134 * @param {Boolean} deep
31135 * @param {Boolean} anim
31137 "beforecollapse" : true,
31140 * Fires when this node is expanded
31141 * @param {Node} this This node
31145 * @event disabledchange
31146 * Fires when the disabled status of this node changes
31147 * @param {Node} this This node
31148 * @param {Boolean} disabled
31150 "disabledchange" : true,
31153 * Fires when this node is collapsed
31154 * @param {Node} this This node
31158 * @event beforeclick
31159 * Fires before click processing. Return false to cancel the default action.
31160 * @param {Node} this This node
31161 * @param {Roo.EventObject} e The event object
31163 "beforeclick":true,
31165 * @event checkchange
31166 * Fires when a node with a checkbox's checked property changes
31167 * @param {Node} this This node
31168 * @param {Boolean} checked
31170 "checkchange":true,
31173 * Fires when this node is clicked
31174 * @param {Node} this This node
31175 * @param {Roo.EventObject} e The event object
31180 * Fires when this node is double clicked
31181 * @param {Node} this This node
31182 * @param {Roo.EventObject} e The event object
31186 * @event contextmenu
31187 * Fires when this node is right clicked
31188 * @param {Node} this This node
31189 * @param {Roo.EventObject} e The event object
31191 "contextmenu":true,
31193 * @event beforechildrenrendered
31194 * Fires right before the child nodes for this node are rendered
31195 * @param {Node} this This node
31197 "beforechildrenrendered":true
31200 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31203 * Read-only. The UI for this node
31206 this.ui = new uiClass(this);
31208 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31209 preventHScroll: true,
31211 * Returns true if this node is expanded
31212 * @return {Boolean}
31214 isExpanded : function(){
31215 return this.expanded;
31219 * Returns the UI object for this node
31220 * @return {TreeNodeUI}
31222 getUI : function(){
31226 // private override
31227 setFirstChild : function(node){
31228 var of = this.firstChild;
31229 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31230 if(this.childrenRendered && of && node != of){
31231 of.renderIndent(true, true);
31234 this.renderIndent(true, true);
31238 // private override
31239 setLastChild : function(node){
31240 var ol = this.lastChild;
31241 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31242 if(this.childrenRendered && ol && node != ol){
31243 ol.renderIndent(true, true);
31246 this.renderIndent(true, true);
31250 // these methods are overridden to provide lazy rendering support
31251 // private override
31252 appendChild : function(){
31253 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31254 if(node && this.childrenRendered){
31257 this.ui.updateExpandIcon();
31261 // private override
31262 removeChild : function(node){
31263 this.ownerTree.getSelectionModel().unselect(node);
31264 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31265 // if it's been rendered remove dom node
31266 if(this.childrenRendered){
31269 if(this.childNodes.length < 1){
31270 this.collapse(false, false);
31272 this.ui.updateExpandIcon();
31274 if(!this.firstChild) {
31275 this.childrenRendered = false;
31280 // private override
31281 insertBefore : function(node, refNode){
31282 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31283 if(newNode && refNode && this.childrenRendered){
31286 this.ui.updateExpandIcon();
31291 * Sets the text for this node
31292 * @param {String} text
31294 setText : function(text){
31295 var oldText = this.text;
31297 this.attributes.text = text;
31298 if(this.rendered){ // event without subscribing
31299 this.ui.onTextChange(this, text, oldText);
31301 this.fireEvent("textchange", this, text, oldText);
31305 * Triggers selection of this node
31307 select : function(){
31308 this.getOwnerTree().getSelectionModel().select(this);
31312 * Triggers deselection of this node
31314 unselect : function(){
31315 this.getOwnerTree().getSelectionModel().unselect(this);
31319 * Returns true if this node is selected
31320 * @return {Boolean}
31322 isSelected : function(){
31323 return this.getOwnerTree().getSelectionModel().isSelected(this);
31327 * Expand this node.
31328 * @param {Boolean} deep (optional) True to expand all children as well
31329 * @param {Boolean} anim (optional) false to cancel the default animation
31330 * @param {Function} callback (optional) A callback to be called when
31331 * expanding this node completes (does not wait for deep expand to complete).
31332 * Called with 1 parameter, this node.
31334 expand : function(deep, anim, callback){
31335 if(!this.expanded){
31336 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
31339 if(!this.childrenRendered){
31340 this.renderChildren();
31342 this.expanded = true;
31343 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
31344 this.ui.animExpand(function(){
31345 this.fireEvent("expand", this);
31346 if(typeof callback == "function"){
31350 this.expandChildNodes(true);
31352 }.createDelegate(this));
31356 this.fireEvent("expand", this);
31357 if(typeof callback == "function"){
31362 if(typeof callback == "function"){
31367 this.expandChildNodes(true);
31371 isHiddenRoot : function(){
31372 return this.isRoot && !this.getOwnerTree().rootVisible;
31376 * Collapse this node.
31377 * @param {Boolean} deep (optional) True to collapse all children as well
31378 * @param {Boolean} anim (optional) false to cancel the default animation
31380 collapse : function(deep, anim){
31381 if(this.expanded && !this.isHiddenRoot()){
31382 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
31385 this.expanded = false;
31386 if((this.getOwnerTree().animate && anim !== false) || anim){
31387 this.ui.animCollapse(function(){
31388 this.fireEvent("collapse", this);
31390 this.collapseChildNodes(true);
31392 }.createDelegate(this));
31395 this.ui.collapse();
31396 this.fireEvent("collapse", this);
31400 var cs = this.childNodes;
31401 for(var i = 0, len = cs.length; i < len; i++) {
31402 cs[i].collapse(true, false);
31408 delayedExpand : function(delay){
31409 if(!this.expandProcId){
31410 this.expandProcId = this.expand.defer(delay, this);
31415 cancelExpand : function(){
31416 if(this.expandProcId){
31417 clearTimeout(this.expandProcId);
31419 this.expandProcId = false;
31423 * Toggles expanded/collapsed state of the node
31425 toggle : function(){
31434 * Ensures all parent nodes are expanded
31436 ensureVisible : function(callback){
31437 var tree = this.getOwnerTree();
31438 tree.expandPath(this.parentNode.getPath(), false, function(){
31439 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
31440 Roo.callback(callback);
31441 }.createDelegate(this));
31445 * Expand all child nodes
31446 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
31448 expandChildNodes : function(deep){
31449 var cs = this.childNodes;
31450 for(var i = 0, len = cs.length; i < len; i++) {
31451 cs[i].expand(deep);
31456 * Collapse all child nodes
31457 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
31459 collapseChildNodes : function(deep){
31460 var cs = this.childNodes;
31461 for(var i = 0, len = cs.length; i < len; i++) {
31462 cs[i].collapse(deep);
31467 * Disables this node
31469 disable : function(){
31470 this.disabled = true;
31472 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31473 this.ui.onDisableChange(this, true);
31475 this.fireEvent("disabledchange", this, true);
31479 * Enables this node
31481 enable : function(){
31482 this.disabled = false;
31483 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
31484 this.ui.onDisableChange(this, false);
31486 this.fireEvent("disabledchange", this, false);
31490 renderChildren : function(suppressEvent){
31491 if(suppressEvent !== false){
31492 this.fireEvent("beforechildrenrendered", this);
31494 var cs = this.childNodes;
31495 for(var i = 0, len = cs.length; i < len; i++){
31496 cs[i].render(true);
31498 this.childrenRendered = true;
31502 sort : function(fn, scope){
31503 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
31504 if(this.childrenRendered){
31505 var cs = this.childNodes;
31506 for(var i = 0, len = cs.length; i < len; i++){
31507 cs[i].render(true);
31513 render : function(bulkRender){
31514 this.ui.render(bulkRender);
31515 if(!this.rendered){
31516 this.rendered = true;
31518 this.expanded = false;
31519 this.expand(false, false);
31525 renderIndent : function(deep, refresh){
31527 this.ui.childIndent = null;
31529 this.ui.renderIndent();
31530 if(deep === true && this.childrenRendered){
31531 var cs = this.childNodes;
31532 for(var i = 0, len = cs.length; i < len; i++){
31533 cs[i].renderIndent(true, refresh);
31539 * Ext JS Library 1.1.1
31540 * Copyright(c) 2006-2007, Ext JS, LLC.
31542 * Originally Released Under LGPL - original licence link has changed is not relivant.
31545 * <script type="text/javascript">
31549 * @class Roo.tree.AsyncTreeNode
31550 * @extends Roo.tree.TreeNode
31551 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
31553 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31555 Roo.tree.AsyncTreeNode = function(config){
31556 this.loaded = false;
31557 this.loading = false;
31558 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
31560 * @event beforeload
31561 * Fires before this node is loaded, return false to cancel
31562 * @param {Node} this This node
31564 this.addEvents({'beforeload':true, 'load': true});
31567 * Fires when this node is loaded
31568 * @param {Node} this This node
31571 * The loader used by this node (defaults to using the tree's defined loader)
31576 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
31577 expand : function(deep, anim, callback){
31578 if(this.loading){ // if an async load is already running, waiting til it's done
31580 var f = function(){
31581 if(!this.loading){ // done loading
31582 clearInterval(timer);
31583 this.expand(deep, anim, callback);
31585 }.createDelegate(this);
31586 timer = setInterval(f, 200);
31590 if(this.fireEvent("beforeload", this) === false){
31593 this.loading = true;
31594 this.ui.beforeLoad(this);
31595 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
31597 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
31601 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
31605 * Returns true if this node is currently loading
31606 * @return {Boolean}
31608 isLoading : function(){
31609 return this.loading;
31612 loadComplete : function(deep, anim, callback){
31613 this.loading = false;
31614 this.loaded = true;
31615 this.ui.afterLoad(this);
31616 this.fireEvent("load", this);
31617 this.expand(deep, anim, callback);
31621 * Returns true if this node has been loaded
31622 * @return {Boolean}
31624 isLoaded : function(){
31625 return this.loaded;
31628 hasChildNodes : function(){
31629 if(!this.isLeaf() && !this.loaded){
31632 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
31637 * Trigger a reload for this node
31638 * @param {Function} callback
31640 reload : function(callback){
31641 this.collapse(false, false);
31642 while(this.firstChild){
31643 this.removeChild(this.firstChild);
31645 this.childrenRendered = false;
31646 this.loaded = false;
31647 if(this.isHiddenRoot()){
31648 this.expanded = false;
31650 this.expand(false, false, callback);
31654 * Ext JS Library 1.1.1
31655 * Copyright(c) 2006-2007, Ext JS, LLC.
31657 * Originally Released Under LGPL - original licence link has changed is not relivant.
31660 * <script type="text/javascript">
31664 * @class Roo.tree.TreeNodeUI
31666 * @param {Object} node The node to render
31667 * The TreeNode UI implementation is separate from the
31668 * tree implementation. Unless you are customizing the tree UI,
31669 * you should never have to use this directly.
31671 Roo.tree.TreeNodeUI = function(node){
31673 this.rendered = false;
31674 this.animating = false;
31675 this.emptyIcon = Roo.BLANK_IMAGE_URL;
31678 Roo.tree.TreeNodeUI.prototype = {
31679 removeChild : function(node){
31681 this.ctNode.removeChild(node.ui.getEl());
31685 beforeLoad : function(){
31686 this.addClass("x-tree-node-loading");
31689 afterLoad : function(){
31690 this.removeClass("x-tree-node-loading");
31693 onTextChange : function(node, text, oldText){
31695 this.textNode.innerHTML = text;
31699 onDisableChange : function(node, state){
31700 this.disabled = state;
31702 this.addClass("x-tree-node-disabled");
31704 this.removeClass("x-tree-node-disabled");
31708 onSelectedChange : function(state){
31711 this.addClass("x-tree-selected");
31714 this.removeClass("x-tree-selected");
31718 onMove : function(tree, node, oldParent, newParent, index, refNode){
31719 this.childIndent = null;
31721 var targetNode = newParent.ui.getContainer();
31722 if(!targetNode){//target not rendered
31723 this.holder = document.createElement("div");
31724 this.holder.appendChild(this.wrap);
31727 var insertBefore = refNode ? refNode.ui.getEl() : null;
31729 targetNode.insertBefore(this.wrap, insertBefore);
31731 targetNode.appendChild(this.wrap);
31733 this.node.renderIndent(true);
31737 addClass : function(cls){
31739 Roo.fly(this.elNode).addClass(cls);
31743 removeClass : function(cls){
31745 Roo.fly(this.elNode).removeClass(cls);
31749 remove : function(){
31751 this.holder = document.createElement("div");
31752 this.holder.appendChild(this.wrap);
31756 fireEvent : function(){
31757 return this.node.fireEvent.apply(this.node, arguments);
31760 initEvents : function(){
31761 this.node.on("move", this.onMove, this);
31762 var E = Roo.EventManager;
31763 var a = this.anchor;
31765 var el = Roo.fly(a, '_treeui');
31767 if(Roo.isOpera){ // opera render bug ignores the CSS
31768 el.setStyle("text-decoration", "none");
31771 el.on("click", this.onClick, this);
31772 el.on("dblclick", this.onDblClick, this);
31775 Roo.EventManager.on(this.checkbox,
31776 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
31779 el.on("contextmenu", this.onContextMenu, this);
31781 var icon = Roo.fly(this.iconNode);
31782 icon.on("click", this.onClick, this);
31783 icon.on("dblclick", this.onDblClick, this);
31784 icon.on("contextmenu", this.onContextMenu, this);
31785 E.on(this.ecNode, "click", this.ecClick, this, true);
31787 if(this.node.disabled){
31788 this.addClass("x-tree-node-disabled");
31790 if(this.node.hidden){
31791 this.addClass("x-tree-node-disabled");
31793 var ot = this.node.getOwnerTree();
31794 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
31795 if(dd && (!this.node.isRoot || ot.rootVisible)){
31796 Roo.dd.Registry.register(this.elNode, {
31798 handles: this.getDDHandles(),
31804 getDDHandles : function(){
31805 return [this.iconNode, this.textNode];
31810 this.wrap.style.display = "none";
31816 this.wrap.style.display = "";
31820 onContextMenu : function(e){
31821 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
31822 e.preventDefault();
31824 this.fireEvent("contextmenu", this.node, e);
31828 onClick : function(e){
31833 if(this.fireEvent("beforeclick", this.node, e) !== false){
31834 if(!this.disabled && this.node.attributes.href){
31835 this.fireEvent("click", this.node, e);
31838 e.preventDefault();
31843 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
31844 this.node.toggle();
31847 this.fireEvent("click", this.node, e);
31853 onDblClick : function(e){
31854 e.preventDefault();
31859 this.toggleCheck();
31861 if(!this.animating && this.node.hasChildNodes()){
31862 this.node.toggle();
31864 this.fireEvent("dblclick", this.node, e);
31867 onCheckChange : function(){
31868 var checked = this.checkbox.checked;
31869 this.node.attributes.checked = checked;
31870 this.fireEvent('checkchange', this.node, checked);
31873 ecClick : function(e){
31874 if(!this.animating && this.node.hasChildNodes()){
31875 this.node.toggle();
31879 startDrop : function(){
31880 this.dropping = true;
31883 // delayed drop so the click event doesn't get fired on a drop
31884 endDrop : function(){
31885 setTimeout(function(){
31886 this.dropping = false;
31887 }.createDelegate(this), 50);
31890 expand : function(){
31891 this.updateExpandIcon();
31892 this.ctNode.style.display = "";
31895 focus : function(){
31896 if(!this.node.preventHScroll){
31897 try{this.anchor.focus();
31899 }else if(!Roo.isIE){
31901 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
31902 var l = noscroll.scrollLeft;
31903 this.anchor.focus();
31904 noscroll.scrollLeft = l;
31909 toggleCheck : function(value){
31910 var cb = this.checkbox;
31912 cb.checked = (value === undefined ? !cb.checked : value);
31918 this.anchor.blur();
31922 animExpand : function(callback){
31923 var ct = Roo.get(this.ctNode);
31925 if(!this.node.hasChildNodes()){
31926 this.updateExpandIcon();
31927 this.ctNode.style.display = "";
31928 Roo.callback(callback);
31931 this.animating = true;
31932 this.updateExpandIcon();
31935 callback : function(){
31936 this.animating = false;
31937 Roo.callback(callback);
31940 duration: this.node.ownerTree.duration || .25
31944 highlight : function(){
31945 var tree = this.node.getOwnerTree();
31946 Roo.fly(this.wrap).highlight(
31947 tree.hlColor || "C3DAF9",
31948 {endColor: tree.hlBaseColor}
31952 collapse : function(){
31953 this.updateExpandIcon();
31954 this.ctNode.style.display = "none";
31957 animCollapse : function(callback){
31958 var ct = Roo.get(this.ctNode);
31959 ct.enableDisplayMode('block');
31962 this.animating = true;
31963 this.updateExpandIcon();
31966 callback : function(){
31967 this.animating = false;
31968 Roo.callback(callback);
31971 duration: this.node.ownerTree.duration || .25
31975 getContainer : function(){
31976 return this.ctNode;
31979 getEl : function(){
31983 appendDDGhost : function(ghostNode){
31984 ghostNode.appendChild(this.elNode.cloneNode(true));
31987 getDDRepairXY : function(){
31988 return Roo.lib.Dom.getXY(this.iconNode);
31991 onRender : function(){
31995 render : function(bulkRender){
31996 var n = this.node, a = n.attributes;
31997 var targetNode = n.parentNode ?
31998 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32000 if(!this.rendered){
32001 this.rendered = true;
32003 this.renderElements(n, a, targetNode, bulkRender);
32006 if(this.textNode.setAttributeNS){
32007 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32009 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32012 this.textNode.setAttribute("ext:qtip", a.qtip);
32014 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32017 }else if(a.qtipCfg){
32018 a.qtipCfg.target = Roo.id(this.textNode);
32019 Roo.QuickTips.register(a.qtipCfg);
32022 if(!this.node.expanded){
32023 this.updateExpandIcon();
32026 if(bulkRender === true) {
32027 targetNode.appendChild(this.wrap);
32032 renderElements : function(n, a, targetNode, bulkRender){
32033 // add some indent caching, this helps performance when rendering a large tree
32034 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32035 var t = n.getOwnerTree();
32036 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32037 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32038 var cb = typeof a.checked == 'boolean';
32039 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32040 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32041 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32042 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32043 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32044 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32045 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32046 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32047 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32048 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32051 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32052 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32053 n.nextSibling.ui.getEl(), buf.join(""));
32055 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32058 this.elNode = this.wrap.childNodes[0];
32059 this.ctNode = this.wrap.childNodes[1];
32060 var cs = this.elNode.childNodes;
32061 this.indentNode = cs[0];
32062 this.ecNode = cs[1];
32063 this.iconNode = cs[2];
32066 this.checkbox = cs[3];
32069 this.anchor = cs[index];
32070 this.textNode = cs[index].firstChild;
32073 getAnchor : function(){
32074 return this.anchor;
32077 getTextEl : function(){
32078 return this.textNode;
32081 getIconEl : function(){
32082 return this.iconNode;
32085 isChecked : function(){
32086 return this.checkbox ? this.checkbox.checked : false;
32089 updateExpandIcon : function(){
32091 var n = this.node, c1, c2;
32092 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32093 var hasChild = n.hasChildNodes();
32097 c1 = "x-tree-node-collapsed";
32098 c2 = "x-tree-node-expanded";
32101 c1 = "x-tree-node-expanded";
32102 c2 = "x-tree-node-collapsed";
32105 this.removeClass("x-tree-node-leaf");
32106 this.wasLeaf = false;
32108 if(this.c1 != c1 || this.c2 != c2){
32109 Roo.fly(this.elNode).replaceClass(c1, c2);
32110 this.c1 = c1; this.c2 = c2;
32114 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32117 this.wasLeaf = true;
32120 var ecc = "x-tree-ec-icon "+cls;
32121 if(this.ecc != ecc){
32122 this.ecNode.className = ecc;
32128 getChildIndent : function(){
32129 if(!this.childIndent){
32133 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32135 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32137 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32142 this.childIndent = buf.join("");
32144 return this.childIndent;
32147 renderIndent : function(){
32150 var p = this.node.parentNode;
32152 indent = p.ui.getChildIndent();
32154 if(this.indentMarkup != indent){ // don't rerender if not required
32155 this.indentNode.innerHTML = indent;
32156 this.indentMarkup = indent;
32158 this.updateExpandIcon();
32163 Roo.tree.RootTreeNodeUI = function(){
32164 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32166 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32167 render : function(){
32168 if(!this.rendered){
32169 var targetNode = this.node.ownerTree.innerCt.dom;
32170 this.node.expanded = true;
32171 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32172 this.wrap = this.ctNode = targetNode.firstChild;
32175 collapse : function(){
32177 expand : function(){
32181 * Ext JS Library 1.1.1
32182 * Copyright(c) 2006-2007, Ext JS, LLC.
32184 * Originally Released Under LGPL - original licence link has changed is not relivant.
32187 * <script type="text/javascript">
32190 * @class Roo.tree.TreeLoader
32191 * @extends Roo.util.Observable
32192 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32193 * nodes from a specified URL. The response must be a javascript Array definition
32194 * who's elements are node definition objects. eg:
32196 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
32197 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
32200 * A server request is sent, and child nodes are loaded only when a node is expanded.
32201 * The loading node's id is passed to the server under the parameter name "node" to
32202 * enable the server to produce the correct child nodes.
32204 * To pass extra parameters, an event handler may be attached to the "beforeload"
32205 * event, and the parameters specified in the TreeLoader's baseParams property:
32207 myTreeLoader.on("beforeload", function(treeLoader, node) {
32208 this.baseParams.category = node.attributes.category;
32211 * This would pass an HTTP parameter called "category" to the server containing
32212 * the value of the Node's "category" attribute.
32214 * Creates a new Treeloader.
32215 * @param {Object} config A config object containing config properties.
32217 Roo.tree.TreeLoader = function(config){
32218 this.baseParams = {};
32219 this.requestMethod = "POST";
32220 Roo.apply(this, config);
32224 * @event beforeload
32225 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32226 * @param {Object} This TreeLoader object.
32227 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32228 * @param {Object} callback The callback function specified in the {@link #load} call.
32230 "beforeload" : true,
32233 * Fires when the node has been successfuly loaded.
32234 * @param {Object} This TreeLoader object.
32235 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32236 * @param {Object} response The response object containing the data from the server.
32240 * @event loadexception
32241 * Fires if the network request failed.
32242 * @param {Object} This TreeLoader object.
32243 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32244 * @param {Object} response The response object containing the data from the server.
32246 "loadexception" : true
32249 Roo.tree.TreeLoader.superclass.constructor.call(this);
32252 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32254 * @cfg {String} dataUrl The URL from which to request a Json string which
32255 * specifies an array of node definition object representing the child nodes
32259 * @cfg {Object} baseParams (optional) An object containing properties which
32260 * specify HTTP parameters to be passed to each request for child nodes.
32263 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32264 * created by this loader. If the attributes sent by the server have an attribute in this object,
32265 * they take priority.
32268 * @cfg {Object} uiProviders (optional) An object containing properties which
32269 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32270 * <i>uiProvider</i> attribute of a returned child node is a string rather
32271 * than a reference to a TreeNodeUI implementation, this that string value
32272 * is used as a property name in the uiProviders object. You can define the provider named
32273 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32278 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32279 * child nodes before loading.
32281 clearOnLoad : true,
32284 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32285 * property on loading, rather than expecting an array. (eg. more compatible to a standard
32286 * Grid query { data : [ .....] }
32291 * @cfg {String} queryParam (optional)
32292 * Name of the query as it will be passed on the querystring (defaults to 'node')
32293 * eg. the request will be ?node=[id]
32300 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
32301 * This is called automatically when a node is expanded, but may be used to reload
32302 * a node (or append new children if the {@link #clearOnLoad} option is false.)
32303 * @param {Roo.tree.TreeNode} node
32304 * @param {Function} callback
32306 load : function(node, callback){
32307 if(this.clearOnLoad){
32308 while(node.firstChild){
32309 node.removeChild(node.firstChild);
32312 if(node.attributes.children){ // preloaded json children
32313 var cs = node.attributes.children;
32314 for(var i = 0, len = cs.length; i < len; i++){
32315 node.appendChild(this.createNode(cs[i]));
32317 if(typeof callback == "function"){
32320 }else if(this.dataUrl){
32321 this.requestData(node, callback);
32325 getParams: function(node){
32326 var buf = [], bp = this.baseParams;
32327 for(var key in bp){
32328 if(typeof bp[key] != "function"){
32329 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
32332 var n = this.queryParam === false ? 'node' : this.queryParam;
32333 buf.push(n + "=", encodeURIComponent(node.id));
32334 return buf.join("");
32337 requestData : function(node, callback){
32338 if(this.fireEvent("beforeload", this, node, callback) !== false){
32339 this.transId = Roo.Ajax.request({
32340 method:this.requestMethod,
32341 url: this.dataUrl||this.url,
32342 success: this.handleResponse,
32343 failure: this.handleFailure,
32345 argument: {callback: callback, node: node},
32346 params: this.getParams(node)
32349 // if the load is cancelled, make sure we notify
32350 // the node that we are done
32351 if(typeof callback == "function"){
32357 isLoading : function(){
32358 return this.transId ? true : false;
32361 abort : function(){
32362 if(this.isLoading()){
32363 Roo.Ajax.abort(this.transId);
32368 * Override this function for custom TreeNode node implementation
32370 createNode : function(attr){
32371 // apply baseAttrs, nice idea Corey!
32372 if(this.baseAttrs){
32373 Roo.applyIf(attr, this.baseAttrs);
32375 if(this.applyLoader !== false){
32376 attr.loader = this;
32378 if(typeof(attr.uiProvider) == 'string'){
32380 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
32381 /** eval:var:attr */ eval(attr.uiProvider);
32383 if(typeof(this.uiProviders['default']) != 'undefined') {
32384 attr.uiProvider = this.uiProviders['default'];
32386 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
32388 new Roo.tree.TreeNode(attr) :
32389 new Roo.tree.AsyncTreeNode(attr));
32392 processResponse : function(response, node, callback){
32393 var json = response.responseText;
32396 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
32397 if (this.root !== false) {
32401 for(var i = 0, len = o.length; i < len; i++){
32402 var n = this.createNode(o[i]);
32404 node.appendChild(n);
32407 if(typeof callback == "function"){
32408 callback(this, node);
32411 this.handleFailure(response);
32415 handleResponse : function(response){
32416 this.transId = false;
32417 var a = response.argument;
32418 this.processResponse(response, a.node, a.callback);
32419 this.fireEvent("load", this, a.node, response);
32422 handleFailure : function(response){
32423 this.transId = false;
32424 var a = response.argument;
32425 this.fireEvent("loadexception", this, a.node, response);
32426 if(typeof a.callback == "function"){
32427 a.callback(this, a.node);
32432 * Ext JS Library 1.1.1
32433 * Copyright(c) 2006-2007, Ext JS, LLC.
32435 * Originally Released Under LGPL - original licence link has changed is not relivant.
32438 * <script type="text/javascript">
32442 * @class Roo.tree.TreeFilter
32443 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
32444 * @param {TreePanel} tree
32445 * @param {Object} config (optional)
32447 Roo.tree.TreeFilter = function(tree, config){
32449 this.filtered = {};
32450 Roo.apply(this, config);
32453 Roo.tree.TreeFilter.prototype = {
32460 * Filter the data by a specific attribute.
32461 * @param {String/RegExp} value Either string that the attribute value
32462 * should start with or a RegExp to test against the attribute
32463 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
32464 * @param {TreeNode} startNode (optional) The node to start the filter at.
32466 filter : function(value, attr, startNode){
32467 attr = attr || "text";
32469 if(typeof value == "string"){
32470 var vlen = value.length;
32471 // auto clear empty filter
32472 if(vlen == 0 && this.clearBlank){
32476 value = value.toLowerCase();
32478 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
32480 }else if(value.exec){ // regex?
32482 return value.test(n.attributes[attr]);
32485 throw 'Illegal filter type, must be string or regex';
32487 this.filterBy(f, null, startNode);
32491 * Filter by a function. The passed function will be called with each
32492 * node in the tree (or from the startNode). If the function returns true, the node is kept
32493 * otherwise it is filtered. If a node is filtered, its children are also filtered.
32494 * @param {Function} fn The filter function
32495 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
32497 filterBy : function(fn, scope, startNode){
32498 startNode = startNode || this.tree.root;
32499 if(this.autoClear){
32502 var af = this.filtered, rv = this.reverse;
32503 var f = function(n){
32504 if(n == startNode){
32510 var m = fn.call(scope || n, n);
32518 startNode.cascade(f);
32521 if(typeof id != "function"){
32523 if(n && n.parentNode){
32524 n.parentNode.removeChild(n);
32532 * Clears the current filter. Note: with the "remove" option
32533 * set a filter cannot be cleared.
32535 clear : function(){
32537 var af = this.filtered;
32539 if(typeof id != "function"){
32546 this.filtered = {};
32551 * Ext JS Library 1.1.1
32552 * Copyright(c) 2006-2007, Ext JS, LLC.
32554 * Originally Released Under LGPL - original licence link has changed is not relivant.
32557 * <script type="text/javascript">
32562 * @class Roo.tree.TreeSorter
32563 * Provides sorting of nodes in a TreePanel
32565 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
32566 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
32567 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
32568 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
32569 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
32570 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
32572 * @param {TreePanel} tree
32573 * @param {Object} config
32575 Roo.tree.TreeSorter = function(tree, config){
32576 Roo.apply(this, config);
32577 tree.on("beforechildrenrendered", this.doSort, this);
32578 tree.on("append", this.updateSort, this);
32579 tree.on("insert", this.updateSort, this);
32581 var dsc = this.dir && this.dir.toLowerCase() == "desc";
32582 var p = this.property || "text";
32583 var sortType = this.sortType;
32584 var fs = this.folderSort;
32585 var cs = this.caseSensitive === true;
32586 var leafAttr = this.leafAttr || 'leaf';
32588 this.sortFn = function(n1, n2){
32590 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
32593 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
32597 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
32598 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
32600 return dsc ? +1 : -1;
32602 return dsc ? -1 : +1;
32609 Roo.tree.TreeSorter.prototype = {
32610 doSort : function(node){
32611 node.sort(this.sortFn);
32614 compareNodes : function(n1, n2){
32615 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
32618 updateSort : function(tree, node){
32619 if(node.childrenRendered){
32620 this.doSort.defer(1, this, [node]);
32625 * Ext JS Library 1.1.1
32626 * Copyright(c) 2006-2007, Ext JS, LLC.
32628 * Originally Released Under LGPL - original licence link has changed is not relivant.
32631 * <script type="text/javascript">
32634 if(Roo.dd.DropZone){
32636 Roo.tree.TreeDropZone = function(tree, config){
32637 this.allowParentInsert = false;
32638 this.allowContainerDrop = false;
32639 this.appendOnly = false;
32640 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
32642 this.lastInsertClass = "x-tree-no-status";
32643 this.dragOverData = {};
32646 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
32647 ddGroup : "TreeDD",
32649 expandDelay : 1000,
32651 expandNode : function(node){
32652 if(node.hasChildNodes() && !node.isExpanded()){
32653 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
32657 queueExpand : function(node){
32658 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
32661 cancelExpand : function(){
32662 if(this.expandProcId){
32663 clearTimeout(this.expandProcId);
32664 this.expandProcId = false;
32668 isValidDropPoint : function(n, pt, dd, e, data){
32669 if(!n || !data){ return false; }
32670 var targetNode = n.node;
32671 var dropNode = data.node;
32672 // default drop rules
32673 if(!(targetNode && targetNode.isTarget && pt)){
32676 if(pt == "append" && targetNode.allowChildren === false){
32679 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
32682 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
32685 // reuse the object
32686 var overEvent = this.dragOverData;
32687 overEvent.tree = this.tree;
32688 overEvent.target = targetNode;
32689 overEvent.data = data;
32690 overEvent.point = pt;
32691 overEvent.source = dd;
32692 overEvent.rawEvent = e;
32693 overEvent.dropNode = dropNode;
32694 overEvent.cancel = false;
32695 var result = this.tree.fireEvent("nodedragover", overEvent);
32696 return overEvent.cancel === false && result !== false;
32699 getDropPoint : function(e, n, dd){
32702 return tn.allowChildren !== false ? "append" : false; // always append for root
32704 var dragEl = n.ddel;
32705 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
32706 var y = Roo.lib.Event.getPageY(e);
32707 var noAppend = tn.allowChildren === false || tn.isLeaf();
32708 if(this.appendOnly || tn.parentNode.allowChildren === false){
32709 return noAppend ? false : "append";
32711 var noBelow = false;
32712 if(!this.allowParentInsert){
32713 noBelow = tn.hasChildNodes() && tn.isExpanded();
32715 var q = (b - t) / (noAppend ? 2 : 3);
32716 if(y >= t && y < (t + q)){
32718 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
32725 onNodeEnter : function(n, dd, e, data){
32726 this.cancelExpand();
32729 onNodeOver : function(n, dd, e, data){
32730 var pt = this.getDropPoint(e, n, dd);
32733 // auto node expand check
32734 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
32735 this.queueExpand(node);
32736 }else if(pt != "append"){
32737 this.cancelExpand();
32740 // set the insert point style on the target node
32741 var returnCls = this.dropNotAllowed;
32742 if(this.isValidDropPoint(n, pt, dd, e, data)){
32747 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
32748 cls = "x-tree-drag-insert-above";
32749 }else if(pt == "below"){
32750 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
32751 cls = "x-tree-drag-insert-below";
32753 returnCls = "x-tree-drop-ok-append";
32754 cls = "x-tree-drag-append";
32756 if(this.lastInsertClass != cls){
32757 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
32758 this.lastInsertClass = cls;
32765 onNodeOut : function(n, dd, e, data){
32766 this.cancelExpand();
32767 this.removeDropIndicators(n);
32770 onNodeDrop : function(n, dd, e, data){
32771 var point = this.getDropPoint(e, n, dd);
32772 var targetNode = n.node;
32773 targetNode.ui.startDrop();
32774 if(!this.isValidDropPoint(n, point, dd, e, data)){
32775 targetNode.ui.endDrop();
32778 // first try to find the drop node
32779 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
32782 target: targetNode,
32787 dropNode: dropNode,
32790 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
32791 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
32792 targetNode.ui.endDrop();
32795 // allow target changing
32796 targetNode = dropEvent.target;
32797 if(point == "append" && !targetNode.isExpanded()){
32798 targetNode.expand(false, null, function(){
32799 this.completeDrop(dropEvent);
32800 }.createDelegate(this));
32802 this.completeDrop(dropEvent);
32807 completeDrop : function(de){
32808 var ns = de.dropNode, p = de.point, t = de.target;
32809 if(!(ns instanceof Array)){
32813 for(var i = 0, len = ns.length; i < len; i++){
32816 t.parentNode.insertBefore(n, t);
32817 }else if(p == "below"){
32818 t.parentNode.insertBefore(n, t.nextSibling);
32824 if(this.tree.hlDrop){
32828 this.tree.fireEvent("nodedrop", de);
32831 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
32832 if(this.tree.hlDrop){
32833 dropNode.ui.focus();
32834 dropNode.ui.highlight();
32836 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
32839 getTree : function(){
32843 removeDropIndicators : function(n){
32846 Roo.fly(el).removeClass([
32847 "x-tree-drag-insert-above",
32848 "x-tree-drag-insert-below",
32849 "x-tree-drag-append"]);
32850 this.lastInsertClass = "_noclass";
32854 beforeDragDrop : function(target, e, id){
32855 this.cancelExpand();
32859 afterRepair : function(data){
32860 if(data && Roo.enableFx){
32861 data.node.ui.highlight();
32869 * Ext JS Library 1.1.1
32870 * Copyright(c) 2006-2007, Ext JS, LLC.
32872 * Originally Released Under LGPL - original licence link has changed is not relivant.
32875 * <script type="text/javascript">
32879 if(Roo.dd.DragZone){
32880 Roo.tree.TreeDragZone = function(tree, config){
32881 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
32885 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
32886 ddGroup : "TreeDD",
32888 onBeforeDrag : function(data, e){
32890 return n && n.draggable && !n.disabled;
32893 onInitDrag : function(e){
32894 var data = this.dragData;
32895 this.tree.getSelectionModel().select(data.node);
32896 this.proxy.update("");
32897 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
32898 this.tree.fireEvent("startdrag", this.tree, data.node, e);
32901 getRepairXY : function(e, data){
32902 return data.node.ui.getDDRepairXY();
32905 onEndDrag : function(data, e){
32906 this.tree.fireEvent("enddrag", this.tree, data.node, e);
32909 onValidDrop : function(dd, e, id){
32910 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
32914 beforeInvalidDrop : function(e, id){
32915 // this scrolls the original position back into view
32916 var sm = this.tree.getSelectionModel();
32917 sm.clearSelections();
32918 sm.select(this.dragData.node);
32923 * Ext JS Library 1.1.1
32924 * Copyright(c) 2006-2007, Ext JS, LLC.
32926 * Originally Released Under LGPL - original licence link has changed is not relivant.
32929 * <script type="text/javascript">
32932 * @class Roo.tree.TreeEditor
32933 * @extends Roo.Editor
32934 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
32935 * as the editor field.
32937 * @param {TreePanel} tree
32938 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
32940 Roo.tree.TreeEditor = function(tree, config){
32941 config = config || {};
32942 var field = config.events ? config : new Roo.form.TextField(config);
32943 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
32947 tree.on('beforeclick', this.beforeNodeClick, this);
32948 tree.getTreeEl().on('mousedown', this.hide, this);
32949 this.on('complete', this.updateNode, this);
32950 this.on('beforestartedit', this.fitToTree, this);
32951 this.on('startedit', this.bindScroll, this, {delay:10});
32952 this.on('specialkey', this.onSpecialKey, this);
32955 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
32957 * @cfg {String} alignment
32958 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
32964 * @cfg {Boolean} hideEl
32965 * True to hide the bound element while the editor is displayed (defaults to false)
32969 * @cfg {String} cls
32970 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
32972 cls: "x-small-editor x-tree-editor",
32974 * @cfg {Boolean} shim
32975 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
32981 * @cfg {Number} maxWidth
32982 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
32983 * the containing tree element's size, it will be automatically limited for you to the container width, taking
32984 * scroll and client offsets into account prior to each edit.
32991 fitToTree : function(ed, el){
32992 var td = this.tree.getTreeEl().dom, nd = el.dom;
32993 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
32994 td.scrollLeft = nd.offsetLeft;
32998 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
32999 this.setSize(w, '');
33003 triggerEdit : function(node){
33004 this.completeEdit();
33005 this.editNode = node;
33006 this.startEdit(node.ui.textNode, node.text);
33010 bindScroll : function(){
33011 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33015 beforeNodeClick : function(node, e){
33016 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33017 this.lastClick = new Date();
33018 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33020 this.triggerEdit(node);
33026 updateNode : function(ed, value){
33027 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33028 this.editNode.setText(value);
33032 onHide : function(){
33033 Roo.tree.TreeEditor.superclass.onHide.call(this);
33035 this.editNode.ui.focus();
33040 onSpecialKey : function(field, e){
33041 var k = e.getKey();
33045 }else if(k == e.ENTER && !e.hasModifier()){
33047 this.completeEdit();
33050 });//<Script type="text/javascript">
33053 * Ext JS Library 1.1.1
33054 * Copyright(c) 2006-2007, Ext JS, LLC.
33056 * Originally Released Under LGPL - original licence link has changed is not relivant.
33059 * <script type="text/javascript">
33063 * Not documented??? - probably should be...
33066 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33067 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33069 renderElements : function(n, a, targetNode, bulkRender){
33070 //consel.log("renderElements?");
33071 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33073 var t = n.getOwnerTree();
33074 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33076 var cols = t.columns;
33077 var bw = t.borderWidth;
33079 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33080 var cb = typeof a.checked == "boolean";
33081 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33082 var colcls = 'x-t-' + tid + '-c0';
33084 '<li class="x-tree-node">',
33087 '<div class="x-tree-node-el ', a.cls,'">',
33089 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33092 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33093 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33094 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33095 (a.icon ? ' x-tree-node-inline-icon' : ''),
33096 (a.iconCls ? ' '+a.iconCls : ''),
33097 '" unselectable="on" />',
33098 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33099 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33101 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33102 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33103 '<span unselectable="on" qtip="' + tx + '">',
33107 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33108 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33111 for(var i = 1, len = cols.length; i < len; i++){
33113 colcls = 'x-t-' + tid + '-c' +i;
33114 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33115 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33116 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33122 '<div class="x-clear"></div></div>',
33123 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33126 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33127 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33128 n.nextSibling.ui.getEl(), buf.join(""));
33130 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33132 var el = this.wrap.firstChild;
33134 this.elNode = el.firstChild;
33135 this.ranchor = el.childNodes[1];
33136 this.ctNode = this.wrap.childNodes[1];
33137 var cs = el.firstChild.childNodes;
33138 this.indentNode = cs[0];
33139 this.ecNode = cs[1];
33140 this.iconNode = cs[2];
33143 this.checkbox = cs[3];
33146 this.anchor = cs[index];
33148 this.textNode = cs[index].firstChild;
33150 //el.on("click", this.onClick, this);
33151 //el.on("dblclick", this.onDblClick, this);
33154 // console.log(this);
33156 initEvents : function(){
33157 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33160 var a = this.ranchor;
33162 var el = Roo.get(a);
33164 if(Roo.isOpera){ // opera render bug ignores the CSS
33165 el.setStyle("text-decoration", "none");
33168 el.on("click", this.onClick, this);
33169 el.on("dblclick", this.onDblClick, this);
33170 el.on("contextmenu", this.onContextMenu, this);
33174 /*onSelectedChange : function(state){
33177 this.addClass("x-tree-selected");
33180 this.removeClass("x-tree-selected");
33183 addClass : function(cls){
33185 Roo.fly(this.elRow).addClass(cls);
33191 removeClass : function(cls){
33193 Roo.fly(this.elRow).removeClass(cls);
33199 });//<Script type="text/javascript">
33203 * Ext JS Library 1.1.1
33204 * Copyright(c) 2006-2007, Ext JS, LLC.
33206 * Originally Released Under LGPL - original licence link has changed is not relivant.
33209 * <script type="text/javascript">
33214 * @class Roo.tree.ColumnTree
33215 * @extends Roo.data.TreePanel
33216 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33217 * @cfg {int} borderWidth compined right/left border allowance
33219 * @param {String/HTMLElement/Element} el The container element
33220 * @param {Object} config
33222 Roo.tree.ColumnTree = function(el, config)
33224 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33228 * Fire this event on a container when it resizes
33229 * @param {int} w Width
33230 * @param {int} h Height
33234 this.on('resize', this.onResize, this);
33237 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
33241 borderWidth: Roo.isBorderBox ? 0 : 2,
33244 render : function(){
33245 // add the header.....
33247 Roo.tree.ColumnTree.superclass.render.apply(this);
33249 this.el.addClass('x-column-tree');
33251 this.headers = this.el.createChild(
33252 {cls:'x-tree-headers'},this.innerCt.dom);
33254 var cols = this.columns, c;
33255 var totalWidth = 0;
33257 var len = cols.length;
33258 for(var i = 0; i < len; i++){
33260 totalWidth += c.width;
33261 this.headEls.push(this.headers.createChild({
33262 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
33264 cls:'x-tree-hd-text',
33267 style:'width:'+(c.width-this.borderWidth)+'px;'
33270 this.headers.createChild({cls:'x-clear'});
33271 // prevent floats from wrapping when clipped
33272 this.headers.setWidth(totalWidth);
33273 //this.innerCt.setWidth(totalWidth);
33274 this.innerCt.setStyle({ overflow: 'auto' });
33275 this.onResize(this.width, this.height);
33279 onResize : function(w,h)
33284 this.innerCt.setWidth(this.width);
33285 this.innerCt.setHeight(this.height-20);
33288 var cols = this.columns, c;
33289 var totalWidth = 0;
33291 var len = cols.length;
33292 for(var i = 0; i < len; i++){
33294 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
33295 // it's the expander..
33296 expEl = this.headEls[i];
33299 totalWidth += c.width;
33303 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
33305 this.headers.setWidth(w-20);
33314 * Ext JS Library 1.1.1
33315 * Copyright(c) 2006-2007, Ext JS, LLC.
33317 * Originally Released Under LGPL - original licence link has changed is not relivant.
33320 * <script type="text/javascript">
33324 * @class Roo.menu.Menu
33325 * @extends Roo.util.Observable
33326 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
33327 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
33329 * Creates a new Menu
33330 * @param {Object} config Configuration options
33332 Roo.menu.Menu = function(config){
33333 Roo.apply(this, config);
33334 this.id = this.id || Roo.id();
33337 * @event beforeshow
33338 * Fires before this menu is displayed
33339 * @param {Roo.menu.Menu} this
33343 * @event beforehide
33344 * Fires before this menu is hidden
33345 * @param {Roo.menu.Menu} this
33350 * Fires after this menu is displayed
33351 * @param {Roo.menu.Menu} this
33356 * Fires after this menu is hidden
33357 * @param {Roo.menu.Menu} this
33362 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
33363 * @param {Roo.menu.Menu} this
33364 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33365 * @param {Roo.EventObject} e
33370 * Fires when the mouse is hovering over this menu
33371 * @param {Roo.menu.Menu} this
33372 * @param {Roo.EventObject} e
33373 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33378 * Fires when the mouse exits this menu
33379 * @param {Roo.menu.Menu} this
33380 * @param {Roo.EventObject} e
33381 * @param {Roo.menu.Item} menuItem The menu item that was clicked
33386 * Fires when a menu item contained in this menu is clicked
33387 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
33388 * @param {Roo.EventObject} e
33392 if (this.registerMenu) {
33393 Roo.menu.MenuMgr.register(this);
33396 var mis = this.items;
33397 this.items = new Roo.util.MixedCollection();
33399 this.add.apply(this, mis);
33403 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
33405 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
33409 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
33410 * for bottom-right shadow (defaults to "sides")
33414 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
33415 * this menu (defaults to "tl-tr?")
33417 subMenuAlign : "tl-tr?",
33419 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
33420 * relative to its element of origin (defaults to "tl-bl?")
33422 defaultAlign : "tl-bl?",
33424 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
33426 allowOtherMenus : false,
33428 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
33430 registerMenu : true,
33435 render : function(){
33439 var el = this.el = new Roo.Layer({
33441 shadow:this.shadow,
33443 parentEl: this.parentEl || document.body,
33447 this.keyNav = new Roo.menu.MenuNav(this);
33450 el.addClass("x-menu-plain");
33453 el.addClass(this.cls);
33455 // generic focus element
33456 this.focusEl = el.createChild({
33457 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
33459 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
33460 ul.on("click", this.onClick, this);
33461 ul.on("mouseover", this.onMouseOver, this);
33462 ul.on("mouseout", this.onMouseOut, this);
33463 this.items.each(function(item){
33464 var li = document.createElement("li");
33465 li.className = "x-menu-list-item";
33466 ul.dom.appendChild(li);
33467 item.render(li, this);
33474 autoWidth : function(){
33475 var el = this.el, ul = this.ul;
33479 var w = this.width;
33482 }else if(Roo.isIE){
33483 el.setWidth(this.minWidth);
33484 var t = el.dom.offsetWidth; // force recalc
33485 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
33490 delayAutoWidth : function(){
33493 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
33495 this.awTask.delay(20);
33500 findTargetItem : function(e){
33501 var t = e.getTarget(".x-menu-list-item", this.ul, true);
33502 if(t && t.menuItemId){
33503 return this.items.get(t.menuItemId);
33508 onClick : function(e){
33510 if(t = this.findTargetItem(e)){
33512 this.fireEvent("click", this, t, e);
33517 setActiveItem : function(item, autoExpand){
33518 if(item != this.activeItem){
33519 if(this.activeItem){
33520 this.activeItem.deactivate();
33522 this.activeItem = item;
33523 item.activate(autoExpand);
33524 }else if(autoExpand){
33530 tryActivate : function(start, step){
33531 var items = this.items;
33532 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
33533 var item = items.get(i);
33534 if(!item.disabled && item.canActivate){
33535 this.setActiveItem(item, false);
33543 onMouseOver : function(e){
33545 if(t = this.findTargetItem(e)){
33546 if(t.canActivate && !t.disabled){
33547 this.setActiveItem(t, true);
33550 this.fireEvent("mouseover", this, e, t);
33554 onMouseOut : function(e){
33556 if(t = this.findTargetItem(e)){
33557 if(t == this.activeItem && t.shouldDeactivate(e)){
33558 this.activeItem.deactivate();
33559 delete this.activeItem;
33562 this.fireEvent("mouseout", this, e, t);
33566 * Read-only. Returns true if the menu is currently displayed, else false.
33569 isVisible : function(){
33570 return this.el && !this.hidden;
33574 * Displays this menu relative to another element
33575 * @param {String/HTMLElement/Roo.Element} element The element to align to
33576 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
33577 * the element (defaults to this.defaultAlign)
33578 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33580 show : function(el, pos, parentMenu){
33581 this.parentMenu = parentMenu;
33585 this.fireEvent("beforeshow", this);
33586 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
33590 * Displays this menu at a specific xy position
33591 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
33592 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
33594 showAt : function(xy, parentMenu, /* private: */_e){
33595 this.parentMenu = parentMenu;
33600 this.fireEvent("beforeshow", this);
33601 xy = this.el.adjustForConstraints(xy);
33605 this.hidden = false;
33607 this.fireEvent("show", this);
33610 focus : function(){
33612 this.doFocus.defer(50, this);
33616 doFocus : function(){
33618 this.focusEl.focus();
33623 * Hides this menu and optionally all parent menus
33624 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
33626 hide : function(deep){
33627 if(this.el && this.isVisible()){
33628 this.fireEvent("beforehide", this);
33629 if(this.activeItem){
33630 this.activeItem.deactivate();
33631 this.activeItem = null;
33634 this.hidden = true;
33635 this.fireEvent("hide", this);
33637 if(deep === true && this.parentMenu){
33638 this.parentMenu.hide(true);
33643 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
33644 * Any of the following are valid:
33646 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
33647 * <li>An HTMLElement object which will be converted to a menu item</li>
33648 * <li>A menu item config object that will be created as a new menu item</li>
33649 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
33650 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
33655 var menu = new Roo.menu.Menu();
33657 // Create a menu item to add by reference
33658 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
33660 // Add a bunch of items at once using different methods.
33661 // Only the last item added will be returned.
33662 var item = menu.add(
33663 menuItem, // add existing item by ref
33664 'Dynamic Item', // new TextItem
33665 '-', // new separator
33666 { text: 'Config Item' } // new item by config
33669 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
33670 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
33673 var a = arguments, l = a.length, item;
33674 for(var i = 0; i < l; i++){
33676 if(el.render){ // some kind of Item
33677 item = this.addItem(el);
33678 }else if(typeof el == "string"){ // string
33679 if(el == "separator" || el == "-"){
33680 item = this.addSeparator();
33682 item = this.addText(el);
33684 }else if(el.tagName || el.el){ // element
33685 item = this.addElement(el);
33686 }else if(typeof el == "object"){ // must be menu item config?
33687 item = this.addMenuItem(el);
33694 * Returns this menu's underlying {@link Roo.Element} object
33695 * @return {Roo.Element} The element
33697 getEl : function(){
33705 * Adds a separator bar to the menu
33706 * @return {Roo.menu.Item} The menu item that was added
33708 addSeparator : function(){
33709 return this.addItem(new Roo.menu.Separator());
33713 * Adds an {@link Roo.Element} object to the menu
33714 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
33715 * @return {Roo.menu.Item} The menu item that was added
33717 addElement : function(el){
33718 return this.addItem(new Roo.menu.BaseItem(el));
33722 * Adds an existing object based on {@link Roo.menu.Item} to the menu
33723 * @param {Roo.menu.Item} item The menu item to add
33724 * @return {Roo.menu.Item} The menu item that was added
33726 addItem : function(item){
33727 this.items.add(item);
33729 var li = document.createElement("li");
33730 li.className = "x-menu-list-item";
33731 this.ul.dom.appendChild(li);
33732 item.render(li, this);
33733 this.delayAutoWidth();
33739 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
33740 * @param {Object} config A MenuItem config object
33741 * @return {Roo.menu.Item} The menu item that was added
33743 addMenuItem : function(config){
33744 if(!(config instanceof Roo.menu.Item)){
33745 if(typeof config.checked == "boolean"){ // must be check menu item config?
33746 config = new Roo.menu.CheckItem(config);
33748 config = new Roo.menu.Item(config);
33751 return this.addItem(config);
33755 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
33756 * @param {String} text The text to display in the menu item
33757 * @return {Roo.menu.Item} The menu item that was added
33759 addText : function(text){
33760 return this.addItem(new Roo.menu.TextItem(text));
33764 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
33765 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
33766 * @param {Roo.menu.Item} item The menu item to add
33767 * @return {Roo.menu.Item} The menu item that was added
33769 insert : function(index, item){
33770 this.items.insert(index, item);
33772 var li = document.createElement("li");
33773 li.className = "x-menu-list-item";
33774 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
33775 item.render(li, this);
33776 this.delayAutoWidth();
33782 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
33783 * @param {Roo.menu.Item} item The menu item to remove
33785 remove : function(item){
33786 this.items.removeKey(item.id);
33791 * Removes and destroys all items in the menu
33793 removeAll : function(){
33795 while(f = this.items.first()){
33801 // MenuNav is a private utility class used internally by the Menu
33802 Roo.menu.MenuNav = function(menu){
33803 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
33804 this.scope = this.menu = menu;
33807 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
33808 doRelay : function(e, h){
33809 var k = e.getKey();
33810 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
33811 this.menu.tryActivate(0, 1);
33814 return h.call(this.scope || this, e, this.menu);
33817 up : function(e, m){
33818 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
33819 m.tryActivate(m.items.length-1, -1);
33823 down : function(e, m){
33824 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
33825 m.tryActivate(0, 1);
33829 right : function(e, m){
33831 m.activeItem.expandMenu(true);
33835 left : function(e, m){
33837 if(m.parentMenu && m.parentMenu.activeItem){
33838 m.parentMenu.activeItem.activate();
33842 enter : function(e, m){
33844 e.stopPropagation();
33845 m.activeItem.onClick(e);
33846 m.fireEvent("click", this, m.activeItem);
33852 * Ext JS Library 1.1.1
33853 * Copyright(c) 2006-2007, Ext JS, LLC.
33855 * Originally Released Under LGPL - original licence link has changed is not relivant.
33858 * <script type="text/javascript">
33862 * @class Roo.menu.MenuMgr
33863 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
33866 Roo.menu.MenuMgr = function(){
33867 var menus, active, groups = {}, attached = false, lastShow = new Date();
33869 // private - called when first menu is created
33872 active = new Roo.util.MixedCollection();
33873 Roo.get(document).addKeyListener(27, function(){
33874 if(active.length > 0){
33881 function hideAll(){
33882 if(active && active.length > 0){
33883 var c = active.clone();
33884 c.each(function(m){
33891 function onHide(m){
33893 if(active.length < 1){
33894 Roo.get(document).un("mousedown", onMouseDown);
33900 function onShow(m){
33901 var last = active.last();
33902 lastShow = new Date();
33905 Roo.get(document).on("mousedown", onMouseDown);
33909 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
33910 m.parentMenu.activeChild = m;
33911 }else if(last && last.isVisible()){
33912 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
33917 function onBeforeHide(m){
33919 m.activeChild.hide();
33921 if(m.autoHideTimer){
33922 clearTimeout(m.autoHideTimer);
33923 delete m.autoHideTimer;
33928 function onBeforeShow(m){
33929 var pm = m.parentMenu;
33930 if(!pm && !m.allowOtherMenus){
33932 }else if(pm && pm.activeChild && active != m){
33933 pm.activeChild.hide();
33938 function onMouseDown(e){
33939 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
33945 function onBeforeCheck(mi, state){
33947 var g = groups[mi.group];
33948 for(var i = 0, l = g.length; i < l; i++){
33950 g[i].setChecked(false);
33959 * Hides all menus that are currently visible
33961 hideAll : function(){
33966 register : function(menu){
33970 menus[menu.id] = menu;
33971 menu.on("beforehide", onBeforeHide);
33972 menu.on("hide", onHide);
33973 menu.on("beforeshow", onBeforeShow);
33974 menu.on("show", onShow);
33975 var g = menu.group;
33976 if(g && menu.events["checkchange"]){
33980 groups[g].push(menu);
33981 menu.on("checkchange", onCheck);
33986 * Returns a {@link Roo.menu.Menu} object
33987 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
33988 * be used to generate and return a new Menu instance.
33990 get : function(menu){
33991 if(typeof menu == "string"){ // menu id
33992 return menus[menu];
33993 }else if(menu.events){ // menu instance
33995 }else if(typeof menu.length == 'number'){ // array of menu items?
33996 return new Roo.menu.Menu({items:menu});
33997 }else{ // otherwise, must be a config
33998 return new Roo.menu.Menu(menu);
34003 unregister : function(menu){
34004 delete menus[menu.id];
34005 menu.un("beforehide", onBeforeHide);
34006 menu.un("hide", onHide);
34007 menu.un("beforeshow", onBeforeShow);
34008 menu.un("show", onShow);
34009 var g = menu.group;
34010 if(g && menu.events["checkchange"]){
34011 groups[g].remove(menu);
34012 menu.un("checkchange", onCheck);
34017 registerCheckable : function(menuItem){
34018 var g = menuItem.group;
34023 groups[g].push(menuItem);
34024 menuItem.on("beforecheckchange", onBeforeCheck);
34029 unregisterCheckable : function(menuItem){
34030 var g = menuItem.group;
34032 groups[g].remove(menuItem);
34033 menuItem.un("beforecheckchange", onBeforeCheck);
34039 * Ext JS Library 1.1.1
34040 * Copyright(c) 2006-2007, Ext JS, LLC.
34042 * Originally Released Under LGPL - original licence link has changed is not relivant.
34045 * <script type="text/javascript">
34050 * @class Roo.menu.BaseItem
34051 * @extends Roo.Component
34052 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34053 * management and base configuration options shared by all menu components.
34055 * Creates a new BaseItem
34056 * @param {Object} config Configuration options
34058 Roo.menu.BaseItem = function(config){
34059 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34064 * Fires when this item is clicked
34065 * @param {Roo.menu.BaseItem} this
34066 * @param {Roo.EventObject} e
34071 * Fires when this item is activated
34072 * @param {Roo.menu.BaseItem} this
34076 * @event deactivate
34077 * Fires when this item is deactivated
34078 * @param {Roo.menu.BaseItem} this
34084 this.on("click", this.handler, this.scope, true);
34088 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34090 * @cfg {Function} handler
34091 * A function that will handle the click event of this menu item (defaults to undefined)
34094 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34096 canActivate : false,
34098 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34100 activeClass : "x-menu-item-active",
34102 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34104 hideOnClick : true,
34106 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34111 ctype: "Roo.menu.BaseItem",
34114 actionMode : "container",
34117 render : function(container, parentMenu){
34118 this.parentMenu = parentMenu;
34119 Roo.menu.BaseItem.superclass.render.call(this, container);
34120 this.container.menuItemId = this.id;
34124 onRender : function(container, position){
34125 this.el = Roo.get(this.el);
34126 container.dom.appendChild(this.el.dom);
34130 onClick : function(e){
34131 if(!this.disabled && this.fireEvent("click", this, e) !== false
34132 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34133 this.handleClick(e);
34140 activate : function(){
34144 var li = this.container;
34145 li.addClass(this.activeClass);
34146 this.region = li.getRegion().adjust(2, 2, -2, -2);
34147 this.fireEvent("activate", this);
34152 deactivate : function(){
34153 this.container.removeClass(this.activeClass);
34154 this.fireEvent("deactivate", this);
34158 shouldDeactivate : function(e){
34159 return !this.region || !this.region.contains(e.getPoint());
34163 handleClick : function(e){
34164 if(this.hideOnClick){
34165 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34170 expandMenu : function(autoActivate){
34175 hideMenu : function(){
34180 * Ext JS Library 1.1.1
34181 * Copyright(c) 2006-2007, Ext JS, LLC.
34183 * Originally Released Under LGPL - original licence link has changed is not relivant.
34186 * <script type="text/javascript">
34190 * @class Roo.menu.Adapter
34191 * @extends Roo.menu.BaseItem
34192 * 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.
34193 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34195 * Creates a new Adapter
34196 * @param {Object} config Configuration options
34198 Roo.menu.Adapter = function(component, config){
34199 Roo.menu.Adapter.superclass.constructor.call(this, config);
34200 this.component = component;
34202 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34204 canActivate : true,
34207 onRender : function(container, position){
34208 this.component.render(container);
34209 this.el = this.component.getEl();
34213 activate : function(){
34217 this.component.focus();
34218 this.fireEvent("activate", this);
34223 deactivate : function(){
34224 this.fireEvent("deactivate", this);
34228 disable : function(){
34229 this.component.disable();
34230 Roo.menu.Adapter.superclass.disable.call(this);
34234 enable : function(){
34235 this.component.enable();
34236 Roo.menu.Adapter.superclass.enable.call(this);
34240 * Ext JS Library 1.1.1
34241 * Copyright(c) 2006-2007, Ext JS, LLC.
34243 * Originally Released Under LGPL - original licence link has changed is not relivant.
34246 * <script type="text/javascript">
34250 * @class Roo.menu.TextItem
34251 * @extends Roo.menu.BaseItem
34252 * Adds a static text string to a menu, usually used as either a heading or group separator.
34254 * Creates a new TextItem
34255 * @param {String} text The text to display
34257 Roo.menu.TextItem = function(text){
34259 Roo.menu.TextItem.superclass.constructor.call(this);
34262 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
34264 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34266 hideOnClick : false,
34268 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
34270 itemCls : "x-menu-text",
34273 onRender : function(){
34274 var s = document.createElement("span");
34275 s.className = this.itemCls;
34276 s.innerHTML = this.text;
34278 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
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.Separator
34293 * @extends Roo.menu.BaseItem
34294 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
34295 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
34297 * @param {Object} config Configuration options
34299 Roo.menu.Separator = function(config){
34300 Roo.menu.Separator.superclass.constructor.call(this, config);
34303 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
34305 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
34307 itemCls : "x-menu-sep",
34309 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
34311 hideOnClick : false,
34314 onRender : function(li){
34315 var s = document.createElement("span");
34316 s.className = this.itemCls;
34317 s.innerHTML = " ";
34319 li.addClass("x-menu-sep-li");
34320 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
34324 * Ext JS Library 1.1.1
34325 * Copyright(c) 2006-2007, Ext JS, LLC.
34327 * Originally Released Under LGPL - original licence link has changed is not relivant.
34330 * <script type="text/javascript">
34333 * @class Roo.menu.Item
34334 * @extends Roo.menu.BaseItem
34335 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
34336 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
34337 * activation and click handling.
34339 * Creates a new Item
34340 * @param {Object} config Configuration options
34342 Roo.menu.Item = function(config){
34343 Roo.menu.Item.superclass.constructor.call(this, config);
34345 this.menu = Roo.menu.MenuMgr.get(this.menu);
34348 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
34350 * @cfg {String} icon
34351 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
34354 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
34356 itemCls : "x-menu-item",
34358 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
34360 canActivate : true,
34362 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
34365 // doc'd in BaseItem
34369 ctype: "Roo.menu.Item",
34372 onRender : function(container, position){
34373 var el = document.createElement("a");
34374 el.hideFocus = true;
34375 el.unselectable = "on";
34376 el.href = this.href || "#";
34377 if(this.hrefTarget){
34378 el.target = this.hrefTarget;
34380 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
34381 el.innerHTML = String.format(
34382 '<img src="{0}" class="x-menu-item-icon {2}" />{1}',
34383 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || '');
34385 Roo.menu.Item.superclass.onRender.call(this, container, position);
34389 * Sets the text to display in this menu item
34390 * @param {String} text The text to display
34392 setText : function(text){
34395 this.el.update(String.format(
34396 '<img src="{0}" class="x-menu-item-icon {2}">{1}',
34397 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
34398 this.parentMenu.autoWidth();
34403 handleClick : function(e){
34404 if(!this.href){ // if no link defined, stop the event automatically
34407 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
34411 activate : function(autoExpand){
34412 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
34422 shouldDeactivate : function(e){
34423 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
34424 if(this.menu && this.menu.isVisible()){
34425 return !this.menu.getEl().getRegion().contains(e.getPoint());
34433 deactivate : function(){
34434 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
34439 expandMenu : function(autoActivate){
34440 if(!this.disabled && this.menu){
34441 clearTimeout(this.hideTimer);
34442 delete this.hideTimer;
34443 if(!this.menu.isVisible() && !this.showTimer){
34444 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
34445 }else if (this.menu.isVisible() && autoActivate){
34446 this.menu.tryActivate(0, 1);
34452 deferExpand : function(autoActivate){
34453 delete this.showTimer;
34454 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
34456 this.menu.tryActivate(0, 1);
34461 hideMenu : function(){
34462 clearTimeout(this.showTimer);
34463 delete this.showTimer;
34464 if(!this.hideTimer && this.menu && this.menu.isVisible()){
34465 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
34470 deferHide : function(){
34471 delete this.hideTimer;
34476 * Ext JS Library 1.1.1
34477 * Copyright(c) 2006-2007, Ext JS, LLC.
34479 * Originally Released Under LGPL - original licence link has changed is not relivant.
34482 * <script type="text/javascript">
34486 * @class Roo.menu.CheckItem
34487 * @extends Roo.menu.Item
34488 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
34490 * Creates a new CheckItem
34491 * @param {Object} config Configuration options
34493 Roo.menu.CheckItem = function(config){
34494 Roo.menu.CheckItem.superclass.constructor.call(this, config);
34497 * @event beforecheckchange
34498 * Fires before the checked value is set, providing an opportunity to cancel if needed
34499 * @param {Roo.menu.CheckItem} this
34500 * @param {Boolean} checked The new checked value that will be set
34502 "beforecheckchange" : true,
34504 * @event checkchange
34505 * Fires after the checked value has been set
34506 * @param {Roo.menu.CheckItem} this
34507 * @param {Boolean} checked The checked value that was set
34509 "checkchange" : true
34511 if(this.checkHandler){
34512 this.on('checkchange', this.checkHandler, this.scope);
34515 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
34517 * @cfg {String} group
34518 * All check items with the same group name will automatically be grouped into a single-select
34519 * radio button group (defaults to '')
34522 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
34524 itemCls : "x-menu-item x-menu-check-item",
34526 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
34528 groupClass : "x-menu-group-item",
34531 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
34532 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
34533 * initialized with checked = true will be rendered as checked.
34538 ctype: "Roo.menu.CheckItem",
34541 onRender : function(c){
34542 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
34544 this.el.addClass(this.groupClass);
34546 Roo.menu.MenuMgr.registerCheckable(this);
34548 this.checked = false;
34549 this.setChecked(true, true);
34554 destroy : function(){
34556 Roo.menu.MenuMgr.unregisterCheckable(this);
34558 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
34562 * Set the checked state of this item
34563 * @param {Boolean} checked The new checked value
34564 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
34566 setChecked : function(state, suppressEvent){
34567 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
34568 if(this.container){
34569 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
34571 this.checked = state;
34572 if(suppressEvent !== true){
34573 this.fireEvent("checkchange", this, state);
34579 handleClick : function(e){
34580 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
34581 this.setChecked(!this.checked);
34583 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
34587 * Ext JS Library 1.1.1
34588 * Copyright(c) 2006-2007, Ext JS, LLC.
34590 * Originally Released Under LGPL - original licence link has changed is not relivant.
34593 * <script type="text/javascript">
34597 * @class Roo.menu.DateItem
34598 * @extends Roo.menu.Adapter
34599 * A menu item that wraps the {@link Roo.DatPicker} component.
34601 * Creates a new DateItem
34602 * @param {Object} config Configuration options
34604 Roo.menu.DateItem = function(config){
34605 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
34606 /** The Roo.DatePicker object @type Roo.DatePicker */
34607 this.picker = this.component;
34608 this.addEvents({select: true});
34610 this.picker.on("render", function(picker){
34611 picker.getEl().swallowEvent("click");
34612 picker.container.addClass("x-menu-date-item");
34615 this.picker.on("select", this.onSelect, this);
34618 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
34620 onSelect : function(picker, date){
34621 this.fireEvent("select", this, date, picker);
34622 Roo.menu.DateItem.superclass.handleClick.call(this);
34626 * Ext JS Library 1.1.1
34627 * Copyright(c) 2006-2007, Ext JS, LLC.
34629 * Originally Released Under LGPL - original licence link has changed is not relivant.
34632 * <script type="text/javascript">
34636 * @class Roo.menu.ColorItem
34637 * @extends Roo.menu.Adapter
34638 * A menu item that wraps the {@link Roo.ColorPalette} component.
34640 * Creates a new ColorItem
34641 * @param {Object} config Configuration options
34643 Roo.menu.ColorItem = function(config){
34644 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
34645 /** The Roo.ColorPalette object @type Roo.ColorPalette */
34646 this.palette = this.component;
34647 this.relayEvents(this.palette, ["select"]);
34648 if(this.selectHandler){
34649 this.on('select', this.selectHandler, this.scope);
34652 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
34654 * Ext JS Library 1.1.1
34655 * Copyright(c) 2006-2007, Ext JS, LLC.
34657 * Originally Released Under LGPL - original licence link has changed is not relivant.
34660 * <script type="text/javascript">
34665 * @class Roo.menu.DateMenu
34666 * @extends Roo.menu.Menu
34667 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
34669 * Creates a new DateMenu
34670 * @param {Object} config Configuration options
34672 Roo.menu.DateMenu = function(config){
34673 Roo.menu.DateMenu.superclass.constructor.call(this, config);
34675 var di = new Roo.menu.DateItem(config);
34678 * The {@link Roo.DatePicker} instance for this DateMenu
34681 this.picker = di.picker;
34684 * @param {DatePicker} picker
34685 * @param {Date} date
34687 this.relayEvents(di, ["select"]);
34689 this.on('beforeshow', function(){
34691 this.picker.hideMonthPicker(true);
34695 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
34699 * Ext JS Library 1.1.1
34700 * Copyright(c) 2006-2007, Ext JS, LLC.
34702 * Originally Released Under LGPL - original licence link has changed is not relivant.
34705 * <script type="text/javascript">
34710 * @class Roo.menu.ColorMenu
34711 * @extends Roo.menu.Menu
34712 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
34714 * Creates a new ColorMenu
34715 * @param {Object} config Configuration options
34717 Roo.menu.ColorMenu = function(config){
34718 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
34720 var ci = new Roo.menu.ColorItem(config);
34723 * The {@link Roo.ColorPalette} instance for this ColorMenu
34724 * @type ColorPalette
34726 this.palette = ci.palette;
34729 * @param {ColorPalette} palette
34730 * @param {String} color
34732 this.relayEvents(ci, ["select"]);
34734 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
34736 * Ext JS Library 1.1.1
34737 * Copyright(c) 2006-2007, Ext JS, LLC.
34739 * Originally Released Under LGPL - original licence link has changed is not relivant.
34742 * <script type="text/javascript">
34746 * @class Roo.form.Field
34747 * @extends Roo.BoxComponent
34748 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
34750 * Creates a new Field
34751 * @param {Object} config Configuration options
34753 Roo.form.Field = function(config){
34754 Roo.form.Field.superclass.constructor.call(this, config);
34757 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
34759 * @cfg {String} fieldLabel Label to use when rendering a form.
34762 * @cfg {String} qtip Mouse over tip
34766 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
34768 invalidClass : "x-form-invalid",
34770 * @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")
34772 invalidText : "The value in this field is invalid",
34774 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
34776 focusClass : "x-form-focus",
34778 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
34779 automatic validation (defaults to "keyup").
34781 validationEvent : "keyup",
34783 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
34785 validateOnBlur : true,
34787 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
34789 validationDelay : 250,
34791 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
34792 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
34794 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
34796 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
34798 fieldClass : "x-form-field",
34800 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
34803 ----------- ----------------------------------------------------------------------
34804 qtip Display a quick tip when the user hovers over the field
34805 title Display a default browser title attribute popup
34806 under Add a block div beneath the field containing the error text
34807 side Add an error icon to the right of the field with a popup on hover
34808 [element id] Add the error text directly to the innerHTML of the specified element
34811 msgTarget : 'qtip',
34813 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
34818 * @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.
34823 * @cfg {Boolean} disabled True to disable the field (defaults to false).
34828 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
34830 inputType : undefined,
34833 * @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).
34835 tabIndex : undefined,
34838 isFormField : true,
34843 * @property {Roo.Element} fieldEl
34844 * Element Containing the rendered Field (with label etc.)
34847 * @cfg {Mixed} value A value to initialize this field with.
34852 * @cfg {String} name The field's HTML name attribute.
34855 * @cfg {String} cls A CSS class to apply to the field's underlying element.
34859 initComponent : function(){
34860 Roo.form.Field.superclass.initComponent.call(this);
34864 * Fires when this field receives input focus.
34865 * @param {Roo.form.Field} this
34870 * Fires when this field loses input focus.
34871 * @param {Roo.form.Field} this
34875 * @event specialkey
34876 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
34877 * {@link Roo.EventObject#getKey} to determine which key was pressed.
34878 * @param {Roo.form.Field} this
34879 * @param {Roo.EventObject} e The event object
34884 * Fires just before the field blurs if the field value has changed.
34885 * @param {Roo.form.Field} this
34886 * @param {Mixed} newValue The new value
34887 * @param {Mixed} oldValue The original value
34892 * Fires after the field has been marked as invalid.
34893 * @param {Roo.form.Field} this
34894 * @param {String} msg The validation message
34899 * Fires after the field has been validated with no errors.
34900 * @param {Roo.form.Field} this
34907 * Returns the name attribute of the field if available
34908 * @return {String} name The field name
34910 getName: function(){
34911 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
34915 onRender : function(ct, position){
34916 Roo.form.Field.superclass.onRender.call(this, ct, position);
34918 var cfg = this.getAutoCreate();
34920 cfg.name = this.name || this.id;
34922 if(this.inputType){
34923 cfg.type = this.inputType;
34925 this.el = ct.createChild(cfg, position);
34927 var type = this.el.dom.type;
34929 if(type == 'password'){
34932 this.el.addClass('x-form-'+type);
34935 this.el.dom.readOnly = true;
34937 if(this.tabIndex !== undefined){
34938 this.el.dom.setAttribute('tabIndex', this.tabIndex);
34941 this.el.addClass([this.fieldClass, this.cls]);
34946 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
34947 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
34948 * @return {Roo.form.Field} this
34950 applyTo : function(target){
34951 this.allowDomMove = false;
34952 this.el = Roo.get(target);
34953 this.render(this.el.dom.parentNode);
34958 initValue : function(){
34959 if(this.value !== undefined){
34960 this.setValue(this.value);
34961 }else if(this.el.dom.value.length > 0){
34962 this.setValue(this.el.dom.value);
34967 * Returns true if this field has been changed since it was originally loaded and is not disabled.
34969 isDirty : function() {
34970 if(this.disabled) {
34973 return String(this.getValue()) !== String(this.originalValue);
34977 afterRender : function(){
34978 Roo.form.Field.superclass.afterRender.call(this);
34983 fireKey : function(e){
34984 if(e.isNavKeyPress()){
34985 this.fireEvent("specialkey", this, e);
34990 * Resets the current field value to the originally loaded value and clears any validation messages
34992 reset : function(){
34993 this.setValue(this.originalValue);
34994 this.clearInvalid();
34998 initEvents : function(){
34999 this.el.on(Roo.isIE ? "keydown" : "keypress", this.fireKey, this);
35000 this.el.on("focus", this.onFocus, this);
35001 this.el.on("blur", this.onBlur, this);
35003 // reference to original value for reset
35004 this.originalValue = this.getValue();
35008 onFocus : function(){
35009 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35010 this.el.addClass(this.focusClass);
35012 if(!this.hasFocus){
35013 this.hasFocus = true;
35014 this.startValue = this.getValue();
35015 this.fireEvent("focus", this);
35019 beforeBlur : Roo.emptyFn,
35022 onBlur : function(){
35024 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35025 this.el.removeClass(this.focusClass);
35027 this.hasFocus = false;
35028 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35031 var v = this.getValue();
35032 if(String(v) !== String(this.startValue)){
35033 this.fireEvent('change', this, v, this.startValue);
35035 this.fireEvent("blur", this);
35039 * Returns whether or not the field value is currently valid
35040 * @param {Boolean} preventMark True to disable marking the field invalid
35041 * @return {Boolean} True if the value is valid, else false
35043 isValid : function(preventMark){
35047 var restore = this.preventMark;
35048 this.preventMark = preventMark === true;
35049 var v = this.validateValue(this.processValue(this.getRawValue()));
35050 this.preventMark = restore;
35055 * Validates the field value
35056 * @return {Boolean} True if the value is valid, else false
35058 validate : function(){
35059 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35060 this.clearInvalid();
35066 processValue : function(value){
35071 // Subclasses should provide the validation implementation by overriding this
35072 validateValue : function(value){
35077 * Mark this field as invalid
35078 * @param {String} msg The validation message
35080 markInvalid : function(msg){
35081 if(!this.rendered || this.preventMark){ // not rendered
35084 this.el.addClass(this.invalidClass);
35085 msg = msg || this.invalidText;
35086 switch(this.msgTarget){
35088 this.el.dom.qtip = msg;
35089 this.el.dom.qclass = 'x-form-invalid-tip';
35090 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35091 Roo.QuickTips.enable();
35095 this.el.dom.title = msg;
35099 var elp = this.el.findParent('.x-form-element', 5, true);
35100 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35101 this.errorEl.setWidth(elp.getWidth(true)-20);
35103 this.errorEl.update(msg);
35104 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35107 if(!this.errorIcon){
35108 var elp = this.el.findParent('.x-form-element', 5, true);
35109 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35111 this.alignErrorIcon();
35112 this.errorIcon.dom.qtip = msg;
35113 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35114 this.errorIcon.show();
35115 this.on('resize', this.alignErrorIcon, this);
35118 var t = Roo.getDom(this.msgTarget);
35120 t.style.display = this.msgDisplay;
35123 this.fireEvent('invalid', this, msg);
35127 alignErrorIcon : function(){
35128 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35132 * Clear any invalid styles/messages for this field
35134 clearInvalid : function(){
35135 if(!this.rendered || this.preventMark){ // not rendered
35138 this.el.removeClass(this.invalidClass);
35139 switch(this.msgTarget){
35141 this.el.dom.qtip = '';
35144 this.el.dom.title = '';
35148 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35152 if(this.errorIcon){
35153 this.errorIcon.dom.qtip = '';
35154 this.errorIcon.hide();
35155 this.un('resize', this.alignErrorIcon, this);
35159 var t = Roo.getDom(this.msgTarget);
35161 t.style.display = 'none';
35164 this.fireEvent('valid', this);
35168 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35169 * @return {Mixed} value The field value
35171 getRawValue : function(){
35172 var v = this.el.getValue();
35173 if(v === this.emptyText){
35180 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
35181 * @return {Mixed} value The field value
35183 getValue : function(){
35184 var v = this.el.getValue();
35185 if(v === this.emptyText || v === undefined){
35192 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
35193 * @param {Mixed} value The value to set
35195 setRawValue : function(v){
35196 return this.el.dom.value = (v === null || v === undefined ? '' : v);
35200 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
35201 * @param {Mixed} value The value to set
35203 setValue : function(v){
35206 this.el.dom.value = (v === null || v === undefined ? '' : v);
35211 adjustSize : function(w, h){
35212 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
35213 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
35217 adjustWidth : function(tag, w){
35218 tag = tag.toLowerCase();
35219 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
35220 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
35221 if(tag == 'input'){
35224 if(tag = 'textarea'){
35227 }else if(Roo.isOpera){
35228 if(tag == 'input'){
35231 if(tag = 'textarea'){
35241 // anything other than normal should be considered experimental
35242 Roo.form.Field.msgFx = {
35244 show: function(msgEl, f){
35245 msgEl.setDisplayed('block');
35248 hide : function(msgEl, f){
35249 msgEl.setDisplayed(false).update('');
35254 show: function(msgEl, f){
35255 msgEl.slideIn('t', {stopFx:true});
35258 hide : function(msgEl, f){
35259 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
35264 show: function(msgEl, f){
35265 msgEl.fixDisplay();
35266 msgEl.alignTo(f.el, 'tl-tr');
35267 msgEl.slideIn('l', {stopFx:true});
35270 hide : function(msgEl, f){
35271 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
35276 * Ext JS Library 1.1.1
35277 * Copyright(c) 2006-2007, Ext JS, LLC.
35279 * Originally Released Under LGPL - original licence link has changed is not relivant.
35282 * <script type="text/javascript">
35287 * @class Roo.form.TextField
35288 * @extends Roo.form.Field
35289 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
35290 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
35292 * Creates a new TextField
35293 * @param {Object} config Configuration options
35295 Roo.form.TextField = function(config){
35296 Roo.form.TextField.superclass.constructor.call(this, config);
35300 * Fires when the autosize function is triggered. The field may or may not have actually changed size
35301 * according to the default logic, but this event provides a hook for the developer to apply additional
35302 * logic at runtime to resize the field if needed.
35303 * @param {Roo.form.Field} this This text field
35304 * @param {Number} width The new field width
35310 Roo.extend(Roo.form.TextField, Roo.form.Field, {
35312 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
35316 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
35320 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
35324 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
35328 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
35332 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
35334 disableKeyFilter : false,
35336 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
35340 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
35344 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
35346 maxLength : Number.MAX_VALUE,
35348 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
35350 minLengthText : "The minimum length for this field is {0}",
35352 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
35354 maxLengthText : "The maximum length for this field is {0}",
35356 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
35358 selectOnFocus : false,
35360 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
35362 blankText : "This field is required",
35364 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
35365 * If available, this function will be called only after the basic validators all return true, and will be passed the
35366 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
35370 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
35371 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
35372 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
35376 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
35380 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
35384 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
35385 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
35387 emptyClass : 'x-form-empty-field',
35390 initEvents : function(){
35391 Roo.form.TextField.superclass.initEvents.call(this);
35392 if(this.validationEvent == 'keyup'){
35393 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
35394 this.el.on('keyup', this.filterValidation, this);
35396 else if(this.validationEvent !== false){
35397 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
35399 if(this.selectOnFocus || this.emptyText){
35400 this.on("focus", this.preFocus, this);
35401 if(this.emptyText){
35402 this.on('blur', this.postBlur, this);
35403 this.applyEmptyText();
35406 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
35407 this.el.on("keypress", this.filterKeys, this);
35410 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
35411 this.el.on("click", this.autoSize, this);
35415 processValue : function(value){
35416 if(this.stripCharsRe){
35417 var newValue = value.replace(this.stripCharsRe, '');
35418 if(newValue !== value){
35419 this.setRawValue(newValue);
35426 filterValidation : function(e){
35427 if(!e.isNavKeyPress()){
35428 this.validationTask.delay(this.validationDelay);
35433 onKeyUp : function(e){
35434 if(!e.isNavKeyPress()){
35440 * Resets the current field value to the originally-loaded value and clears any validation messages.
35441 * Also adds emptyText and emptyClass if the original value was blank.
35443 reset : function(){
35444 Roo.form.TextField.superclass.reset.call(this);
35445 this.applyEmptyText();
35448 applyEmptyText : function(){
35449 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
35450 this.setRawValue(this.emptyText);
35451 this.el.addClass(this.emptyClass);
35456 preFocus : function(){
35457 if(this.emptyText){
35458 if(this.el.dom.value == this.emptyText){
35459 this.setRawValue('');
35461 this.el.removeClass(this.emptyClass);
35463 if(this.selectOnFocus){
35464 this.el.dom.select();
35469 postBlur : function(){
35470 this.applyEmptyText();
35474 filterKeys : function(e){
35475 var k = e.getKey();
35476 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
35479 var c = e.getCharCode(), cc = String.fromCharCode(c);
35480 if(Roo.isIE && (e.isSpecialKey() || !cc)){
35483 if(!this.maskRe.test(cc)){
35488 setValue : function(v){
35489 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
35490 this.el.removeClass(this.emptyClass);
35492 Roo.form.TextField.superclass.setValue.apply(this, arguments);
35493 this.applyEmptyText();
35498 * Validates a value according to the field's validation rules and marks the field as invalid
35499 * if the validation fails
35500 * @param {Mixed} value The value to validate
35501 * @return {Boolean} True if the value is valid, else false
35503 validateValue : function(value){
35504 if(value.length < 1 || value === this.emptyText){ // if it's blank
35505 if(this.allowBlank){
35506 this.clearInvalid();
35509 this.markInvalid(this.blankText);
35513 if(value.length < this.minLength){
35514 this.markInvalid(String.format(this.minLengthText, this.minLength));
35517 if(value.length > this.maxLength){
35518 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
35522 var vt = Roo.form.VTypes;
35523 if(!vt[this.vtype](value, this)){
35524 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
35528 if(typeof this.validator == "function"){
35529 var msg = this.validator(value);
35531 this.markInvalid(msg);
35535 if(this.regex && !this.regex.test(value)){
35536 this.markInvalid(this.regexText);
35543 * Selects text in this field
35544 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
35545 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
35547 selectText : function(start, end){
35548 var v = this.getRawValue();
35550 start = start === undefined ? 0 : start;
35551 end = end === undefined ? v.length : end;
35552 var d = this.el.dom;
35553 if(d.setSelectionRange){
35554 d.setSelectionRange(start, end);
35555 }else if(d.createTextRange){
35556 var range = d.createTextRange();
35557 range.moveStart("character", start);
35558 range.moveEnd("character", v.length-end);
35565 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
35566 * This only takes effect if grow = true, and fires the autosize event.
35568 autoSize : function(){
35569 if(!this.grow || !this.rendered){
35573 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
35576 var v = el.dom.value;
35577 var d = document.createElement('div');
35578 d.appendChild(document.createTextNode(v));
35582 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
35583 this.el.setWidth(w);
35584 this.fireEvent("autosize", this, w);
35588 * Ext JS Library 1.1.1
35589 * Copyright(c) 2006-2007, Ext JS, LLC.
35591 * Originally Released Under LGPL - original licence link has changed is not relivant.
35594 * <script type="text/javascript">
35598 * @class Roo.form.Hidden
35599 * @extends Roo.form.TextField
35600 * Simple Hidden element used on forms
35602 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
35605 * Creates a new Hidden form element.
35606 * @param {Object} config Configuration options
35611 // easy hidden field...
35612 Roo.form.Hidden = function(config){
35613 Roo.form.Hidden.superclass.constructor.call(this, config);
35616 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
35618 inputType: 'hidden',
35621 labelSeparator: '',
35623 itemCls : 'x-form-item-display-none'
35631 * Ext JS Library 1.1.1
35632 * Copyright(c) 2006-2007, Ext JS, LLC.
35634 * Originally Released Under LGPL - original licence link has changed is not relivant.
35637 * <script type="text/javascript">
35641 * @class Roo.form.TriggerField
35642 * @extends Roo.form.TextField
35643 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
35644 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
35645 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
35646 * for which you can provide a custom implementation. For example:
35648 var trigger = new Roo.form.TriggerField();
35649 trigger.onTriggerClick = myTriggerFn;
35650 trigger.applyTo('my-field');
35653 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
35654 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
35655 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
35656 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
35658 * Create a new TriggerField.
35659 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
35660 * to the base TextField)
35662 Roo.form.TriggerField = function(config){
35663 this.mimicing = false;
35664 Roo.form.TriggerField.superclass.constructor.call(this, config);
35667 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
35669 * @cfg {String} triggerClass A CSS class to apply to the trigger
35672 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35673 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
35675 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
35677 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
35681 /** @cfg {Boolean} grow @hide */
35682 /** @cfg {Number} growMin @hide */
35683 /** @cfg {Number} growMax @hide */
35689 autoSize: Roo.emptyFn,
35693 deferHeight : true,
35696 actionMode : 'wrap',
35698 onResize : function(w, h){
35699 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
35700 if(typeof w == 'number'){
35701 this.el.setWidth(this.adjustWidth('input', w - this.trigger.getWidth()));
35706 adjustSize : Roo.BoxComponent.prototype.adjustSize,
35709 getResizeEl : function(){
35714 getPositionEl : function(){
35719 alignErrorIcon : function(){
35720 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
35724 onRender : function(ct, position){
35725 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
35726 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
35727 this.trigger = this.wrap.createChild(this.triggerConfig ||
35728 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
35729 if(this.hideTrigger){
35730 this.trigger.setDisplayed(false);
35732 this.initTrigger();
35734 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
35739 initTrigger : function(){
35740 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
35741 this.trigger.addClassOnOver('x-form-trigger-over');
35742 this.trigger.addClassOnClick('x-form-trigger-click');
35746 onDestroy : function(){
35748 this.trigger.removeAllListeners();
35749 this.trigger.remove();
35752 this.wrap.remove();
35754 Roo.form.TriggerField.superclass.onDestroy.call(this);
35758 onFocus : function(){
35759 Roo.form.TriggerField.superclass.onFocus.call(this);
35760 if(!this.mimicing){
35761 this.wrap.addClass('x-trigger-wrap-focus');
35762 this.mimicing = true;
35763 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
35764 if(this.monitorTab){
35765 this.el.on("keydown", this.checkTab, this);
35771 checkTab : function(e){
35772 if(e.getKey() == e.TAB){
35773 this.triggerBlur();
35778 onBlur : function(){
35783 mimicBlur : function(e, t){
35784 if(!this.wrap.contains(t) && this.validateBlur()){
35785 this.triggerBlur();
35790 triggerBlur : function(){
35791 this.mimicing = false;
35792 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
35793 if(this.monitorTab){
35794 this.el.un("keydown", this.checkTab, this);
35796 this.wrap.removeClass('x-trigger-wrap-focus');
35797 Roo.form.TriggerField.superclass.onBlur.call(this);
35801 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
35802 validateBlur : function(e, t){
35807 onDisable : function(){
35808 Roo.form.TriggerField.superclass.onDisable.call(this);
35810 this.wrap.addClass('x-item-disabled');
35815 onEnable : function(){
35816 Roo.form.TriggerField.superclass.onEnable.call(this);
35818 this.wrap.removeClass('x-item-disabled');
35823 onShow : function(){
35824 var ae = this.getActionEl();
35827 ae.dom.style.display = '';
35828 ae.dom.style.visibility = 'visible';
35834 onHide : function(){
35835 var ae = this.getActionEl();
35836 ae.dom.style.display = 'none';
35840 * The function that should handle the trigger's click event. This method does nothing by default until overridden
35841 * by an implementing function.
35843 * @param {EventObject} e
35845 onTriggerClick : Roo.emptyFn
35848 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
35849 // to be extended by an implementing class. For an example of implementing this class, see the custom
35850 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
35851 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
35852 initComponent : function(){
35853 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
35855 this.triggerConfig = {
35856 tag:'span', cls:'x-form-twin-triggers', cn:[
35857 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
35858 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
35862 getTrigger : function(index){
35863 return this.triggers[index];
35866 initTrigger : function(){
35867 var ts = this.trigger.select('.x-form-trigger', true);
35868 this.wrap.setStyle('overflow', 'hidden');
35869 var triggerField = this;
35870 ts.each(function(t, all, index){
35871 t.hide = function(){
35872 var w = triggerField.wrap.getWidth();
35873 this.dom.style.display = 'none';
35874 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
35876 t.show = function(){
35877 var w = triggerField.wrap.getWidth();
35878 this.dom.style.display = '';
35879 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
35881 var triggerIndex = 'Trigger'+(index+1);
35883 if(this['hide'+triggerIndex]){
35884 t.dom.style.display = 'none';
35886 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
35887 t.addClassOnOver('x-form-trigger-over');
35888 t.addClassOnClick('x-form-trigger-click');
35890 this.triggers = ts.elements;
35893 onTrigger1Click : Roo.emptyFn,
35894 onTrigger2Click : Roo.emptyFn
35897 * Ext JS Library 1.1.1
35898 * Copyright(c) 2006-2007, Ext JS, LLC.
35900 * Originally Released Under LGPL - original licence link has changed is not relivant.
35903 * <script type="text/javascript">
35907 * @class Roo.form.TextArea
35908 * @extends Roo.form.TextField
35909 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
35910 * support for auto-sizing.
35912 * Creates a new TextArea
35913 * @param {Object} config Configuration options
35915 Roo.form.TextArea = function(config){
35916 Roo.form.TextArea.superclass.constructor.call(this, config);
35917 // these are provided exchanges for backwards compat
35918 // minHeight/maxHeight were replaced by growMin/growMax to be
35919 // compatible with TextField growing config values
35920 if(this.minHeight !== undefined){
35921 this.growMin = this.minHeight;
35923 if(this.maxHeight !== undefined){
35924 this.growMax = this.maxHeight;
35928 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
35930 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
35934 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
35938 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
35939 * in the field (equivalent to setting overflow: hidden, defaults to false)
35941 preventScrollbars: false,
35943 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35944 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
35948 onRender : function(ct, position){
35950 this.defaultAutoCreate = {
35952 style:"width:300px;height:60px;",
35953 autocomplete: "off"
35956 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
35958 this.textSizeEl = Roo.DomHelper.append(document.body, {
35959 tag: "pre", cls: "x-form-grow-sizer"
35961 if(this.preventScrollbars){
35962 this.el.setStyle("overflow", "hidden");
35964 this.el.setHeight(this.growMin);
35968 onDestroy : function(){
35969 if(this.textSizeEl){
35970 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
35972 Roo.form.TextArea.superclass.onDestroy.call(this);
35976 onKeyUp : function(e){
35977 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
35983 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
35984 * This only takes effect if grow = true, and fires the autosize event if the height changes.
35986 autoSize : function(){
35987 if(!this.grow || !this.textSizeEl){
35991 var v = el.dom.value;
35992 var ts = this.textSizeEl;
35995 ts.appendChild(document.createTextNode(v));
35998 Roo.fly(ts).setWidth(this.el.getWidth());
36000 v = "  ";
36003 v = v.replace(/\n/g, '<p> </p>');
36005 v += " \n ";
36008 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36009 if(h != this.lastHeight){
36010 this.lastHeight = h;
36011 this.el.setHeight(h);
36012 this.fireEvent("autosize", this, h);
36017 * Ext JS Library 1.1.1
36018 * Copyright(c) 2006-2007, Ext JS, LLC.
36020 * Originally Released Under LGPL - original licence link has changed is not relivant.
36023 * <script type="text/javascript">
36028 * @class Roo.form.NumberField
36029 * @extends Roo.form.TextField
36030 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36032 * Creates a new NumberField
36033 * @param {Object} config Configuration options
36035 Roo.form.NumberField = function(config){
36036 Roo.form.NumberField.superclass.constructor.call(this, config);
36039 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36041 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36043 fieldClass: "x-form-field x-form-num-field",
36045 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36047 allowDecimals : true,
36049 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36051 decimalSeparator : ".",
36053 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36055 decimalPrecision : 2,
36057 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36059 allowNegative : true,
36061 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36063 minValue : Number.NEGATIVE_INFINITY,
36065 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36067 maxValue : Number.MAX_VALUE,
36069 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36071 minText : "The minimum value for this field is {0}",
36073 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36075 maxText : "The maximum value for this field is {0}",
36077 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36078 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36080 nanText : "{0} is not a valid number",
36083 initEvents : function(){
36084 Roo.form.NumberField.superclass.initEvents.call(this);
36085 var allowed = "0123456789";
36086 if(this.allowDecimals){
36087 allowed += this.decimalSeparator;
36089 if(this.allowNegative){
36092 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36093 var keyPress = function(e){
36094 var k = e.getKey();
36095 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36098 var c = e.getCharCode();
36099 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36103 this.el.on("keypress", keyPress, this);
36107 validateValue : function(value){
36108 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36111 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36114 var num = this.parseValue(value);
36116 this.markInvalid(String.format(this.nanText, value));
36119 if(num < this.minValue){
36120 this.markInvalid(String.format(this.minText, this.minValue));
36123 if(num > this.maxValue){
36124 this.markInvalid(String.format(this.maxText, this.maxValue));
36130 getValue : function(){
36131 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36135 parseValue : function(value){
36136 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36137 return isNaN(value) ? '' : value;
36141 fixPrecision : function(value){
36142 var nan = isNaN(value);
36143 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36144 return nan ? '' : value;
36146 return parseFloat(value).toFixed(this.decimalPrecision);
36149 setValue : function(v){
36150 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36154 decimalPrecisionFcn : function(v){
36155 return Math.floor(v);
36158 beforeBlur : function(){
36159 var v = this.parseValue(this.getRawValue());
36161 this.setValue(this.fixPrecision(v));
36166 * Ext JS Library 1.1.1
36167 * Copyright(c) 2006-2007, Ext JS, LLC.
36169 * Originally Released Under LGPL - original licence link has changed is not relivant.
36172 * <script type="text/javascript">
36176 * @class Roo.form.DateField
36177 * @extends Roo.form.TriggerField
36178 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
36180 * Create a new DateField
36181 * @param {Object} config
36183 Roo.form.DateField = function(config){
36184 Roo.form.DateField.superclass.constructor.call(this, config);
36190 * Fires when a date is selected
36191 * @param {Roo.form.DateField} combo This combo box
36192 * @param {Date} date The date selected
36199 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
36200 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
36201 this.ddMatch = null;
36202 if(this.disabledDates){
36203 var dd = this.disabledDates;
36205 for(var i = 0; i < dd.length; i++){
36207 if(i != dd.length-1) re += "|";
36209 this.ddMatch = new RegExp(re + ")");
36213 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
36215 * @cfg {String} format
36216 * The default date format string which can be overriden for localization support. The format must be
36217 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
36221 * @cfg {String} altFormats
36222 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
36223 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
36225 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
36227 * @cfg {Array} disabledDays
36228 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
36230 disabledDays : null,
36232 * @cfg {String} disabledDaysText
36233 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
36235 disabledDaysText : "Disabled",
36237 * @cfg {Array} disabledDates
36238 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
36239 * expression so they are very powerful. Some examples:
36241 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
36242 * <li>["03/08", "09/16"] would disable those days for every year</li>
36243 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
36244 * <li>["03/../2006"] would disable every day in March 2006</li>
36245 * <li>["^03"] would disable every day in every March</li>
36247 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
36248 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
36250 disabledDates : null,
36252 * @cfg {String} disabledDatesText
36253 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
36255 disabledDatesText : "Disabled",
36257 * @cfg {Date/String} minValue
36258 * The minimum allowed date. Can be either a Javascript date object or a string date in a
36259 * valid format (defaults to null).
36263 * @cfg {Date/String} maxValue
36264 * The maximum allowed date. Can be either a Javascript date object or a string date in a
36265 * valid format (defaults to null).
36269 * @cfg {String} minText
36270 * The error text to display when the date in the cell is before minValue (defaults to
36271 * 'The date in this field must be after {minValue}').
36273 minText : "The date in this field must be equal to or after {0}",
36275 * @cfg {String} maxText
36276 * The error text to display when the date in the cell is after maxValue (defaults to
36277 * 'The date in this field must be before {maxValue}').
36279 maxText : "The date in this field must be equal to or before {0}",
36281 * @cfg {String} invalidText
36282 * The error text to display when the date in the field is invalid (defaults to
36283 * '{value} is not a valid date - it must be in the format {format}').
36285 invalidText : "{0} is not a valid date - it must be in the format {1}",
36287 * @cfg {String} triggerClass
36288 * An additional CSS class used to style the trigger button. The trigger will always get the
36289 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
36290 * which displays a calendar icon).
36292 triggerClass : 'x-form-date-trigger',
36296 * @cfg {bool} useIso
36297 * if enabled, then the date field will use a hidden field to store the
36298 * real value as iso formated date. default (false)
36302 * @cfg {String/Object} autoCreate
36303 * A DomHelper element spec, or true for a default element spec (defaults to
36304 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
36307 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
36310 hiddenField: false,
36312 onRender : function(ct, position)
36314 Roo.form.DateField.superclass.onRender.call(this, ct, position);
36316 this.el.dom.removeAttribute('name');
36317 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
36319 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
36320 // prevent input submission
36321 this.hiddenName = this.name;
36328 validateValue : function(value)
36330 value = this.formatDate(value);
36331 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
36334 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36337 var svalue = value;
36338 value = this.parseDate(value);
36340 this.markInvalid(String.format(this.invalidText, svalue, this.format));
36343 var time = value.getTime();
36344 if(this.minValue && time < this.minValue.getTime()){
36345 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
36348 if(this.maxValue && time > this.maxValue.getTime()){
36349 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
36352 if(this.disabledDays){
36353 var day = value.getDay();
36354 for(var i = 0; i < this.disabledDays.length; i++) {
36355 if(day === this.disabledDays[i]){
36356 this.markInvalid(this.disabledDaysText);
36361 var fvalue = this.formatDate(value);
36362 if(this.ddMatch && this.ddMatch.test(fvalue)){
36363 this.markInvalid(String.format(this.disabledDatesText, fvalue));
36370 // Provides logic to override the default TriggerField.validateBlur which just returns true
36371 validateBlur : function(){
36372 return !this.menu || !this.menu.isVisible();
36376 * Returns the current date value of the date field.
36377 * @return {Date} The date value
36379 getValue : function(){
36381 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
36385 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
36386 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
36387 * (the default format used is "m/d/y").
36390 //All of these calls set the same date value (May 4, 2006)
36392 //Pass a date object:
36393 var dt = new Date('5/4/06');
36394 dateField.setValue(dt);
36396 //Pass a date string (default format):
36397 dateField.setValue('5/4/06');
36399 //Pass a date string (custom format):
36400 dateField.format = 'Y-m-d';
36401 dateField.setValue('2006-5-4');
36403 * @param {String/Date} date The date or valid date string
36405 setValue : function(date){
36406 if (this.hiddenField) {
36407 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
36409 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
36413 parseDate : function(value){
36414 if(!value || value instanceof Date){
36417 var v = Date.parseDate(value, this.format);
36418 if(!v && this.altFormats){
36419 if(!this.altFormatsArray){
36420 this.altFormatsArray = this.altFormats.split("|");
36422 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
36423 v = Date.parseDate(value, this.altFormatsArray[i]);
36430 formatDate : function(date, fmt){
36431 return (!date || !(date instanceof Date)) ?
36432 date : date.dateFormat(fmt || this.format);
36437 select: function(m, d){
36439 this.fireEvent('select', this, d);
36441 show : function(){ // retain focus styling
36445 this.focus.defer(10, this);
36446 var ml = this.menuListeners;
36447 this.menu.un("select", ml.select, this);
36448 this.menu.un("show", ml.show, this);
36449 this.menu.un("hide", ml.hide, this);
36454 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
36455 onTriggerClick : function(){
36459 if(this.menu == null){
36460 this.menu = new Roo.menu.DateMenu();
36462 Roo.apply(this.menu.picker, {
36463 showClear: this.allowBlank,
36464 minDate : this.minValue,
36465 maxDate : this.maxValue,
36466 disabledDatesRE : this.ddMatch,
36467 disabledDatesText : this.disabledDatesText,
36468 disabledDays : this.disabledDays,
36469 disabledDaysText : this.disabledDaysText,
36470 format : this.format,
36471 minText : String.format(this.minText, this.formatDate(this.minValue)),
36472 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
36474 this.menu.on(Roo.apply({}, this.menuListeners, {
36477 this.menu.picker.setValue(this.getValue() || new Date());
36478 this.menu.show(this.el, "tl-bl?");
36481 beforeBlur : function(){
36482 var v = this.parseDate(this.getRawValue());
36488 /** @cfg {Boolean} grow @hide */
36489 /** @cfg {Number} growMin @hide */
36490 /** @cfg {Number} growMax @hide */
36497 * Ext JS Library 1.1.1
36498 * Copyright(c) 2006-2007, Ext JS, LLC.
36500 * Originally Released Under LGPL - original licence link has changed is not relivant.
36503 * <script type="text/javascript">
36508 * @class Roo.form.ComboBox
36509 * @extends Roo.form.TriggerField
36510 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
36512 * Create a new ComboBox.
36513 * @param {Object} config Configuration options
36515 Roo.form.ComboBox = function(config){
36516 Roo.form.ComboBox.superclass.constructor.call(this, config);
36520 * Fires when the dropdown list is expanded
36521 * @param {Roo.form.ComboBox} combo This combo box
36526 * Fires when the dropdown list is collapsed
36527 * @param {Roo.form.ComboBox} combo This combo box
36531 * @event beforeselect
36532 * Fires before a list item is selected. Return false to cancel the selection.
36533 * @param {Roo.form.ComboBox} combo This combo box
36534 * @param {Roo.data.Record} record The data record returned from the underlying store
36535 * @param {Number} index The index of the selected item in the dropdown list
36537 'beforeselect' : true,
36540 * Fires when a list item is selected
36541 * @param {Roo.form.ComboBox} combo This combo box
36542 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
36543 * @param {Number} index The index of the selected item in the dropdown list
36547 * @event beforequery
36548 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
36549 * The event object passed has these properties:
36550 * @param {Roo.form.ComboBox} combo This combo box
36551 * @param {String} query The query
36552 * @param {Boolean} forceAll true to force "all" query
36553 * @param {Boolean} cancel true to cancel the query
36554 * @param {Object} e The query event object
36556 'beforequery': true
36558 if(this.transform){
36559 this.allowDomMove = false;
36560 var s = Roo.getDom(this.transform);
36561 if(!this.hiddenName){
36562 this.hiddenName = s.name;
36565 this.mode = 'local';
36566 var d = [], opts = s.options;
36567 for(var i = 0, len = opts.length;i < len; i++){
36569 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
36571 this.value = value;
36573 d.push([value, o.text]);
36575 this.store = new Roo.data.SimpleStore({
36577 fields: ['value', 'text'],
36580 this.valueField = 'value';
36581 this.displayField = 'text';
36583 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
36584 if(!this.lazyRender){
36585 this.target = true;
36586 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
36587 s.parentNode.removeChild(s); // remove it
36588 this.render(this.el.parentNode);
36590 s.parentNode.removeChild(s); // remove it
36595 this.store = Roo.factory(this.store, Roo.data);
36598 this.selectedIndex = -1;
36599 if(this.mode == 'local'){
36600 if(config.queryDelay === undefined){
36601 this.queryDelay = 10;
36603 if(config.minChars === undefined){
36609 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
36611 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
36614 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
36615 * rendering into an Roo.Editor, defaults to false)
36618 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
36619 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
36622 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
36625 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
36626 * the dropdown list (defaults to undefined, with no header element)
36630 * @cfg {String/Roo.Template} tpl The template to use to render the output
36634 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
36636 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
36638 listWidth: undefined,
36640 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
36641 * mode = 'remote' or 'text' if mode = 'local')
36643 displayField: undefined,
36645 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
36646 * mode = 'remote' or 'value' if mode = 'local').
36647 * Note: use of a valueField requires the user make a selection
36648 * in order for a value to be mapped.
36650 valueField: undefined,
36652 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
36653 * field's data value (defaults to the underlying DOM element's name)
36655 hiddenName: undefined,
36657 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
36661 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
36663 selectedClass: 'x-combo-selected',
36665 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36666 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
36667 * which displays a downward arrow icon).
36669 triggerClass : 'x-form-arrow-trigger',
36671 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
36675 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
36676 * anchor positions (defaults to 'tl-bl')
36678 listAlign: 'tl-bl?',
36680 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
36684 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
36685 * query specified by the allQuery config option (defaults to 'query')
36687 triggerAction: 'query',
36689 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
36690 * (defaults to 4, does not apply if editable = false)
36694 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
36695 * delay (typeAheadDelay) if it matches a known value (defaults to false)
36699 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
36700 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
36704 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
36705 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
36709 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
36710 * when editable = true (defaults to false)
36712 selectOnFocus:false,
36714 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
36716 queryParam: 'query',
36718 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
36719 * when mode = 'remote' (defaults to 'Loading...')
36721 loadingText: 'Loading...',
36723 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
36727 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
36731 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
36732 * traditional select (defaults to true)
36736 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
36740 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
36744 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
36745 * listWidth has a higher value)
36749 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
36750 * allow the user to set arbitrary text into the field (defaults to false)
36752 forceSelection:false,
36754 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
36755 * if typeAhead = true (defaults to 250)
36757 typeAheadDelay : 250,
36759 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
36760 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
36762 valueNotFoundText : undefined,
36764 * @cfg {bool} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
36766 blockFocus : false,
36769 * @cfg {bool} disableClear Disable showing of clear button.
36771 disableClear : false,
36774 onRender : function(ct, position){
36775 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
36776 if(this.hiddenName){
36777 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
36779 this.hiddenField.value =
36780 this.hiddenValue !== undefined ? this.hiddenValue :
36781 this.value !== undefined ? this.value : '';
36783 // prevent input submission
36784 this.el.dom.removeAttribute('name');
36787 this.el.dom.setAttribute('autocomplete', 'off');
36790 var cls = 'x-combo-list';
36792 this.list = new Roo.Layer({
36793 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
36796 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
36797 this.list.setWidth(lw);
36798 this.list.swallowEvent('mousewheel');
36799 this.assetHeight = 0;
36802 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
36803 this.assetHeight += this.header.getHeight();
36806 this.innerList = this.list.createChild({cls:cls+'-inner'});
36807 this.innerList.on('mouseover', this.onViewOver, this);
36808 this.innerList.on('mousemove', this.onViewMove, this);
36809 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
36811 if(this.allowBlank && !this.pageSize && !this.disableClear){
36812 this.footer = this.list.createChild({cls:cls+'-ft'});
36813 this.pageTb = new Roo.Toolbar(this.footer);
36817 this.footer = this.list.createChild({cls:cls+'-ft'});
36818 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
36819 {pageSize: this.pageSize});
36823 if (this.pageTb && this.allowBlank && !this.disableClear) {
36825 this.pageTb.add(new Roo.Toolbar.Fill(), {
36826 cls: 'x-btn-icon x-btn-clear',
36828 handler: function()
36831 _this.clearValue();
36832 _this.onSelect(false, -1);
36837 this.assetHeight += this.footer.getHeight();
36842 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
36845 this.view = new Roo.View(this.innerList, this.tpl, {
36846 singleSelect:true, store: this.store, selectedClass: this.selectedClass
36849 this.view.on('click', this.onViewClick, this);
36851 this.store.on('beforeload', this.onBeforeLoad, this);
36852 this.store.on('load', this.onLoad, this);
36853 this.store.on('loadexception', this.collapse, this);
36855 if(this.resizable){
36856 this.resizer = new Roo.Resizable(this.list, {
36857 pinned:true, handles:'se'
36859 this.resizer.on('resize', function(r, w, h){
36860 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
36861 this.listWidth = w;
36862 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
36863 this.restrictHeight();
36865 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
36867 if(!this.editable){
36868 this.editable = true;
36869 this.setEditable(false);
36874 initEvents : function(){
36875 Roo.form.ComboBox.superclass.initEvents.call(this);
36877 this.keyNav = new Roo.KeyNav(this.el, {
36878 "up" : function(e){
36879 this.inKeyMode = true;
36883 "down" : function(e){
36884 if(!this.isExpanded()){
36885 this.onTriggerClick();
36887 this.inKeyMode = true;
36892 "enter" : function(e){
36893 this.onViewClick();
36897 "esc" : function(e){
36901 "tab" : function(e){
36902 this.onViewClick(false);
36908 doRelay : function(foo, bar, hname){
36909 if(hname == 'down' || this.scope.isExpanded()){
36910 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
36917 this.queryDelay = Math.max(this.queryDelay || 10,
36918 this.mode == 'local' ? 10 : 250);
36919 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
36920 if(this.typeAhead){
36921 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
36923 if(this.editable !== false){
36924 this.el.on("keyup", this.onKeyUp, this);
36926 if(this.forceSelection){
36927 this.on('blur', this.doForce, this);
36931 onDestroy : function(){
36933 this.view.setStore(null);
36934 this.view.el.removeAllListeners();
36935 this.view.el.remove();
36936 this.view.purgeListeners();
36939 this.list.destroy();
36942 this.store.un('beforeload', this.onBeforeLoad, this);
36943 this.store.un('load', this.onLoad, this);
36944 this.store.un('loadexception', this.collapse, this);
36946 Roo.form.ComboBox.superclass.onDestroy.call(this);
36950 fireKey : function(e){
36951 if(e.isNavKeyPress() && !this.list.isVisible()){
36952 this.fireEvent("specialkey", this, e);
36957 onResize: function(w, h){
36958 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
36959 if(this.list && this.listWidth === undefined){
36960 var lw = Math.max(w, this.minListWidth);
36961 this.list.setWidth(lw);
36962 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
36967 * Allow or prevent the user from directly editing the field text. If false is passed,
36968 * the user will only be able to select from the items defined in the dropdown list. This method
36969 * is the runtime equivalent of setting the 'editable' config option at config time.
36970 * @param {Boolean} value True to allow the user to directly edit the field text
36972 setEditable : function(value){
36973 if(value == this.editable){
36976 this.editable = value;
36978 this.el.dom.setAttribute('readOnly', true);
36979 this.el.on('mousedown', this.onTriggerClick, this);
36980 this.el.addClass('x-combo-noedit');
36982 this.el.dom.setAttribute('readOnly', false);
36983 this.el.un('mousedown', this.onTriggerClick, this);
36984 this.el.removeClass('x-combo-noedit');
36989 onBeforeLoad : function(){
36990 if(!this.hasFocus){
36993 this.innerList.update(this.loadingText ?
36994 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
36995 this.restrictHeight();
36996 this.selectedIndex = -1;
37000 onLoad : function(){
37001 if(!this.hasFocus){
37004 if(this.store.getCount() > 0){
37006 this.restrictHeight();
37007 if(this.lastQuery == this.allQuery){
37009 this.el.dom.select();
37011 if(!this.selectByValue(this.value, true)){
37012 this.select(0, true);
37016 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37017 this.taTask.delay(this.typeAheadDelay);
37021 this.onEmptyResults();
37027 onTypeAhead : function(){
37028 if(this.store.getCount() > 0){
37029 var r = this.store.getAt(0);
37030 var newValue = r.data[this.displayField];
37031 var len = newValue.length;
37032 var selStart = this.getRawValue().length;
37033 if(selStart != len){
37034 this.setRawValue(newValue);
37035 this.selectText(selStart, newValue.length);
37041 onSelect : function(record, index){
37042 if(this.fireEvent('beforeselect', this, record, index) !== false){
37043 this.setFromData(index > -1 ? record.data : false);
37045 this.fireEvent('select', this, record, index);
37050 * Returns the currently selected field value or empty string if no value is set.
37051 * @return {String} value The selected value
37053 getValue : function(){
37054 if(this.valueField){
37055 return typeof this.value != 'undefined' ? this.value : '';
37057 return Roo.form.ComboBox.superclass.getValue.call(this);
37062 * Clears any text/value currently set in the field
37064 clearValue : function(){
37065 if(this.hiddenField){
37066 this.hiddenField.value = '';
37069 this.setRawValue('');
37070 this.lastSelectionText = '';
37071 this.applyEmptyText();
37075 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37076 * will be displayed in the field. If the value does not match the data value of an existing item,
37077 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37078 * Otherwise the field will be blank (although the value will still be set).
37079 * @param {String} value The value to match
37081 setValue : function(v){
37083 if(this.valueField){
37084 var r = this.findRecord(this.valueField, v);
37086 text = r.data[this.displayField];
37087 }else if(this.valueNotFoundText !== undefined){
37088 text = this.valueNotFoundText;
37091 this.lastSelectionText = text;
37092 if(this.hiddenField){
37093 this.hiddenField.value = v;
37095 Roo.form.ComboBox.superclass.setValue.call(this, text);
37099 * @property {Object} the last set data for the element
37104 * Sets the value of the field based on a object which is related to the record format for the store.
37105 * @param {Object} value the value to set as. or false on reset?
37107 setFromData : function(o){
37108 var dv = ''; // display value
37109 var vv = ''; // value value..
37111 if (this.displayField) {
37112 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
37114 // this is an error condition!!!
37115 console.log('no value field set for '+ this.name);
37118 if(this.valueField){
37119 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
37121 if(this.hiddenField){
37122 this.hiddenField.value = vv;
37124 this.lastSelectionText = dv;
37125 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37129 // no hidden field.. - we store the value in 'value', but still display
37130 // display field!!!!
37131 this.lastSelectionText = dv;
37132 Roo.form.ComboBox.superclass.setValue.call(this, dv);
37138 findRecord : function(prop, value){
37140 if(this.store.getCount() > 0){
37141 this.store.each(function(r){
37142 if(r.data[prop] == value){
37152 onViewMove : function(e, t){
37153 this.inKeyMode = false;
37157 onViewOver : function(e, t){
37158 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
37161 var item = this.view.findItemFromChild(t);
37163 var index = this.view.indexOf(item);
37164 this.select(index, false);
37169 onViewClick : function(doFocus){
37170 var index = this.view.getSelectedIndexes()[0];
37171 var r = this.store.getAt(index);
37173 this.onSelect(r, index);
37175 if(doFocus !== false && !this.blockFocus){
37181 restrictHeight : function(){
37182 this.innerList.dom.style.height = '';
37183 var inner = this.innerList.dom;
37184 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
37185 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
37186 this.list.beginUpdate();
37187 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
37188 this.list.alignTo(this.el, this.listAlign);
37189 this.list.endUpdate();
37193 onEmptyResults : function(){
37198 * Returns true if the dropdown list is expanded, else false.
37200 isExpanded : function(){
37201 return this.list.isVisible();
37205 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
37206 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37207 * @param {String} value The data value of the item to select
37208 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37209 * selected item if it is not currently in view (defaults to true)
37210 * @return {Boolean} True if the value matched an item in the list, else false
37212 selectByValue : function(v, scrollIntoView){
37213 if(v !== undefined && v !== null){
37214 var r = this.findRecord(this.valueField || this.displayField, v);
37216 this.select(this.store.indexOf(r), scrollIntoView);
37224 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
37225 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
37226 * @param {Number} index The zero-based index of the list item to select
37227 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
37228 * selected item if it is not currently in view (defaults to true)
37230 select : function(index, scrollIntoView){
37231 this.selectedIndex = index;
37232 this.view.select(index);
37233 if(scrollIntoView !== false){
37234 var el = this.view.getNode(index);
37236 this.innerList.scrollChildIntoView(el, false);
37242 selectNext : function(){
37243 var ct = this.store.getCount();
37245 if(this.selectedIndex == -1){
37247 }else if(this.selectedIndex < ct-1){
37248 this.select(this.selectedIndex+1);
37254 selectPrev : function(){
37255 var ct = this.store.getCount();
37257 if(this.selectedIndex == -1){
37259 }else if(this.selectedIndex != 0){
37260 this.select(this.selectedIndex-1);
37266 onKeyUp : function(e){
37267 if(this.editable !== false && !e.isSpecialKey()){
37268 this.lastKey = e.getKey();
37269 this.dqTask.delay(this.queryDelay);
37274 validateBlur : function(){
37275 return !this.list || !this.list.isVisible();
37279 initQuery : function(){
37280 this.doQuery(this.getRawValue());
37284 doForce : function(){
37285 if(this.el.dom.value.length > 0){
37286 this.el.dom.value =
37287 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
37288 this.applyEmptyText();
37293 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
37294 * query allowing the query action to be canceled if needed.
37295 * @param {String} query The SQL query to execute
37296 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
37297 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
37298 * saved in the current store (defaults to false)
37300 doQuery : function(q, forceAll){
37301 if(q === undefined || q === null){
37306 forceAll: forceAll,
37310 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
37314 forceAll = qe.forceAll;
37315 if(forceAll === true || (q.length >= this.minChars)){
37316 if(this.lastQuery != q){
37317 this.lastQuery = q;
37318 if(this.mode == 'local'){
37319 this.selectedIndex = -1;
37321 this.store.clearFilter();
37323 this.store.filter(this.displayField, q);
37327 this.store.baseParams[this.queryParam] = q;
37329 params: this.getParams(q)
37334 this.selectedIndex = -1;
37341 getParams : function(q){
37343 //p[this.queryParam] = q;
37346 p.limit = this.pageSize;
37352 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
37354 collapse : function(){
37355 if(!this.isExpanded()){
37359 Roo.get(document).un('mousedown', this.collapseIf, this);
37360 Roo.get(document).un('mousewheel', this.collapseIf, this);
37361 this.fireEvent('collapse', this);
37365 collapseIf : function(e){
37366 if(!e.within(this.wrap) && !e.within(this.list)){
37372 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
37374 expand : function(){
37375 if(this.isExpanded() || !this.hasFocus){
37378 this.list.alignTo(this.el, this.listAlign);
37380 Roo.get(document).on('mousedown', this.collapseIf, this);
37381 Roo.get(document).on('mousewheel', this.collapseIf, this);
37382 this.fireEvent('expand', this);
37386 // Implements the default empty TriggerField.onTriggerClick function
37387 onTriggerClick : function(){
37391 if(this.isExpanded()){
37393 if (!this.blockFocus) {
37398 this.hasFocus = true;
37399 if(this.triggerAction == 'all') {
37400 this.doQuery(this.allQuery, true);
37402 this.doQuery(this.getRawValue());
37404 if (!this.blockFocus) {
37410 /** @cfg {Boolean} grow @hide */
37411 /** @cfg {Number} growMin @hide */
37412 /** @cfg {Number} growMax @hide */
37419 * Ext JS Library 1.1.1
37420 * Copyright(c) 2006-2007, Ext JS, LLC.
37422 * Originally Released Under LGPL - original licence link has changed is not relivant.
37425 * <script type="text/javascript">
37428 * @class Roo.form.Checkbox
37429 * @extends Roo.form.Field
37430 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
37432 * Creates a new Checkbox
37433 * @param {Object} config Configuration options
37435 Roo.form.Checkbox = function(config){
37436 Roo.form.Checkbox.superclass.constructor.call(this, config);
37440 * Fires when the checkbox is checked or unchecked.
37441 * @param {Roo.form.Checkbox} this This checkbox
37442 * @param {Boolean} checked The new checked value
37448 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
37450 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
37452 focusClass : undefined,
37454 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
37456 fieldClass: "x-form-field",
37458 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
37462 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37463 * {tag: "input", type: "checkbox", autocomplete: "off"})
37465 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
37467 * @cfg {String} boxLabel The text that appears beside the checkbox
37471 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
37475 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
37477 valueOff: '0', // value when not checked..
37479 actionMode : 'viewEl',
37482 itemCls : 'x-menu-check-item x-form-item',
37483 groupClass : 'x-menu-group-item',
37484 inputType : 'hidden',
37487 inSetChecked: false, // check that we are not calling self...
37489 inputElement: false, // real input element?
37490 basedOn: false, // ????
37492 isFormField: true, // not sure where this is needed!!!!
37494 onResize : function(){
37495 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
37496 if(!this.boxLabel){
37497 this.el.alignTo(this.wrap, 'c-c');
37501 initEvents : function(){
37502 Roo.form.Checkbox.superclass.initEvents.call(this);
37503 this.el.on("click", this.onClick, this);
37504 this.el.on("change", this.onClick, this);
37508 getResizeEl : function(){
37512 getPositionEl : function(){
37517 onRender : function(ct, position){
37518 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
37520 if(this.inputValue !== undefined){
37521 this.el.dom.value = this.inputValue;
37524 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
37525 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
37526 var viewEl = this.wrap.createChild({
37527 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
37528 this.viewEl = viewEl;
37529 this.wrap.on('click', this.onClick, this);
37531 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
37532 this.el.on('propertychange', this.setFromHidden, this); //ie
37537 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
37538 // viewEl.on('click', this.onClick, this);
37540 //if(this.checked){
37541 this.setChecked(this.checked);
37543 //this.checked = this.el.dom;
37549 initValue : Roo.emptyFn,
37552 * Returns the checked state of the checkbox.
37553 * @return {Boolean} True if checked, else false
37555 getValue : function(){
37557 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
37559 return this.valueOff;
37564 onClick : function(){
37565 this.setChecked(!this.checked);
37567 //if(this.el.dom.checked != this.checked){
37568 // this.setValue(this.el.dom.checked);
37573 * Sets the checked state of the checkbox.
37574 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
37576 setValue : function(v,suppressEvent){
37577 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
37578 //if(this.el && this.el.dom){
37579 // this.el.dom.checked = this.checked;
37580 // this.el.dom.defaultChecked = this.checked;
37582 this.setChecked(v === this.inputValue);
37583 //this.fireEvent("check", this, this.checked);
37586 setChecked : function(state,suppressEvent)
37588 if (this.inSetChecked) {
37589 this.checked = state;
37595 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
37597 this.checked = state;
37598 if(suppressEvent !== true){
37599 this.fireEvent('checkchange', this, state);
37601 this.inSetChecked = true;
37602 this.el.dom.value = state ? this.inputValue : this.valueOff;
37603 this.inSetChecked = false;
37606 // handle setting of hidden value by some other method!!?!?
37607 setFromHidden: function()
37612 //console.log("SET FROM HIDDEN");
37613 //alert('setFrom hidden');
37614 this.setValue(this.el.dom.value);
37617 onDestroy : function()
37620 Roo.get(this.viewEl).remove();
37623 Roo.form.Checkbox.superclass.onDestroy.call(this);
37628 * Ext JS Library 1.1.1
37629 * Copyright(c) 2006-2007, Ext JS, LLC.
37631 * Originally Released Under LGPL - original licence link has changed is not relivant.
37634 * <script type="text/javascript">
37638 * @class Roo.form.Radio
37639 * @extends Roo.form.Checkbox
37640 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
37641 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
37643 * Creates a new Radio
37644 * @param {Object} config Configuration options
37646 Roo.form.Radio = function(){
37647 Roo.form.Radio.superclass.constructor.apply(this, arguments);
37649 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
37650 inputType: 'radio',
37653 * If this radio is part of a group, it will return the selected value
37656 getGroupValue : function(){
37657 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
37659 });//<script type="text/javascript">
37662 * Ext JS Library 1.1.1
37663 * Copyright(c) 2006-2007, Ext JS, LLC.
37664 * licensing@extjs.com
37666 * http://www.extjs.com/license
37672 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
37673 * - IE ? - no idea how much works there.
37681 * @class Ext.form.HtmlEditor
37682 * @extends Ext.form.Field
37683 * Provides a lightweight HTML Editor component.
37684 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
37686 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
37687 * supported by this editor.</b><br/><br/>
37688 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
37689 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
37691 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
37693 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
37697 * @cfg {String} createLinkText The default text for the create link prompt
37699 createLinkText : 'Please enter the URL for the link:',
37701 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
37703 defaultLinkValue : 'http:/'+'/',
37709 // private properties
37710 validationEvent : false,
37712 initialized : false,
37714 sourceEditMode : false,
37715 onFocus : Roo.emptyFn,
37717 hideMode:'offsets',
37718 defaultAutoCreate : {
37720 style:"width:500px;height:300px;",
37721 autocomplete: "off"
37725 initComponent : function(){
37728 * @event initialize
37729 * Fires when the editor is fully initialized (including the iframe)
37730 * @param {HtmlEditor} this
37735 * Fires when the editor is first receives the focus. Any insertion must wait
37736 * until after this event.
37737 * @param {HtmlEditor} this
37741 * @event beforesync
37742 * Fires before the textarea is updated with content from the editor iframe. Return false
37743 * to cancel the sync.
37744 * @param {HtmlEditor} this
37745 * @param {String} html
37749 * @event beforepush
37750 * Fires before the iframe editor is updated with content from the textarea. Return false
37751 * to cancel the push.
37752 * @param {HtmlEditor} this
37753 * @param {String} html
37758 * Fires when the textarea is updated with content from the editor iframe.
37759 * @param {HtmlEditor} this
37760 * @param {String} html
37765 * Fires when the iframe editor is updated with content from the textarea.
37766 * @param {HtmlEditor} this
37767 * @param {String} html
37771 * @event editmodechange
37772 * Fires when the editor switches edit modes
37773 * @param {HtmlEditor} this
37774 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
37776 editmodechange: true,
37778 * @event editorevent
37779 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
37780 * @param {HtmlEditor} this
37787 * Protected method that will not generally be called directly. It
37788 * is called when the editor creates its toolbar. Override this method if you need to
37789 * add custom toolbar buttons.
37790 * @param {HtmlEditor} editor
37792 createToolbar : function(editor){
37793 if (!editor.toolbars || !editor.toolbars.length) {
37794 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
37797 for (var i =0 ; i < editor.toolbars.length;i++) {
37798 editor.toolbars[i].init(editor);
37805 * Protected method that will not generally be called directly. It
37806 * is called when the editor initializes the iframe with HTML contents. Override this method if you
37807 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
37809 getDocMarkup : function(){
37810 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
37814 onRender : function(ct, position){
37815 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
37816 this.el.dom.style.border = '0 none';
37817 this.el.dom.setAttribute('tabIndex', -1);
37818 this.el.addClass('x-hidden');
37819 if(Roo.isIE){ // fix IE 1px bogus margin
37820 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
37822 this.wrap = this.el.wrap({
37823 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
37826 this.frameId = Roo.id();
37827 this.createToolbar(this);
37834 var iframe = this.wrap.createChild({
37837 name: this.frameId,
37838 frameBorder : 'no',
37839 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
37842 // console.log(iframe);
37843 //this.wrap.dom.appendChild(iframe);
37845 this.iframe = iframe.dom;
37847 this.assignDocWin();
37849 this.doc.designMode = 'on';
37852 this.doc.write(this.getDocMarkup());
37856 var task = { // must defer to wait for browser to be ready
37858 //console.log("run task?" + this.doc.readyState);
37859 this.assignDocWin();
37860 if(this.doc.body || this.doc.readyState == 'complete'){
37864 this.doc.designMode="on";
37868 Roo.TaskMgr.stop(task);
37869 this.initEditor.defer(10, this);
37876 Roo.TaskMgr.start(task);
37879 this.setSize(this.el.getSize());
37884 onResize : function(w, h){
37885 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
37886 if(this.el && this.iframe){
37887 if(typeof w == 'number'){
37888 var aw = w - this.wrap.getFrameWidth('lr');
37889 this.el.setWidth(this.adjustWidth('textarea', aw));
37890 this.iframe.style.width = aw + 'px';
37892 if(typeof h == 'number'){
37894 for (var i =0; i < this.toolbars.length;i++) {
37895 // fixme - ask toolbars for heights?
37896 tbh += this.toolbars[i].tb.el.getHeight();
37902 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
37903 this.el.setHeight(this.adjustWidth('textarea', ah));
37904 this.iframe.style.height = ah + 'px';
37906 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
37913 * Toggles the editor between standard and source edit mode.
37914 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
37916 toggleSourceEdit : function(sourceEditMode){
37918 this.sourceEditMode = sourceEditMode === true;
37920 if(this.sourceEditMode){
37923 this.iframe.className = 'x-hidden';
37924 this.el.removeClass('x-hidden');
37925 this.el.dom.removeAttribute('tabIndex');
37930 this.iframe.className = '';
37931 this.el.addClass('x-hidden');
37932 this.el.dom.setAttribute('tabIndex', -1);
37935 this.setSize(this.wrap.getSize());
37936 this.fireEvent('editmodechange', this, this.sourceEditMode);
37939 // private used internally
37940 createLink : function(){
37941 var url = prompt(this.createLinkText, this.defaultLinkValue);
37942 if(url && url != 'http:/'+'/'){
37943 this.relayCmd('createlink', url);
37947 // private (for BoxComponent)
37948 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37950 // private (for BoxComponent)
37951 getResizeEl : function(){
37955 // private (for BoxComponent)
37956 getPositionEl : function(){
37961 initEvents : function(){
37962 this.originalValue = this.getValue();
37966 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
37969 markInvalid : Roo.emptyFn,
37971 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
37974 clearInvalid : Roo.emptyFn,
37976 setValue : function(v){
37977 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
37982 * Protected method that will not generally be called directly. If you need/want
37983 * custom HTML cleanup, this is the method you should override.
37984 * @param {String} html The HTML to be cleaned
37985 * return {String} The cleaned HTML
37987 cleanHtml : function(html){
37988 html = String(html);
37989 if(html.length > 5){
37990 if(Roo.isSafari){ // strip safari nonsense
37991 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
37994 if(html == ' '){
38001 * Protected method that will not generally be called directly. Syncs the contents
38002 * of the editor iframe with the textarea.
38004 syncValue : function(){
38005 if(this.initialized){
38006 var bd = (this.doc.body || this.doc.documentElement);
38007 var html = bd.innerHTML;
38009 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
38010 var m = bs.match(/text-align:(.*?);/i);
38012 html = '<div style="'+m[0]+'">' + html + '</div>';
38015 html = this.cleanHtml(html);
38016 if(this.fireEvent('beforesync', this, html) !== false){
38017 this.el.dom.value = html;
38018 this.fireEvent('sync', this, html);
38024 * Protected method that will not generally be called directly. Pushes the value of the textarea
38025 * into the iframe editor.
38027 pushValue : function(){
38028 if(this.initialized){
38029 var v = this.el.dom.value;
38033 if(this.fireEvent('beforepush', this, v) !== false){
38034 (this.doc.body || this.doc.documentElement).innerHTML = v;
38035 this.fireEvent('push', this, v);
38041 deferFocus : function(){
38042 this.focus.defer(10, this);
38046 focus : function(){
38047 if(this.win && !this.sourceEditMode){
38054 assignDocWin: function()
38056 var iframe = this.iframe;
38059 this.doc = iframe.contentWindow.document;
38060 this.win = iframe.contentWindow;
38062 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
38063 this.win = Roo.get(this.frameId).dom.contentWindow;
38068 initEditor : function(){
38069 //console.log("INIT EDITOR");
38070 this.assignDocWin();
38074 this.doc.designMode="on";
38076 this.doc.write(this.getDocMarkup());
38079 var dbody = (this.doc.body || this.doc.documentElement);
38080 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
38081 // this copies styles from the containing element into thsi one..
38082 // not sure why we need all of this..
38083 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
38084 ss['background-attachment'] = 'fixed'; // w3c
38085 dbody.bgProperties = 'fixed'; // ie
38086 Roo.DomHelper.applyStyles(dbody, ss);
38087 Roo.EventManager.on(this.doc, {
38088 'mousedown': this.onEditorEvent,
38089 'dblclick': this.onEditorEvent,
38090 'click': this.onEditorEvent,
38091 'keyup': this.onEditorEvent,
38096 Roo.EventManager.on(this.doc, 'keypress', this.applyCommand, this);
38098 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
38099 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
38101 this.initialized = true;
38103 this.fireEvent('initialize', this);
38108 onDestroy : function(){
38114 for (var i =0; i < this.toolbars.length;i++) {
38115 // fixme - ask toolbars for heights?
38116 this.toolbars[i].onDestroy();
38119 this.wrap.dom.innerHTML = '';
38120 this.wrap.remove();
38125 onFirstFocus : function(){
38127 this.assignDocWin();
38130 this.activated = true;
38131 for (var i =0; i < this.toolbars.length;i++) {
38132 this.toolbars[i].onFirstFocus();
38135 if(Roo.isGecko){ // prevent silly gecko errors
38137 var s = this.win.getSelection();
38138 if(!s.focusNode || s.focusNode.nodeType != 3){
38139 var r = s.getRangeAt(0);
38140 r.selectNodeContents((this.doc.body || this.doc.documentElement));
38145 this.execCmd('useCSS', true);
38146 this.execCmd('styleWithCSS', false);
38149 this.fireEvent('activate', this);
38153 adjustFont: function(btn){
38154 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
38155 //if(Roo.isSafari){ // safari
38158 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
38159 if(Roo.isSafari){ // safari
38160 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
38161 v = (v < 10) ? 10 : v;
38162 v = (v > 48) ? 48 : v;
38163 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
38168 v = Math.max(1, v+adjust);
38170 this.execCmd('FontSize', v );
38173 onEditorEvent : function(e){
38174 this.fireEvent('editorevent', this, e);
38175 // this.updateToolbar();
38179 insertTag : function(tg)
38181 // could be a bit smarter... -> wrap the current selected tRoo..
38183 this.execCmd("formatblock", tg);
38187 insertText : function(txt)
38191 range = this.createRange();
38192 range.deleteContents();
38193 //alert(Sender.getAttribute('label'));
38195 range.insertNode(this.doc.createTextNode(txt));
38199 relayBtnCmd : function(btn){
38200 this.relayCmd(btn.cmd);
38204 * Executes a Midas editor command on the editor document and performs necessary focus and
38205 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
38206 * @param {String} cmd The Midas command
38207 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38209 relayCmd : function(cmd, value){
38211 this.execCmd(cmd, value);
38212 this.fireEvent('editorevent', this);
38213 //this.updateToolbar();
38218 * Executes a Midas editor command directly on the editor document.
38219 * For visual commands, you should use {@link #relayCmd} instead.
38220 * <b>This should only be called after the editor is initialized.</b>
38221 * @param {String} cmd The Midas command
38222 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
38224 execCmd : function(cmd, value){
38225 this.doc.execCommand(cmd, false, value === undefined ? null : value);
38230 applyCommand : function(e){
38232 var c = e.getCharCode(), cmd;
38234 c = String.fromCharCode(c);
38250 e.preventDefault();
38257 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
38259 * @param {String} text
38261 insertAtCursor : function(text){
38262 if(!this.activated){
38267 var r = this.doc.selection.createRange();
38274 }else if(Roo.isGecko || Roo.isOpera){
38276 this.execCmd('InsertHTML', text);
38278 }else if(Roo.isSafari){
38279 this.execCmd('InsertText', text);
38285 fixKeys : function(){ // load time branching for fastest keydown performance
38287 return function(e){
38288 var k = e.getKey(), r;
38291 r = this.doc.selection.createRange();
38294 r.pasteHTML('    ');
38297 }else if(k == e.ENTER){
38298 r = this.doc.selection.createRange();
38300 var target = r.parentElement();
38301 if(!target || target.tagName.toLowerCase() != 'li'){
38303 r.pasteHTML('<br />');
38310 }else if(Roo.isOpera){
38311 return function(e){
38312 var k = e.getKey();
38316 this.execCmd('InsertHTML','    ');
38320 }else if(Roo.isSafari){
38321 return function(e){
38322 var k = e.getKey();
38325 this.execCmd('InsertText','\t');
38332 getAllAncestors: function()
38334 var p = this.getSelectedNode();
38337 a.push(p); // push blank onto stack..
38338 p = this.getParentElement();
38342 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
38346 a.push(this.doc.body);
38350 lastSelNode : false,
38353 getSelection : function()
38355 this.assignDocWin();
38356 return Roo.isIE ? this.doc.selection : this.win.getSelection();
38359 getSelectedNode: function()
38361 // this may only work on Gecko!!!
38363 // should we cache this!!!!
38368 var range = this.createRange(this.getSelection());
38371 var parent = range.parentElement();
38373 var testRange = range.duplicate();
38374 testRange.moveToElementText(parent);
38375 if (testRange.inRange(range)) {
38378 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
38381 parent = parent.parentElement;
38387 var ar = range.endContainer.childNodes;
38389 ar = range.commonAncestorContainer.childNodes;
38390 //alert(ar.length);
38393 var other_nodes = [];
38394 var has_other_nodes = false;
38395 for (var i=0;i<ar.length;i++) {
38396 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
38399 // fullly contained node.
38401 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
38406 // probably selected..
38407 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
38408 other_nodes.push(ar[i]);
38411 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
38416 has_other_nodes = true;
38418 if (!nodes.length && other_nodes.length) {
38419 nodes= other_nodes;
38421 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
38427 createRange: function(sel)
38429 // this has strange effects when using with
38430 // top toolbar - not sure if it's a great idea.
38431 //this.editor.contentWindow.focus();
38432 if (typeof sel != "undefined") {
38434 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
38436 return this.doc.createRange();
38439 return this.doc.createRange();
38442 getParentElement: function()
38445 this.assignDocWin();
38446 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
38448 var range = this.createRange(sel);
38451 var p = range.commonAncestorContainer;
38452 while (p.nodeType == 3) { // text node
38464 // BC Hacks - cause I cant work out what i was trying to do..
38465 rangeIntersectsNode : function(range, node)
38467 var nodeRange = node.ownerDocument.createRange();
38469 nodeRange.selectNode(node);
38472 nodeRange.selectNodeContents(node);
38475 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
38476 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
38478 rangeCompareNode : function(range, node) {
38479 var nodeRange = node.ownerDocument.createRange();
38481 nodeRange.selectNode(node);
38483 nodeRange.selectNodeContents(node);
38485 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
38486 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
38488 if (nodeIsBefore && !nodeIsAfter)
38490 if (!nodeIsBefore && nodeIsAfter)
38492 if (nodeIsBefore && nodeIsAfter)
38500 // hide stuff that is not compatible
38514 * @event specialkey
38518 * @cfg {String} fieldClass @hide
38521 * @cfg {String} focusClass @hide
38524 * @cfg {String} autoCreate @hide
38527 * @cfg {String} inputType @hide
38530 * @cfg {String} invalidClass @hide
38533 * @cfg {String} invalidText @hide
38536 * @cfg {String} msgFx @hide
38539 * @cfg {String} validateOnBlur @hide
38541 });// <script type="text/javascript">
38544 * Ext JS Library 1.1.1
38545 * Copyright(c) 2006-2007, Ext JS, LLC.
38551 * @class Roo.form.HtmlEditorToolbar1
38556 new Roo.form.HtmlEditor({
38559 new Roo.form.HtmlEditorToolbar1({
38560 disable : { fonts: 1 , format: 1, ..., ... , ...],
38566 * @cfg {Object} disable List of elements to disable..
38567 * @cfg {Array} btns List of additional buttons.
38571 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
38574 Roo.form.HtmlEditor.ToolbarStandard = function(config)
38577 Roo.apply(this, config);
38578 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
38579 // dont call parent... till later.
38582 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
38590 * @cfg {Object} disable List of toolbar elements to disable
38595 * @cfg {Array} fontFamilies An array of available font families
38613 // "á" , ?? a acute?
38618 "°" // , // degrees
38620 // "é" , // e ecute
38621 // "ú" , // u ecute?
38624 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
38625 "input:submit", "input:button", "select", "textarea", "label" ],
38628 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
38630 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
38633 * @cfg {String} defaultFont default font to use.
38635 defaultFont: 'tahoma',
38637 fontSelect : false,
38640 formatCombo : false,
38642 init : function(editor)
38644 this.editor = editor;
38647 var fid = editor.frameId;
38649 function btn(id, toggle, handler){
38650 var xid = fid + '-'+ id ;
38654 cls : 'x-btn-icon x-edit-'+id,
38655 enableToggle:toggle !== false,
38656 scope: editor, // was editor...
38657 handler:handler||editor.relayBtnCmd,
38658 clickEvent:'mousedown',
38659 tooltip: etb.buttonTips[id] || undefined, ///tips ???
38666 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
38668 // stop form submits
38669 tb.el.on('click', function(e){
38670 e.preventDefault(); // what does this do?
38673 if(!this.disable.font && !Roo.isSafari){
38674 /* why no safari for fonts
38675 editor.fontSelect = tb.el.createChild({
38678 cls:'x-font-select',
38679 html: editor.createFontOptions()
38681 editor.fontSelect.on('change', function(){
38682 var font = editor.fontSelect.dom.value;
38683 editor.relayCmd('fontname', font);
38684 editor.deferFocus();
38687 editor.fontSelect.dom,
38692 if(!this.disable.formats){
38693 this.formatCombo = new Roo.form.ComboBox({
38694 store: new Roo.data.SimpleStore({
38697 data : this.formats // from states.js
38700 //autoCreate : {tag: "div", size: "20"},
38701 displayField:'tag',
38705 triggerAction: 'all',
38706 emptyText:'Add tag',
38707 selectOnFocus:true,
38710 'select': function(c, r, i) {
38711 editor.insertTag(r.get('tag'));
38717 tb.addField(this.formatCombo);
38721 if(!this.disable.format){
38728 if(!this.disable.fontSize){
38733 btn('increasefontsize', false, editor.adjustFont),
38734 btn('decreasefontsize', false, editor.adjustFont)
38739 if(this.disable.colors){
38742 id:editor.frameId +'-forecolor',
38743 cls:'x-btn-icon x-edit-forecolor',
38744 clickEvent:'mousedown',
38745 tooltip: this.buttonTips['forecolor'] || undefined,
38747 menu : new Roo.menu.ColorMenu({
38748 allowReselect: true,
38749 focus: Roo.emptyFn,
38752 selectHandler: function(cp, color){
38753 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
38754 editor.deferFocus();
38757 clickEvent:'mousedown'
38760 id:editor.frameId +'backcolor',
38761 cls:'x-btn-icon x-edit-backcolor',
38762 clickEvent:'mousedown',
38763 tooltip: this.buttonTips['backcolor'] || undefined,
38765 menu : new Roo.menu.ColorMenu({
38766 focus: Roo.emptyFn,
38769 allowReselect: true,
38770 selectHandler: function(cp, color){
38772 editor.execCmd('useCSS', false);
38773 editor.execCmd('hilitecolor', color);
38774 editor.execCmd('useCSS', true);
38775 editor.deferFocus();
38777 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
38778 Roo.isSafari || Roo.isIE ? '#'+color : color);
38779 editor.deferFocus();
38783 clickEvent:'mousedown'
38788 // now add all the items...
38791 if(!this.disable.alignments){
38794 btn('justifyleft'),
38795 btn('justifycenter'),
38796 btn('justifyright')
38800 //if(!Roo.isSafari){
38801 if(!this.disable.links){
38804 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
38808 if(!this.disable.lists){
38811 btn('insertorderedlist'),
38812 btn('insertunorderedlist')
38815 if(!this.disable.sourceEdit){
38818 btn('sourceedit', true, function(btn){
38819 this.toggleSourceEdit(btn.pressed);
38826 // special menu.. - needs to be tidied up..
38827 if (!this.disable.special) {
38830 cls: 'x-edit-none',
38835 for (var i =0; i < this.specialChars.length; i++) {
38836 smenu.menu.items.push({
38838 text: this.specialChars[i],
38839 handler: function(a,b) {
38840 editor.insertAtCursor(String.fromCharCode(a.text.replace('&#','').replace(';', '')));
38852 for(var i =0; i< this.btns.length;i++) {
38853 var b = this.btns[i];
38854 b.cls = 'x-edit-none';
38863 // disable everything...
38865 this.tb.items.each(function(item){
38866 if(item.id != editor.frameId+ '-sourceedit'){
38870 this.rendered = true;
38872 // the all the btns;
38873 editor.on('editorevent', this.updateToolbar, this);
38874 // other toolbars need to implement this..
38875 //editor.on('editmodechange', this.updateToolbar, this);
38881 * Protected method that will not generally be called directly. It triggers
38882 * a toolbar update by reading the markup state of the current selection in the editor.
38884 updateToolbar: function(){
38886 if(!this.editor.activated){
38887 this.editor.onFirstFocus();
38891 var btns = this.tb.items.map,
38892 doc = this.editor.doc,
38893 frameId = this.editor.frameId;
38895 if(!this.disable.font && !Roo.isSafari){
38897 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
38898 if(name != this.fontSelect.dom.value){
38899 this.fontSelect.dom.value = name;
38903 if(!this.disable.format){
38904 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
38905 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
38906 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
38908 if(!this.disable.alignments){
38909 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
38910 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
38911 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
38913 if(!Roo.isSafari && !this.disable.lists){
38914 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
38915 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
38918 var ans = this.editor.getAllAncestors();
38919 if (this.formatCombo) {
38922 var store = this.formatCombo.store;
38923 this.formatCombo.setValue("");
38924 for (var i =0; i < ans.length;i++) {
38925 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), true).length) {
38927 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
38935 // hides menus... - so this cant be on a menu...
38936 Roo.menu.MenuMgr.hideAll();
38938 //this.editorsyncValue();
38942 createFontOptions : function(){
38943 var buf = [], fs = this.fontFamilies, ff, lc;
38944 for(var i = 0, len = fs.length; i< len; i++){
38946 lc = ff.toLowerCase();
38948 '<option value="',lc,'" style="font-family:',ff,';"',
38949 (this.defaultFont == lc ? ' selected="true">' : '>'),
38954 return buf.join('');
38957 toggleSourceEdit : function(sourceEditMode){
38958 if(sourceEditMode === undefined){
38959 sourceEditMode = !this.sourceEditMode;
38961 this.sourceEditMode = sourceEditMode === true;
38962 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
38963 // just toggle the button?
38964 if(btn.pressed !== this.editor.sourceEditMode){
38965 btn.toggle(this.editor.sourceEditMode);
38969 if(this.sourceEditMode){
38970 this.tb.items.each(function(item){
38971 if(item.cmd != 'sourceedit'){
38977 if(this.initialized){
38978 this.tb.items.each(function(item){
38984 // tell the editor that it's been pressed..
38985 this.editor.toggleSourceEdit(sourceEditMode);
38989 * Object collection of toolbar tooltips for the buttons in the editor. The key
38990 * is the command id associated with that button and the value is a valid QuickTips object.
38995 title: 'Bold (Ctrl+B)',
38996 text: 'Make the selected text bold.',
38997 cls: 'x-html-editor-tip'
39000 title: 'Italic (Ctrl+I)',
39001 text: 'Make the selected text italic.',
39002 cls: 'x-html-editor-tip'
39010 title: 'Bold (Ctrl+B)',
39011 text: 'Make the selected text bold.',
39012 cls: 'x-html-editor-tip'
39015 title: 'Italic (Ctrl+I)',
39016 text: 'Make the selected text italic.',
39017 cls: 'x-html-editor-tip'
39020 title: 'Underline (Ctrl+U)',
39021 text: 'Underline the selected text.',
39022 cls: 'x-html-editor-tip'
39024 increasefontsize : {
39025 title: 'Grow Text',
39026 text: 'Increase the font size.',
39027 cls: 'x-html-editor-tip'
39029 decreasefontsize : {
39030 title: 'Shrink Text',
39031 text: 'Decrease the font size.',
39032 cls: 'x-html-editor-tip'
39035 title: 'Text Highlight Color',
39036 text: 'Change the background color of the selected text.',
39037 cls: 'x-html-editor-tip'
39040 title: 'Font Color',
39041 text: 'Change the color of the selected text.',
39042 cls: 'x-html-editor-tip'
39045 title: 'Align Text Left',
39046 text: 'Align text to the left.',
39047 cls: 'x-html-editor-tip'
39050 title: 'Center Text',
39051 text: 'Center text in the editor.',
39052 cls: 'x-html-editor-tip'
39055 title: 'Align Text Right',
39056 text: 'Align text to the right.',
39057 cls: 'x-html-editor-tip'
39059 insertunorderedlist : {
39060 title: 'Bullet List',
39061 text: 'Start a bulleted list.',
39062 cls: 'x-html-editor-tip'
39064 insertorderedlist : {
39065 title: 'Numbered List',
39066 text: 'Start a numbered list.',
39067 cls: 'x-html-editor-tip'
39070 title: 'Hyperlink',
39071 text: 'Make the selected text a hyperlink.',
39072 cls: 'x-html-editor-tip'
39075 title: 'Source Edit',
39076 text: 'Switch to source editing mode.',
39077 cls: 'x-html-editor-tip'
39081 onDestroy : function(){
39084 this.tb.items.each(function(item){
39086 item.menu.removeAll();
39088 item.menu.el.destroy();
39096 onFirstFocus: function() {
39097 this.tb.items.each(function(item){
39106 // <script type="text/javascript">
39109 * Ext JS Library 1.1.1
39110 * Copyright(c) 2006-2007, Ext JS, LLC.
39117 * @class Roo.form.HtmlEditor.ToolbarContext
39122 new Roo.form.HtmlEditor({
39125 new Roo.form.HtmlEditor.ToolbarStandard(),
39126 new Roo.form.HtmlEditor.ToolbarContext()
39131 * @config : {Object} disable List of elements to disable.. (not done yet.)
39136 Roo.form.HtmlEditor.ToolbarContext = function(config)
39139 Roo.apply(this, config);
39140 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
39141 // dont call parent... till later.
39143 Roo.form.HtmlEditor.ToolbarContext.types = {
39155 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
39217 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
39222 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
39286 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
39294 * @cfg {Object} disable List of toolbar elements to disable
39303 init : function(editor)
39305 this.editor = editor;
39308 var fid = editor.frameId;
39310 function btn(id, toggle, handler){
39311 var xid = fid + '-'+ id ;
39315 cls : 'x-btn-icon x-edit-'+id,
39316 enableToggle:toggle !== false,
39317 scope: editor, // was editor...
39318 handler:handler||editor.relayBtnCmd,
39319 clickEvent:'mousedown',
39320 tooltip: etb.buttonTips[id] || undefined, ///tips ???
39324 // create a new element.
39325 var wdiv = editor.wrap.createChild({
39327 }, editor.wrap.dom.firstChild.nextSibling, true);
39329 // can we do this more than once??
39331 // stop form submits
39334 // disable everything...
39335 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39336 this.toolbars = {};
39338 for (var i in ty) {
39339 this.toolbars[i] = this.buildToolbar(ty[i],i);
39341 this.tb = this.toolbars.BODY;
39345 this.rendered = true;
39347 // the all the btns;
39348 editor.on('editorevent', this.updateToolbar, this);
39349 // other toolbars need to implement this..
39350 //editor.on('editmodechange', this.updateToolbar, this);
39356 * Protected method that will not generally be called directly. It triggers
39357 * a toolbar update by reading the markup state of the current selection in the editor.
39359 updateToolbar: function(){
39361 if(!this.editor.activated){
39362 this.editor.onFirstFocus();
39367 var ans = this.editor.getAllAncestors();
39370 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
39371 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
39372 sel = sel ? sel : this.editor.doc.body;
39373 sel = sel.tagName.length ? sel : this.editor.doc.body;
39374 var tn = sel.tagName.toUpperCase();
39375 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
39376 tn = sel.tagName.toUpperCase();
39377 if (this.tb.name == tn) {
39378 return; // no change
39381 ///console.log("show: " + tn);
39382 this.tb = this.toolbars[tn];
39384 this.tb.fields.each(function(e) {
39385 e.setValue(sel.getAttribute(e.name));
39387 this.tb.selectedNode = sel;
39390 Roo.menu.MenuMgr.hideAll();
39392 //this.editorsyncValue();
39397 onDestroy : function(){
39400 this.tb.items.each(function(item){
39402 item.menu.removeAll();
39404 item.menu.el.destroy();
39412 onFirstFocus: function() {
39413 // need to do this for all the toolbars..
39414 this.tb.items.each(function(item){
39418 buildToolbar: function(tlist, nm)
39420 var editor = this.editor;
39421 // create a new element.
39422 var wdiv = editor.wrap.createChild({
39424 }, editor.wrap.dom.firstChild.nextSibling, true);
39427 var tb = new Roo.Toolbar(wdiv);
39428 tb.add(nm+ ": ");
39429 for (var i in tlist) {
39430 var item = tlist[i];
39431 tb.add(item.title + ": ");
39436 tb.addField( new Roo.form.ComboBox({
39437 store: new Roo.data.SimpleStore({
39440 data : item.opts // from states.js
39443 displayField:'val',
39447 triggerAction: 'all',
39448 emptyText:'Select',
39449 selectOnFocus:true,
39450 width: item.width ? item.width : 130,
39452 'select': function(c, r, i) {
39453 tb.selectedNode.setAttribute(c.name, r.get('val'));
39464 tb.addField( new Roo.form.TextField({
39467 //allowBlank:false,
39472 tb.addField( new Roo.form.TextField({
39478 'change' : function(f, nv, ov) {
39479 tb.selectedNode.setAttribute(f.name, nv);
39485 tb.el.on('click', function(e){
39486 e.preventDefault(); // what does this do?
39488 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
39491 // dont need to disable them... as they will get hidden
39508 * Ext JS Library 1.1.1
39509 * Copyright(c) 2006-2007, Ext JS, LLC.
39511 * Originally Released Under LGPL - original licence link has changed is not relivant.
39514 * <script type="text/javascript">
39518 * @class Roo.form.BasicForm
39519 * @extends Roo.util.Observable
39520 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
39522 * @param {String/HTMLElement/Roo.Element} el The form element or its id
39523 * @param {Object} config Configuration options
39525 Roo.form.BasicForm = function(el, config){
39526 Roo.apply(this, config);
39528 * The Roo.form.Field items in this form.
39529 * @type MixedCollection
39531 this.items = new Roo.util.MixedCollection(false, function(o){
39532 return o.id || (o.id = Roo.id());
39536 * @event beforeaction
39537 * Fires before any action is performed. Return false to cancel the action.
39538 * @param {Form} this
39539 * @param {Action} action The action to be performed
39541 beforeaction: true,
39543 * @event actionfailed
39544 * Fires when an action fails.
39545 * @param {Form} this
39546 * @param {Action} action The action that failed
39548 actionfailed : true,
39550 * @event actioncomplete
39551 * Fires when an action is completed.
39552 * @param {Form} this
39553 * @param {Action} action The action that completed
39555 actioncomplete : true
39560 Roo.form.BasicForm.superclass.constructor.call(this);
39563 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
39565 * @cfg {String} method
39566 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
39569 * @cfg {DataReader} reader
39570 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
39571 * This is optional as there is built-in support for processing JSON.
39574 * @cfg {DataReader} errorReader
39575 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
39576 * This is completely optional as there is built-in support for processing JSON.
39579 * @cfg {String} url
39580 * The URL to use for form actions if one isn't supplied in the action options.
39583 * @cfg {Boolean} fileUpload
39584 * Set to true if this form is a file upload.
39587 * @cfg {Object} baseParams
39588 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
39591 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
39596 activeAction : null,
39599 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
39600 * or setValues() data instead of when the form was first created.
39602 trackResetOnLoad : false,
39605 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
39606 * element by passing it or its id or mask the form itself by passing in true.
39609 waitMsgTarget : undefined,
39612 initEl : function(el){
39613 this.el = Roo.get(el);
39614 this.id = this.el.id || Roo.id();
39615 this.el.on('submit', this.onSubmit, this);
39616 this.el.addClass('x-form');
39620 onSubmit : function(e){
39625 * Returns true if client-side validation on the form is successful.
39628 isValid : function(){
39630 this.items.each(function(f){
39639 * Returns true if any fields in this form have changed since their original load.
39642 isDirty : function(){
39644 this.items.each(function(f){
39654 * Performs a predefined action (submit or load) or custom actions you define on this form.
39655 * @param {String} actionName The name of the action type
39656 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
39657 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
39658 * accept other config options):
39660 Property Type Description
39661 ---------------- --------------- ----------------------------------------------------------------------------------
39662 url String The url for the action (defaults to the form's url)
39663 method String The form method to use (defaults to the form's method, or POST if not defined)
39664 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
39665 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
39666 validate the form on the client (defaults to false)
39668 * @return {BasicForm} this
39670 doAction : function(action, options){
39671 if(typeof action == 'string'){
39672 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
39674 if(this.fireEvent('beforeaction', this, action) !== false){
39675 this.beforeAction(action);
39676 action.run.defer(100, action);
39682 * Shortcut to do a submit action.
39683 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39684 * @return {BasicForm} this
39686 submit : function(options){
39687 this.doAction('submit', options);
39692 * Shortcut to do a load action.
39693 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
39694 * @return {BasicForm} this
39696 load : function(options){
39697 this.doAction('load', options);
39702 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
39703 * @param {Record} record The record to edit
39704 * @return {BasicForm} this
39706 updateRecord : function(record){
39707 record.beginEdit();
39708 var fs = record.fields;
39709 fs.each(function(f){
39710 var field = this.findField(f.name);
39712 record.set(f.name, field.getValue());
39720 * Loads an Roo.data.Record into this form.
39721 * @param {Record} record The record to load
39722 * @return {BasicForm} this
39724 loadRecord : function(record){
39725 this.setValues(record.data);
39730 beforeAction : function(action){
39731 var o = action.options;
39733 if(this.waitMsgTarget === true){
39734 this.el.mask(o.waitMsg, 'x-mask-loading');
39735 }else if(this.waitMsgTarget){
39736 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
39737 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
39739 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
39745 afterAction : function(action, success){
39746 this.activeAction = null;
39747 var o = action.options;
39749 if(this.waitMsgTarget === true){
39751 }else if(this.waitMsgTarget){
39752 this.waitMsgTarget.unmask();
39754 Roo.MessageBox.updateProgress(1);
39755 Roo.MessageBox.hide();
39762 Roo.callback(o.success, o.scope, [this, action]);
39763 this.fireEvent('actioncomplete', this, action);
39765 Roo.callback(o.failure, o.scope, [this, action]);
39766 this.fireEvent('actionfailed', this, action);
39771 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
39772 * @param {String} id The value to search for
39775 findField : function(id){
39776 var field = this.items.get(id);
39778 this.items.each(function(f){
39779 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
39785 return field || null;
39790 * Mark fields in this form invalid in bulk.
39791 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
39792 * @return {BasicForm} this
39794 markInvalid : function(errors){
39795 if(errors instanceof Array){
39796 for(var i = 0, len = errors.length; i < len; i++){
39797 var fieldError = errors[i];
39798 var f = this.findField(fieldError.id);
39800 f.markInvalid(fieldError.msg);
39806 if(typeof errors[id] != 'function' && (field = this.findField(id))){
39807 field.markInvalid(errors[id]);
39815 * Set values for fields in this form in bulk.
39816 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
39817 * @return {BasicForm} this
39819 setValues : function(values){
39820 if(values instanceof Array){ // array of objects
39821 for(var i = 0, len = values.length; i < len; i++){
39823 var f = this.findField(v.id);
39825 f.setValue(v.value);
39826 if(this.trackResetOnLoad){
39827 f.originalValue = f.getValue();
39831 }else{ // object hash
39834 if(typeof values[id] != 'function' && (field = this.findField(id))){
39836 if (field.setFromData &&
39837 field.valueField &&
39838 field.displayField &&
39839 // combos' with local stores can
39840 // be queried via setValue()
39841 // to set their value..
39842 (field.store && !field.store.isLocal)
39846 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
39847 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
39848 field.setFromData(sd);
39851 field.setValue(values[id]);
39855 if(this.trackResetOnLoad){
39856 field.originalValue = field.getValue();
39865 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
39866 * they are returned as an array.
39867 * @param {Boolean} asString
39870 getValues : function(asString){
39871 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
39872 if(asString === true){
39875 return Roo.urlDecode(fs);
39879 * Clears all invalid messages in this form.
39880 * @return {BasicForm} this
39882 clearInvalid : function(){
39883 this.items.each(function(f){
39890 * Resets this form.
39891 * @return {BasicForm} this
39893 reset : function(){
39894 this.items.each(function(f){
39901 * Add Roo.form components to this form.
39902 * @param {Field} field1
39903 * @param {Field} field2 (optional)
39904 * @param {Field} etc (optional)
39905 * @return {BasicForm} this
39908 this.items.addAll(Array.prototype.slice.call(arguments, 0));
39914 * Removes a field from the items collection (does NOT remove its markup).
39915 * @param {Field} field
39916 * @return {BasicForm} this
39918 remove : function(field){
39919 this.items.remove(field);
39924 * Looks at the fields in this form, checks them for an id attribute,
39925 * and calls applyTo on the existing dom element with that id.
39926 * @return {BasicForm} this
39928 render : function(){
39929 this.items.each(function(f){
39930 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
39938 * Calls {@link Ext#apply} for all fields in this form with the passed object.
39939 * @param {Object} values
39940 * @return {BasicForm} this
39942 applyToFields : function(o){
39943 this.items.each(function(f){
39950 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
39951 * @param {Object} values
39952 * @return {BasicForm} this
39954 applyIfToFields : function(o){
39955 this.items.each(function(f){
39963 Roo.BasicForm = Roo.form.BasicForm;/*
39965 * Ext JS Library 1.1.1
39966 * Copyright(c) 2006-2007, Ext JS, LLC.
39968 * Originally Released Under LGPL - original licence link has changed is not relivant.
39971 * <script type="text/javascript">
39975 * @class Roo.form.Form
39976 * @extends Roo.form.BasicForm
39977 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
39979 * @param {Object} config Configuration options
39981 Roo.form.Form = function(config){
39983 if (config.items) {
39984 xitems = config.items;
39985 delete config.items;
39989 Roo.form.Form.superclass.constructor.call(this, null, config);
39990 this.url = this.url || this.action;
39992 this.root = new Roo.form.Layout(Roo.applyIf({
39996 this.active = this.root;
39998 * Array of all the buttons that have been added to this form via {@link addButton}
40002 this.allItems = [];
40005 * @event clientvalidation
40006 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
40007 * @param {Form} this
40008 * @param {Boolean} valid true if the form has passed client-side validation
40010 clientvalidation: true,
40013 * Fires when the form is rendered
40014 * @param {Roo.form.Form} form
40019 Roo.each(xitems, this.addxtype, this);
40025 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
40027 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
40030 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
40033 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
40035 buttonAlign:'center',
40038 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
40043 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
40044 * This property cascades to child containers if not set.
40049 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
40050 * fires a looping event with that state. This is required to bind buttons to the valid
40051 * state using the config value formBind:true on the button.
40053 monitorValid : false,
40056 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
40061 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
40062 * fields are added and the column is closed. If no fields are passed the column remains open
40063 * until end() is called.
40064 * @param {Object} config The config to pass to the column
40065 * @param {Field} field1 (optional)
40066 * @param {Field} field2 (optional)
40067 * @param {Field} etc (optional)
40068 * @return Column The column container object
40070 column : function(c){
40071 var col = new Roo.form.Column(c);
40073 if(arguments.length > 1){ // duplicate code required because of Opera
40074 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40081 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
40082 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
40083 * until end() is called.
40084 * @param {Object} config The config to pass to the fieldset
40085 * @param {Field} field1 (optional)
40086 * @param {Field} field2 (optional)
40087 * @param {Field} etc (optional)
40088 * @return FieldSet The fieldset container object
40090 fieldset : function(c){
40091 var fs = new Roo.form.FieldSet(c);
40093 if(arguments.length > 1){ // duplicate code required because of Opera
40094 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40101 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
40102 * fields are added and the container is closed. If no fields are passed the container remains open
40103 * until end() is called.
40104 * @param {Object} config The config to pass to the Layout
40105 * @param {Field} field1 (optional)
40106 * @param {Field} field2 (optional)
40107 * @param {Field} etc (optional)
40108 * @return Layout The container object
40110 container : function(c){
40111 var l = new Roo.form.Layout(c);
40113 if(arguments.length > 1){ // duplicate code required because of Opera
40114 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
40121 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
40122 * @param {Object} container A Roo.form.Layout or subclass of Layout
40123 * @return {Form} this
40125 start : function(c){
40126 // cascade label info
40127 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
40128 this.active.stack.push(c);
40129 c.ownerCt = this.active;
40135 * Closes the current open container
40136 * @return {Form} this
40139 if(this.active == this.root){
40142 this.active = this.active.ownerCt;
40147 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
40148 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
40149 * as the label of the field.
40150 * @param {Field} field1
40151 * @param {Field} field2 (optional)
40152 * @param {Field} etc. (optional)
40153 * @return {Form} this
40156 this.active.stack.push.apply(this.active.stack, arguments);
40157 this.allItems.push.apply(this.allItems,arguments);
40159 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
40160 if(a[i].isFormField){
40165 Roo.form.Form.superclass.add.apply(this, r);
40170 * Find any element that has been added to a form, using it's ID or name
40171 * This can include framesets, columns etc. along with regular fields..
40172 * @param {String} id - id or name to find.
40174 * @return {Element} e - or false if nothing found.
40176 findbyId : function(id)
40182 Ext.each(this.allItems, function(f){
40183 if (f.id == id || f.name == id ){
40194 * Render this form into the passed container. This should only be called once!
40195 * @param {String/HTMLElement/Element} container The element this component should be rendered into
40196 * @return {Form} this
40198 render : function(ct){
40200 var o = this.autoCreate || {
40202 method : this.method || 'POST',
40203 id : this.id || Roo.id()
40205 this.initEl(ct.createChild(o));
40207 this.root.render(this.el);
40209 this.items.each(function(f){
40210 f.render('x-form-el-'+f.id);
40213 if(this.buttons.length > 0){
40214 // tables are required to maintain order and for correct IE layout
40215 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
40216 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
40217 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
40219 var tr = tb.getElementsByTagName('tr')[0];
40220 for(var i = 0, len = this.buttons.length; i < len; i++) {
40221 var b = this.buttons[i];
40222 var td = document.createElement('td');
40223 td.className = 'x-form-btn-td';
40224 b.render(tr.appendChild(td));
40227 if(this.monitorValid){ // initialize after render
40228 this.startMonitoring();
40230 this.fireEvent('rendered', this);
40235 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
40236 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
40237 * object or a valid Roo.DomHelper element config
40238 * @param {Function} handler The function called when the button is clicked
40239 * @param {Object} scope (optional) The scope of the handler function
40240 * @return {Roo.Button}
40242 addButton : function(config, handler, scope){
40246 minWidth: this.minButtonWidth,
40249 if(typeof config == "string"){
40252 Roo.apply(bc, config);
40254 var btn = new Roo.Button(null, bc);
40255 this.buttons.push(btn);
40260 * Adds a series of form elements (using the xtype property as the factory method.
40261 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
40262 * @param {Object} config
40265 addxtype : function()
40267 var ar = Array.prototype.slice.call(arguments, 0);
40269 for(var i = 0; i < ar.length; i++) {
40271 continue; // skip -- if this happends something invalid got sent, we
40272 // should ignore it, as basically that interface element will not show up
40273 // and that should be pretty obvious!!
40276 if (Roo.form[ar[i].xtype]) {
40278 var fe = Roo.factory(ar[i], Roo.form);
40284 fe.store.form = this;
40289 this.allItems.push(fe);
40290 if (fe.items && fe.addxtype) {
40291 fe.addxtype.apply(fe, fe.items);
40301 // console.log('adding ' + ar[i].xtype);
40303 if (ar[i].xtype == 'Button') {
40304 //console.log('adding button');
40305 //console.log(ar[i]);
40306 this.addButton(ar[i]);
40307 this.allItems.push(fe);
40311 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
40312 alert('end is not supported on xtype any more, use items');
40314 // //console.log('adding end');
40322 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
40323 * option "monitorValid"
40325 startMonitoring : function(){
40328 Roo.TaskMgr.start({
40329 run : this.bindHandler,
40330 interval : this.monitorPoll || 200,
40337 * Stops monitoring of the valid state of this form
40339 stopMonitoring : function(){
40340 this.bound = false;
40344 bindHandler : function(){
40346 return false; // stops binding
40349 this.items.each(function(f){
40350 if(!f.isValid(true)){
40355 for(var i = 0, len = this.buttons.length; i < len; i++){
40356 var btn = this.buttons[i];
40357 if(btn.formBind === true && btn.disabled === valid){
40358 btn.setDisabled(!valid);
40361 this.fireEvent('clientvalidation', this, valid);
40375 Roo.Form = Roo.form.Form;
40378 * Ext JS Library 1.1.1
40379 * Copyright(c) 2006-2007, Ext JS, LLC.
40381 * Originally Released Under LGPL - original licence link has changed is not relivant.
40384 * <script type="text/javascript">
40388 * @class Roo.form.Action
40389 * Internal Class used to handle form actions
40391 * @param {Roo.form.BasicForm} el The form element or its id
40392 * @param {Object} config Configuration options
40396 // define the action interface
40397 Roo.form.Action = function(form, options){
40399 this.options = options || {};
40402 * Client Validation Failed
40405 Roo.form.Action.CLIENT_INVALID = 'client';
40407 * Server Validation Failed
40410 Roo.form.Action.SERVER_INVALID = 'server';
40412 * Connect to Server Failed
40415 Roo.form.Action.CONNECT_FAILURE = 'connect';
40417 * Reading Data from Server Failed
40420 Roo.form.Action.LOAD_FAILURE = 'load';
40422 Roo.form.Action.prototype = {
40424 failureType : undefined,
40425 response : undefined,
40426 result : undefined,
40428 // interface method
40429 run : function(options){
40433 // interface method
40434 success : function(response){
40438 // interface method
40439 handleResponse : function(response){
40443 // default connection failure
40444 failure : function(response){
40445 this.response = response;
40446 this.failureType = Roo.form.Action.CONNECT_FAILURE;
40447 this.form.afterAction(this, false);
40450 processResponse : function(response){
40451 this.response = response;
40452 if(!response.responseText){
40455 this.result = this.handleResponse(response);
40456 return this.result;
40459 // utility functions used internally
40460 getUrl : function(appendParams){
40461 var url = this.options.url || this.form.url || this.form.el.dom.action;
40463 var p = this.getParams();
40465 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
40471 getMethod : function(){
40472 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
40475 getParams : function(){
40476 var bp = this.form.baseParams;
40477 var p = this.options.params;
40479 if(typeof p == "object"){
40480 p = Roo.urlEncode(Roo.applyIf(p, bp));
40481 }else if(typeof p == 'string' && bp){
40482 p += '&' + Roo.urlEncode(bp);
40485 p = Roo.urlEncode(bp);
40490 createCallback : function(){
40492 success: this.success,
40493 failure: this.failure,
40495 timeout: (this.form.timeout*1000),
40496 upload: this.form.fileUpload ? this.success : undefined
40501 Roo.form.Action.Submit = function(form, options){
40502 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
40505 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
40509 var o = this.options;
40510 var method = this.getMethod();
40511 var isPost = method == 'POST';
40512 if(o.clientValidation === false || this.form.isValid()){
40513 Roo.Ajax.request(Roo.apply(this.createCallback(), {
40514 form:this.form.el.dom,
40515 url:this.getUrl(!isPost),
40517 params:isPost ? this.getParams() : null,
40518 isUpload: this.form.fileUpload
40521 }else if (o.clientValidation !== false){ // client validation failed
40522 this.failureType = Roo.form.Action.CLIENT_INVALID;
40523 this.form.afterAction(this, false);
40527 success : function(response){
40528 var result = this.processResponse(response);
40529 if(result === true || result.success){
40530 this.form.afterAction(this, true);
40534 this.form.markInvalid(result.errors);
40535 this.failureType = Roo.form.Action.SERVER_INVALID;
40537 this.form.afterAction(this, false);
40540 handleResponse : function(response){
40541 if(this.form.errorReader){
40542 var rs = this.form.errorReader.read(response);
40545 for(var i = 0, len = rs.records.length; i < len; i++) {
40546 var r = rs.records[i];
40547 errors[i] = r.data;
40550 if(errors.length < 1){
40554 success : rs.success,
40560 ret = Roo.decode(response.responseText);
40564 errorMsg: "Failed to read server message: " + response.responseText,
40574 Roo.form.Action.Load = function(form, options){
40575 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
40576 this.reader = this.form.reader;
40579 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
40583 Roo.Ajax.request(Roo.apply(
40584 this.createCallback(), {
40585 method:this.getMethod(),
40586 url:this.getUrl(false),
40587 params:this.getParams()
40591 success : function(response){
40592 var result = this.processResponse(response);
40593 if(result === true || !result.success || !result.data){
40594 this.failureType = Roo.form.Action.LOAD_FAILURE;
40595 this.form.afterAction(this, false);
40598 this.form.clearInvalid();
40599 this.form.setValues(result.data);
40600 this.form.afterAction(this, true);
40603 handleResponse : function(response){
40604 if(this.form.reader){
40605 var rs = this.form.reader.read(response);
40606 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
40608 success : rs.success,
40612 return Roo.decode(response.responseText);
40616 Roo.form.Action.ACTION_TYPES = {
40617 'load' : Roo.form.Action.Load,
40618 'submit' : Roo.form.Action.Submit
40621 * Ext JS Library 1.1.1
40622 * Copyright(c) 2006-2007, Ext JS, LLC.
40624 * Originally Released Under LGPL - original licence link has changed is not relivant.
40627 * <script type="text/javascript">
40631 * @class Roo.form.Layout
40632 * @extends Roo.Component
40633 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
40635 * @param {Object} config Configuration options
40637 Roo.form.Layout = function(config){
40639 if (config.items) {
40640 xitems = config.items;
40641 delete config.items;
40643 Roo.form.Layout.superclass.constructor.call(this, config);
40645 Roo.each(xitems, this.addxtype, this);
40649 Roo.extend(Roo.form.Layout, Roo.Component, {
40651 * @cfg {String/Object} autoCreate
40652 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
40655 * @cfg {String/Object/Function} style
40656 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
40657 * a function which returns such a specification.
40660 * @cfg {String} labelAlign
40661 * Valid values are "left," "top" and "right" (defaults to "left")
40664 * @cfg {Number} labelWidth
40665 * Fixed width in pixels of all field labels (defaults to undefined)
40668 * @cfg {Boolean} clear
40669 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
40673 * @cfg {String} labelSeparator
40674 * The separator to use after field labels (defaults to ':')
40676 labelSeparator : ':',
40678 * @cfg {Boolean} hideLabels
40679 * True to suppress the display of field labels in this layout (defaults to false)
40681 hideLabels : false,
40684 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
40689 onRender : function(ct, position){
40690 if(this.el){ // from markup
40691 this.el = Roo.get(this.el);
40692 }else { // generate
40693 var cfg = this.getAutoCreate();
40694 this.el = ct.createChild(cfg, position);
40697 this.el.applyStyles(this.style);
40699 if(this.labelAlign){
40700 this.el.addClass('x-form-label-'+this.labelAlign);
40702 if(this.hideLabels){
40703 this.labelStyle = "display:none";
40704 this.elementStyle = "padding-left:0;";
40706 if(typeof this.labelWidth == 'number'){
40707 this.labelStyle = "width:"+this.labelWidth+"px;";
40708 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
40710 if(this.labelAlign == 'top'){
40711 this.labelStyle = "width:auto;";
40712 this.elementStyle = "padding-left:0;";
40715 var stack = this.stack;
40716 var slen = stack.length;
40718 if(!this.fieldTpl){
40719 var t = new Roo.Template(
40720 '<div class="x-form-item {5}">',
40721 '<label for="{0}" style="{2}">{1}{4}</label>',
40722 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
40724 '</div><div class="x-form-clear-left"></div>'
40726 t.disableFormats = true;
40728 Roo.form.Layout.prototype.fieldTpl = t;
40730 for(var i = 0; i < slen; i++) {
40731 if(stack[i].isFormField){
40732 this.renderField(stack[i]);
40734 this.renderComponent(stack[i]);
40739 this.el.createChild({cls:'x-form-clear'});
40744 renderField : function(f){
40745 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
40748 f.labelStyle||this.labelStyle||'', //2
40749 this.elementStyle||'', //3
40750 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
40751 f.itemCls||this.itemCls||'' //5
40752 ], true).getPrevSibling());
40756 renderComponent : function(c){
40757 c.render(c.isLayout ? this.el : this.el.createChild());
40760 * Adds a object form elements (using the xtype property as the factory method.)
40761 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
40762 * @param {Object} config
40764 addxtype : function(o)
40766 // create the lement.
40767 o.form = this.form;
40768 var fe = Roo.factory(o, Roo.form);
40769 this.form.allItems.push(fe);
40770 this.stack.push(fe);
40772 if (fe.isFormField) {
40773 this.form.items.add(fe);
40781 * @class Roo.form.Column
40782 * @extends Roo.form.Layout
40783 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
40785 * @param {Object} config Configuration options
40787 Roo.form.Column = function(config){
40788 Roo.form.Column.superclass.constructor.call(this, config);
40791 Roo.extend(Roo.form.Column, Roo.form.Layout, {
40793 * @cfg {Number/String} width
40794 * The fixed width of the column in pixels or CSS value (defaults to "auto")
40797 * @cfg {String/Object} autoCreate
40798 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
40802 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
40805 onRender : function(ct, position){
40806 Roo.form.Column.superclass.onRender.call(this, ct, position);
40808 this.el.setWidth(this.width);
40815 * @class Roo.form.Row
40816 * @extends Roo.form.Layout
40817 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
40819 * @param {Object} config Configuration options
40823 Roo.form.Row = function(config){
40824 Roo.form.Row.superclass.constructor.call(this, config);
40827 Roo.extend(Roo.form.Row, Roo.form.Layout, {
40829 * @cfg {Number/String} width
40830 * The fixed width of the column in pixels or CSS value (defaults to "auto")
40833 * @cfg {Number/String} height
40834 * The fixed height of the column in pixels or CSS value (defaults to "auto")
40836 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
40840 onRender : function(ct, position){
40841 //console.log('row render');
40843 var t = new Roo.Template(
40844 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
40845 '<label for="{0}" style="{2}">{1}{4}</label>',
40846 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
40850 t.disableFormats = true;
40852 Roo.form.Layout.prototype.rowTpl = t;
40854 this.fieldTpl = this.rowTpl;
40856 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
40857 var labelWidth = 100;
40859 if ((this.labelAlign != 'top')) {
40860 if (typeof this.labelWidth == 'number') {
40861 labelWidth = this.labelWidth
40863 this.padWidth = 20 + labelWidth;
40867 Roo.form.Column.superclass.onRender.call(this, ct, position);
40869 this.el.setWidth(this.width);
40872 this.el.setHeight(this.height);
40877 renderField : function(f){
40878 f.fieldEl = this.fieldTpl.append(this.el, [
40879 f.id, f.fieldLabel,
40880 f.labelStyle||this.labelStyle||'',
40881 this.elementStyle||'',
40882 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
40883 f.itemCls||this.itemCls||'',
40884 f.width ? f.width + this.padWidth : 160 + this.padWidth
40891 * @class Roo.form.FieldSet
40892 * @extends Roo.form.Layout
40893 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
40895 * @param {Object} config Configuration options
40897 Roo.form.FieldSet = function(config){
40898 Roo.form.FieldSet.superclass.constructor.call(this, config);
40901 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
40903 * @cfg {String} legend
40904 * The text to display as the legend for the FieldSet (defaults to '')
40907 * @cfg {String/Object} autoCreate
40908 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
40912 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
40915 onRender : function(ct, position){
40916 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
40918 this.setLegend(this.legend);
40923 setLegend : function(text){
40925 this.el.child('legend').update(text);
40930 * Ext JS Library 1.1.1
40931 * Copyright(c) 2006-2007, Ext JS, LLC.
40933 * Originally Released Under LGPL - original licence link has changed is not relivant.
40936 * <script type="text/javascript">
40939 * @class Roo.form.VTypes
40940 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
40943 Roo.form.VTypes = function(){
40944 // closure these in so they are only created once.
40945 var alpha = /^[a-zA-Z_]+$/;
40946 var alphanum = /^[a-zA-Z0-9_]+$/;
40947 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
40948 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
40950 // All these messages and functions are configurable
40953 * The function used to validate email addresses
40954 * @param {String} value The email address
40956 'email' : function(v){
40957 return email.test(v);
40960 * The error text to display when the email validation function returns false
40963 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
40965 * The keystroke filter mask to be applied on email input
40968 'emailMask' : /[a-z0-9_\.\-@]/i,
40971 * The function used to validate URLs
40972 * @param {String} value The URL
40974 'url' : function(v){
40975 return url.test(v);
40978 * The error text to display when the url validation function returns false
40981 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
40984 * The function used to validate alpha values
40985 * @param {String} value The value
40987 'alpha' : function(v){
40988 return alpha.test(v);
40991 * The error text to display when the alpha validation function returns false
40994 'alphaText' : 'This field should only contain letters and _',
40996 * The keystroke filter mask to be applied on alpha input
40999 'alphaMask' : /[a-z_]/i,
41002 * The function used to validate alphanumeric values
41003 * @param {String} value The value
41005 'alphanum' : function(v){
41006 return alphanum.test(v);
41009 * The error text to display when the alphanumeric validation function returns false
41012 'alphanumText' : 'This field should only contain letters, numbers and _',
41014 * The keystroke filter mask to be applied on alphanumeric input
41017 'alphanumMask' : /[a-z0-9_]/i
41019 }();//<script type="text/javascript">
41022 * @class Roo.form.FCKeditor
41023 * @extends Roo.form.TextArea
41024 * Wrapper around the FCKEditor http://www.fckeditor.net
41026 * Creates a new FCKeditor
41027 * @param {Object} config Configuration options
41029 Roo.form.FCKeditor = function(config){
41030 Roo.form.FCKeditor.superclass.constructor.call(this, config);
41033 * @event editorinit
41034 * Fired when the editor is initialized - you can add extra handlers here..
41035 * @param {FCKeditor} this
41036 * @param {Object} the FCK object.
41043 Roo.form.FCKeditor.editors = { };
41044 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
41046 //defaultAutoCreate : {
41047 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
41051 * @cfg {Object} fck options - see fck manual for details.
41056 * @cfg {Object} fck toolbar set (Basic or Default)
41058 toolbarSet : 'Basic',
41060 * @cfg {Object} fck BasePath
41062 basePath : '/fckeditor/',
41070 onRender : function(ct, position)
41073 this.defaultAutoCreate = {
41075 style:"width:300px;height:60px;",
41076 autocomplete: "off"
41079 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
41082 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
41083 if(this.preventScrollbars){
41084 this.el.setStyle("overflow", "hidden");
41086 this.el.setHeight(this.growMin);
41089 //console.log('onrender' + this.getId() );
41090 Roo.form.FCKeditor.editors[this.getId()] = this;
41093 this.replaceTextarea() ;
41097 getEditor : function() {
41098 return this.fckEditor;
41101 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
41102 * @param {Mixed} value The value to set
41106 setValue : function(value)
41108 //console.log('setValue: ' + value);
41110 if(typeof(value) == 'undefined') { // not sure why this is happending...
41113 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41115 //if(!this.el || !this.getEditor()) {
41116 // this.value = value;
41117 //this.setValue.defer(100,this,[value]);
41121 if(!this.getEditor()) {
41125 this.getEditor().SetData(value);
41132 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
41133 * @return {Mixed} value The field value
41135 getValue : function()
41138 if (this.frame && this.frame.dom.style.display == 'none') {
41139 return Roo.form.FCKeditor.superclass.getValue.call(this);
41142 if(!this.el || !this.getEditor()) {
41144 // this.getValue.defer(100,this);
41149 var value=this.getEditor().GetData();
41150 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
41151 return Roo.form.FCKeditor.superclass.getValue.call(this);
41157 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
41158 * @return {Mixed} value The field value
41160 getRawValue : function()
41162 if (this.frame && this.frame.dom.style.display == 'none') {
41163 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41166 if(!this.el || !this.getEditor()) {
41167 //this.getRawValue.defer(100,this);
41174 var value=this.getEditor().GetData();
41175 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
41176 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
41180 setSize : function(w,h) {
41184 //if (this.frame && this.frame.dom.style.display == 'none') {
41185 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41188 //if(!this.el || !this.getEditor()) {
41189 // this.setSize.defer(100,this, [w,h]);
41195 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
41197 this.frame.dom.setAttribute('width', w);
41198 this.frame.dom.setAttribute('height', h);
41199 this.frame.setSize(w,h);
41203 toggleSourceEdit : function(value) {
41207 this.el.dom.style.display = value ? '' : 'none';
41208 this.frame.dom.style.display = value ? 'none' : '';
41213 focus: function(tag)
41215 if (this.frame.dom.style.display == 'none') {
41216 return Roo.form.FCKeditor.superclass.focus.call(this);
41218 if(!this.el || !this.getEditor()) {
41219 this.focus.defer(100,this, [tag]);
41226 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
41227 this.getEditor().Focus();
41229 if (!this.getEditor().Selection.GetSelection()) {
41230 this.focus.defer(100,this, [tag]);
41235 var r = this.getEditor().EditorDocument.createRange();
41236 r.setStart(tgs[0],0);
41237 r.setEnd(tgs[0],0);
41238 this.getEditor().Selection.GetSelection().removeAllRanges();
41239 this.getEditor().Selection.GetSelection().addRange(r);
41240 this.getEditor().Focus();
41247 replaceTextarea : function()
41249 if ( document.getElementById( this.getId() + '___Frame' ) )
41251 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
41253 // We must check the elements firstly using the Id and then the name.
41254 var oTextarea = document.getElementById( this.getId() );
41256 var colElementsByName = document.getElementsByName( this.getId() ) ;
41258 oTextarea.style.display = 'none' ;
41260 if ( oTextarea.tabIndex ) {
41261 this.TabIndex = oTextarea.tabIndex ;
41264 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
41265 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
41266 this.frame = Roo.get(this.getId() + '___Frame')
41269 _getConfigHtml : function()
41273 for ( var o in this.fckconfig ) {
41274 sConfig += sConfig.length > 0 ? '&' : '';
41275 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
41278 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
41282 _getIFrameHtml : function()
41284 var sFile = 'fckeditor.html' ;
41285 /* no idea what this is about..
41288 if ( (/fcksource=true/i).test( window.top.location.search ) )
41289 sFile = 'fckeditor.original.html' ;
41294 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
41295 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
41298 var html = '<iframe id="' + this.getId() +
41299 '___Frame" src="' + sLink +
41300 '" width="' + this.width +
41301 '" height="' + this.height + '"' +
41302 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
41303 ' frameborder="0" scrolling="no"></iframe>' ;
41308 _insertHtmlBefore : function( html, element )
41310 if ( element.insertAdjacentHTML ) {
41312 element.insertAdjacentHTML( 'beforeBegin', html ) ;
41314 var oRange = document.createRange() ;
41315 oRange.setStartBefore( element ) ;
41316 var oFragment = oRange.createContextualFragment( html );
41317 element.parentNode.insertBefore( oFragment, element ) ;
41330 //Roo.reg('fckeditor', Roo.form.FCKeditor);
41332 function FCKeditor_OnComplete(editorInstance){
41333 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
41334 f.fckEditor = editorInstance;
41335 //console.log("loaded");
41336 f.fireEvent('editorinit', f, editorInstance);
41356 //<script type="text/javascript">
41358 * @class Roo.form.GridField
41359 * @extends Roo.form.Field
41360 * Embed a grid (or editable grid into a form)
41363 * Creates a new GridField
41364 * @param {Object} config Configuration options
41366 Roo.form.GridField = function(config){
41367 Roo.form.GridField.superclass.constructor.call(this, config);
41371 Roo.extend(Roo.form.GridField, Roo.form.Field, {
41373 * @cfg {Number} width - used to restrict width of grid..
41377 * @cfg {Number} height - used to restrict height of grid..
41381 * @cfg {Object} xgrid (xtype'd description of grid) Grid or EditorGrid
41385 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41386 * {tag: "input", type: "checkbox", autocomplete: "off"})
41388 // defaultAutoCreate : { tag: 'div' },
41389 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
41391 * @cfg {String} addTitle Text to include for adding a title.
41395 onResize : function(){
41396 Roo.form.Field.superclass.onResize.apply(this, arguments);
41399 initEvents : function(){
41400 // Roo.form.Checkbox.superclass.initEvents.call(this);
41401 // has no events...
41406 getResizeEl : function(){
41410 getPositionEl : function(){
41415 onRender : function(ct, position){
41417 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
41418 var style = this.style;
41421 Roo.form.DisplayImage.superclass.onRender.call(this, ct, position);
41422 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
41423 this.viewEl = this.wrap.createChild({ tag: 'div' });
41425 this.viewEl.applyStyles(style);
41428 this.viewEl.setWidth(this.width);
41431 this.viewEl.setHeight(this.height);
41433 //if(this.inputValue !== undefined){
41434 //this.setValue(this.value);
41437 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
41440 this.grid.render();
41441 this.grid.getDataSource().on('remove', this.refreshValue, this);
41442 this.grid.getDataSource().on('update', this.refreshValue, this);
41443 this.grid.on('afteredit', this.refreshValue, this);
41449 * Sets the value of the item.
41450 * @param {String} either an object or a string..
41452 setValue : function(v){
41454 v = v || []; // empty set..
41455 // this does not seem smart - it really only affects memoryproxy grids..
41456 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
41457 var ds = this.grid.getDataSource();
41458 // assumes a json reader..
41460 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
41461 ds.loadData( data);
41463 Roo.form.GridField.superclass.setValue.call(this, v);
41464 this.refreshValue();
41465 // should load data in the grid really....
41469 refreshValue: function() {
41471 this.grid.getDataSource().each(function(r) {
41474 this.el.dom.value = Roo.encode(val);
41480 });//<script type="text/javasscript">
41484 * @class Roo.DDView
41485 * A DnD enabled version of Roo.View.
41486 * @param {Element/String} container The Element in which to create the View.
41487 * @param {String} tpl The template string used to create the markup for each element of the View
41488 * @param {Object} config The configuration properties. These include all the config options of
41489 * {@link Roo.View} plus some specific to this class.<br>
41491 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
41492 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
41494 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
41495 .x-view-drag-insert-above {
41496 border-top:1px dotted #3366cc;
41498 .x-view-drag-insert-below {
41499 border-bottom:1px dotted #3366cc;
41505 Roo.DDView = function(container, tpl, config) {
41506 Roo.DDView.superclass.constructor.apply(this, arguments);
41507 this.getEl().setStyle("outline", "0px none");
41508 this.getEl().unselectable();
41509 if (this.dragGroup) {
41510 this.setDraggable(this.dragGroup.split(","));
41512 if (this.dropGroup) {
41513 this.setDroppable(this.dropGroup.split(","));
41515 if (this.deletable) {
41516 this.setDeletable();
41518 this.isDirtyFlag = false;
41524 Roo.extend(Roo.DDView, Roo.View, {
41525 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
41526 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
41527 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
41528 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
41532 reset: Roo.emptyFn,
41534 clearInvalid: Roo.form.Field.prototype.clearInvalid,
41536 validate: function() {
41540 destroy: function() {
41541 this.purgeListeners();
41542 this.getEl.removeAllListeners();
41543 this.getEl().remove();
41544 if (this.dragZone) {
41545 if (this.dragZone.destroy) {
41546 this.dragZone.destroy();
41549 if (this.dropZone) {
41550 if (this.dropZone.destroy) {
41551 this.dropZone.destroy();
41556 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
41557 getName: function() {
41561 /** Loads the View from a JSON string representing the Records to put into the Store. */
41562 setValue: function(v) {
41564 throw "DDView.setValue(). DDView must be constructed with a valid Store";
41567 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
41568 this.store.proxy = new Roo.data.MemoryProxy(data);
41572 /** @return {String} a parenthesised list of the ids of the Records in the View. */
41573 getValue: function() {
41575 this.store.each(function(rec) {
41576 result += rec.id + ',';
41578 return result.substr(0, result.length - 1) + ')';
41581 getIds: function() {
41582 var i = 0, result = new Array(this.store.getCount());
41583 this.store.each(function(rec) {
41584 result[i++] = rec.id;
41589 isDirty: function() {
41590 return this.isDirtyFlag;
41594 * Part of the Roo.dd.DropZone interface. If no target node is found, the
41595 * whole Element becomes the target, and this causes the drop gesture to append.
41597 getTargetFromEvent : function(e) {
41598 var target = e.getTarget();
41599 while ((target !== null) && (target.parentNode != this.el.dom)) {
41600 target = target.parentNode;
41603 target = this.el.dom.lastChild || this.el.dom;
41609 * Create the drag data which consists of an object which has the property "ddel" as
41610 * the drag proxy element.
41612 getDragData : function(e) {
41613 var target = this.findItemFromChild(e.getTarget());
41615 this.handleSelection(e);
41616 var selNodes = this.getSelectedNodes();
41619 copy: this.copy || (this.allowCopy && e.ctrlKey),
41623 var selectedIndices = this.getSelectedIndexes();
41624 for (var i = 0; i < selectedIndices.length; i++) {
41625 dragData.records.push(this.store.getAt(selectedIndices[i]));
41627 if (selNodes.length == 1) {
41628 dragData.ddel = target.cloneNode(true); // the div element
41630 var div = document.createElement('div'); // create the multi element drag "ghost"
41631 div.className = 'multi-proxy';
41632 for (var i = 0, len = selNodes.length; i < len; i++) {
41633 div.appendChild(selNodes[i].cloneNode(true));
41635 dragData.ddel = div;
41637 //console.log(dragData)
41638 //console.log(dragData.ddel.innerHTML)
41641 //console.log('nodragData')
41645 /** Specify to which ddGroup items in this DDView may be dragged. */
41646 setDraggable: function(ddGroup) {
41647 if (ddGroup instanceof Array) {
41648 Roo.each(ddGroup, this.setDraggable, this);
41651 if (this.dragZone) {
41652 this.dragZone.addToGroup(ddGroup);
41654 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
41655 containerScroll: true,
41659 // Draggability implies selection. DragZone's mousedown selects the element.
41660 if (!this.multiSelect) { this.singleSelect = true; }
41662 // Wire the DragZone's handlers up to methods in *this*
41663 this.dragZone.getDragData = this.getDragData.createDelegate(this);
41667 /** Specify from which ddGroup this DDView accepts drops. */
41668 setDroppable: function(ddGroup) {
41669 if (ddGroup instanceof Array) {
41670 Roo.each(ddGroup, this.setDroppable, this);
41673 if (this.dropZone) {
41674 this.dropZone.addToGroup(ddGroup);
41676 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
41677 containerScroll: true,
41681 // Wire the DropZone's handlers up to methods in *this*
41682 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
41683 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
41684 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
41685 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
41686 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
41690 /** Decide whether to drop above or below a View node. */
41691 getDropPoint : function(e, n, dd){
41692 if (n == this.el.dom) { return "above"; }
41693 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
41694 var c = t + (b - t) / 2;
41695 var y = Roo.lib.Event.getPageY(e);
41703 onNodeEnter : function(n, dd, e, data){
41707 onNodeOver : function(n, dd, e, data){
41708 var pt = this.getDropPoint(e, n, dd);
41709 // set the insert point style on the target node
41710 var dragElClass = this.dropNotAllowed;
41713 if (pt == "above"){
41714 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
41715 targetElClass = "x-view-drag-insert-above";
41717 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
41718 targetElClass = "x-view-drag-insert-below";
41720 if (this.lastInsertClass != targetElClass){
41721 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
41722 this.lastInsertClass = targetElClass;
41725 return dragElClass;
41728 onNodeOut : function(n, dd, e, data){
41729 this.removeDropIndicators(n);
41732 onNodeDrop : function(n, dd, e, data){
41733 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
41736 var pt = this.getDropPoint(e, n, dd);
41737 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
41738 if (pt == "below") { insertAt++; }
41739 for (var i = 0; i < data.records.length; i++) {
41740 var r = data.records[i];
41741 var dup = this.store.getById(r.id);
41742 if (dup && (dd != this.dragZone)) {
41743 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
41746 this.store.insert(insertAt++, r.copy());
41748 data.source.isDirtyFlag = true;
41750 this.store.insert(insertAt++, r);
41752 this.isDirtyFlag = true;
41755 this.dragZone.cachedTarget = null;
41759 removeDropIndicators : function(n){
41761 Roo.fly(n).removeClass([
41762 "x-view-drag-insert-above",
41763 "x-view-drag-insert-below"]);
41764 this.lastInsertClass = "_noclass";
41769 * Utility method. Add a delete option to the DDView's context menu.
41770 * @param {String} imageUrl The URL of the "delete" icon image.
41772 setDeletable: function(imageUrl) {
41773 if (!this.singleSelect && !this.multiSelect) {
41774 this.singleSelect = true;
41776 var c = this.getContextMenu();
41777 this.contextMenu.on("itemclick", function(item) {
41780 this.remove(this.getSelectedIndexes());
41784 this.contextMenu.add({
41791 /** Return the context menu for this DDView. */
41792 getContextMenu: function() {
41793 if (!this.contextMenu) {
41794 // Create the View's context menu
41795 this.contextMenu = new Roo.menu.Menu({
41796 id: this.id + "-contextmenu"
41798 this.el.on("contextmenu", this.showContextMenu, this);
41800 return this.contextMenu;
41803 disableContextMenu: function() {
41804 if (this.contextMenu) {
41805 this.el.un("contextmenu", this.showContextMenu, this);
41809 showContextMenu: function(e, item) {
41810 item = this.findItemFromChild(e.getTarget());
41813 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
41814 this.contextMenu.showAt(e.getXY());
41819 * Remove {@link Roo.data.Record}s at the specified indices.
41820 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
41822 remove: function(selectedIndices) {
41823 selectedIndices = [].concat(selectedIndices);
41824 for (var i = 0; i < selectedIndices.length; i++) {
41825 var rec = this.store.getAt(selectedIndices[i]);
41826 this.store.remove(rec);
41831 * Double click fires the event, but also, if this is draggable, and there is only one other
41832 * related DropZone, it transfers the selected node.
41834 onDblClick : function(e){
41835 var item = this.findItemFromChild(e.getTarget());
41837 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
41840 if (this.dragGroup) {
41841 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
41842 while (targets.indexOf(this.dropZone) > -1) {
41843 targets.remove(this.dropZone);
41845 if (targets.length == 1) {
41846 this.dragZone.cachedTarget = null;
41847 var el = Roo.get(targets[0].getEl());
41848 var box = el.getBox(true);
41849 targets[0].onNodeDrop(el.dom, {
41851 xy: [box.x, box.y + box.height - 1]
41852 }, null, this.getDragData(e));
41858 handleSelection: function(e) {
41859 this.dragZone.cachedTarget = null;
41860 var item = this.findItemFromChild(e.getTarget());
41862 this.clearSelections(true);
41865 if (item && (this.multiSelect || this.singleSelect)){
41866 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
41867 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
41868 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
41869 this.unselect(item);
41871 this.select(item, this.multiSelect && e.ctrlKey);
41872 this.lastSelection = item;
41877 onItemClick : function(item, index, e){
41878 if(this.fireEvent("beforeclick", this, index, item, e) === false){
41884 unselect : function(nodeInfo, suppressEvent){
41885 var node = this.getNode(nodeInfo);
41886 if(node && this.isSelected(node)){
41887 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
41888 Roo.fly(node).removeClass(this.selectedClass);
41889 this.selections.remove(node);
41890 if(!suppressEvent){
41891 this.fireEvent("selectionchange", this, this.selections);
41899 * Ext JS Library 1.1.1
41900 * Copyright(c) 2006-2007, Ext JS, LLC.
41902 * Originally Released Under LGPL - original licence link has changed is not relivant.
41905 * <script type="text/javascript">
41909 * @class Roo.LayoutManager
41910 * @extends Roo.util.Observable
41911 * Base class for layout managers.
41913 Roo.LayoutManager = function(container, config){
41914 Roo.LayoutManager.superclass.constructor.call(this);
41915 this.el = Roo.get(container);
41916 // ie scrollbar fix
41917 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
41918 document.body.scroll = "no";
41919 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
41920 this.el.position('relative');
41922 this.id = this.el.id;
41923 this.el.addClass("x-layout-container");
41924 /** false to disable window resize monitoring @type Boolean */
41925 this.monitorWindowResize = true;
41930 * Fires when a layout is performed.
41931 * @param {Roo.LayoutManager} this
41935 * @event regionresized
41936 * Fires when the user resizes a region.
41937 * @param {Roo.LayoutRegion} region The resized region
41938 * @param {Number} newSize The new size (width for east/west, height for north/south)
41940 "regionresized" : true,
41942 * @event regioncollapsed
41943 * Fires when a region is collapsed.
41944 * @param {Roo.LayoutRegion} region The collapsed region
41946 "regioncollapsed" : true,
41948 * @event regionexpanded
41949 * Fires when a region is expanded.
41950 * @param {Roo.LayoutRegion} region The expanded region
41952 "regionexpanded" : true
41954 this.updating = false;
41955 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
41958 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
41960 * Returns true if this layout is currently being updated
41961 * @return {Boolean}
41963 isUpdating : function(){
41964 return this.updating;
41968 * Suspend the LayoutManager from doing auto-layouts while
41969 * making multiple add or remove calls
41971 beginUpdate : function(){
41972 this.updating = true;
41976 * Restore auto-layouts and optionally disable the manager from performing a layout
41977 * @param {Boolean} noLayout true to disable a layout update
41979 endUpdate : function(noLayout){
41980 this.updating = false;
41986 layout: function(){
41990 onRegionResized : function(region, newSize){
41991 this.fireEvent("regionresized", region, newSize);
41995 onRegionCollapsed : function(region){
41996 this.fireEvent("regioncollapsed", region);
41999 onRegionExpanded : function(region){
42000 this.fireEvent("regionexpanded", region);
42004 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
42005 * performs box-model adjustments.
42006 * @return {Object} The size as an object {width: (the width), height: (the height)}
42008 getViewSize : function(){
42010 if(this.el.dom != document.body){
42011 size = this.el.getSize();
42013 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
42015 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
42016 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
42021 * Returns the Element this layout is bound to.
42022 * @return {Roo.Element}
42024 getEl : function(){
42029 * Returns the specified region.
42030 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
42031 * @return {Roo.LayoutRegion}
42033 getRegion : function(target){
42034 return this.regions[target.toLowerCase()];
42037 onWindowResize : function(){
42038 if(this.monitorWindowResize){
42044 * Ext JS Library 1.1.1
42045 * Copyright(c) 2006-2007, Ext JS, LLC.
42047 * Originally Released Under LGPL - original licence link has changed is not relivant.
42050 * <script type="text/javascript">
42053 * @class Roo.BorderLayout
42054 * @extends Roo.LayoutManager
42055 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
42056 * please see: <br><br>
42057 * <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>
42058 * <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>
42061 var layout = new Roo.BorderLayout(document.body, {
42095 preferredTabWidth: 150
42100 var CP = Roo.ContentPanel;
42102 layout.beginUpdate();
42103 layout.add("north", new CP("north", "North"));
42104 layout.add("south", new CP("south", {title: "South", closable: true}));
42105 layout.add("west", new CP("west", {title: "West"}));
42106 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
42107 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
42108 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
42109 layout.getRegion("center").showPanel("center1");
42110 layout.endUpdate();
42113 <b>The container the layout is rendered into can be either the body element or any other element.
42114 If it is not the body element, the container needs to either be an absolute positioned element,
42115 or you will need to add "position:relative" to the css of the container. You will also need to specify
42116 the container size if it is not the body element.</b>
42119 * Create a new BorderLayout
42120 * @param {String/HTMLElement/Element} container The container this layout is bound to
42121 * @param {Object} config Configuration options
42123 Roo.BorderLayout = function(container, config){
42124 config = config || {};
42125 Roo.BorderLayout.superclass.constructor.call(this, container, config);
42126 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
42127 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
42128 var target = this.factory.validRegions[i];
42129 if(config[target]){
42130 this.addRegion(target, config[target]);
42135 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
42137 * Creates and adds a new region if it doesn't already exist.
42138 * @param {String} target The target region key (north, south, east, west or center).
42139 * @param {Object} config The regions config object
42140 * @return {BorderLayoutRegion} The new region
42142 addRegion : function(target, config){
42143 if(!this.regions[target]){
42144 var r = this.factory.create(target, this, config);
42145 this.bindRegion(target, r);
42147 return this.regions[target];
42151 bindRegion : function(name, r){
42152 this.regions[name] = r;
42153 r.on("visibilitychange", this.layout, this);
42154 r.on("paneladded", this.layout, this);
42155 r.on("panelremoved", this.layout, this);
42156 r.on("invalidated", this.layout, this);
42157 r.on("resized", this.onRegionResized, this);
42158 r.on("collapsed", this.onRegionCollapsed, this);
42159 r.on("expanded", this.onRegionExpanded, this);
42163 * Performs a layout update.
42165 layout : function(){
42166 if(this.updating) return;
42167 var size = this.getViewSize();
42168 var w = size.width;
42169 var h = size.height;
42174 //var x = 0, y = 0;
42176 var rs = this.regions;
42177 var north = rs["north"];
42178 var south = rs["south"];
42179 var west = rs["west"];
42180 var east = rs["east"];
42181 var center = rs["center"];
42182 //if(this.hideOnLayout){ // not supported anymore
42183 //c.el.setStyle("display", "none");
42185 if(north && north.isVisible()){
42186 var b = north.getBox();
42187 var m = north.getMargins();
42188 b.width = w - (m.left+m.right);
42191 centerY = b.height + b.y + m.bottom;
42192 centerH -= centerY;
42193 north.updateBox(this.safeBox(b));
42195 if(south && south.isVisible()){
42196 var b = south.getBox();
42197 var m = south.getMargins();
42198 b.width = w - (m.left+m.right);
42200 var totalHeight = (b.height + m.top + m.bottom);
42201 b.y = h - totalHeight + m.top;
42202 centerH -= totalHeight;
42203 south.updateBox(this.safeBox(b));
42205 if(west && west.isVisible()){
42206 var b = west.getBox();
42207 var m = west.getMargins();
42208 b.height = centerH - (m.top+m.bottom);
42210 b.y = centerY + m.top;
42211 var totalWidth = (b.width + m.left + m.right);
42212 centerX += totalWidth;
42213 centerW -= totalWidth;
42214 west.updateBox(this.safeBox(b));
42216 if(east && east.isVisible()){
42217 var b = east.getBox();
42218 var m = east.getMargins();
42219 b.height = centerH - (m.top+m.bottom);
42220 var totalWidth = (b.width + m.left + m.right);
42221 b.x = w - totalWidth + m.left;
42222 b.y = centerY + m.top;
42223 centerW -= totalWidth;
42224 east.updateBox(this.safeBox(b));
42227 var m = center.getMargins();
42229 x: centerX + m.left,
42230 y: centerY + m.top,
42231 width: centerW - (m.left+m.right),
42232 height: centerH - (m.top+m.bottom)
42234 //if(this.hideOnLayout){
42235 //center.el.setStyle("display", "block");
42237 center.updateBox(this.safeBox(centerBox));
42240 this.fireEvent("layout", this);
42244 safeBox : function(box){
42245 box.width = Math.max(0, box.width);
42246 box.height = Math.max(0, box.height);
42251 * Adds a ContentPanel (or subclass) to this layout.
42252 * @param {String} target The target region key (north, south, east, west or center).
42253 * @param {Roo.ContentPanel} panel The panel to add
42254 * @return {Roo.ContentPanel} The added panel
42256 add : function(target, panel){
42258 target = target.toLowerCase();
42259 return this.regions[target].add(panel);
42263 * Remove a ContentPanel (or subclass) to this layout.
42264 * @param {String} target The target region key (north, south, east, west or center).
42265 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
42266 * @return {Roo.ContentPanel} The removed panel
42268 remove : function(target, panel){
42269 target = target.toLowerCase();
42270 return this.regions[target].remove(panel);
42274 * Searches all regions for a panel with the specified id
42275 * @param {String} panelId
42276 * @return {Roo.ContentPanel} The panel or null if it wasn't found
42278 findPanel : function(panelId){
42279 var rs = this.regions;
42280 for(var target in rs){
42281 if(typeof rs[target] != "function"){
42282 var p = rs[target].getPanel(panelId);
42292 * Searches all regions for a panel with the specified id and activates (shows) it.
42293 * @param {String/ContentPanel} panelId The panels id or the panel itself
42294 * @return {Roo.ContentPanel} The shown panel or null
42296 showPanel : function(panelId) {
42297 var rs = this.regions;
42298 for(var target in rs){
42299 var r = rs[target];
42300 if(typeof r != "function"){
42301 if(r.hasPanel(panelId)){
42302 return r.showPanel(panelId);
42310 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
42311 * @param {Roo.state.Provider} provider (optional) An alternate state provider
42313 restoreState : function(provider){
42315 provider = Roo.state.Manager;
42317 var sm = new Roo.LayoutStateManager();
42318 sm.init(this, provider);
42322 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
42323 * object should contain properties for each region to add ContentPanels to, and each property's value should be
42324 * a valid ContentPanel config object. Example:
42326 // Create the main layout
42327 var layout = new Roo.BorderLayout('main-ct', {
42338 // Create and add multiple ContentPanels at once via configs
42341 id: 'source-files',
42343 title:'Ext Source Files',
42356 * @param {Object} regions An object containing ContentPanel configs by region name
42358 batchAdd : function(regions){
42359 this.beginUpdate();
42360 for(var rname in regions){
42361 var lr = this.regions[rname];
42363 this.addTypedPanels(lr, regions[rname]);
42370 addTypedPanels : function(lr, ps){
42371 if(typeof ps == 'string'){
42372 lr.add(new Roo.ContentPanel(ps));
42374 else if(ps instanceof Array){
42375 for(var i =0, len = ps.length; i < len; i++){
42376 this.addTypedPanels(lr, ps[i]);
42379 else if(!ps.events){ // raw config?
42381 delete ps.el; // prevent conflict
42382 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
42384 else { // panel object assumed!
42389 * Adds a xtype elements to the layout.
42393 xtype : 'ContentPanel',
42400 xtype : 'NestedLayoutPanel',
42406 items : [ ... list of content panels or nested layout panels.. ]
42410 * @param {Object} cfg Xtype definition of item to add.
42412 addxtype : function(cfg)
42414 // basically accepts a pannel...
42415 // can accept a layout region..!?!?
42416 // console.log('BorderLayout add ' + cfg.xtype)
42418 if (!cfg.xtype.match(/Panel$/)) {
42422 var region = cfg.region;
42428 xitems = cfg.items;
42435 case 'ContentPanel': // ContentPanel (el, cfg)
42437 var el = this.el.createChild();
42438 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
42439 this.add(region, ret);
42443 case 'TreePanel': // our new panel!
42444 cfg.el = this.el.createChild();
42445 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
42446 this.add(region, ret);
42449 case 'NestedLayoutPanel':
42450 // create a new Layout (which is a Border Layout...
42451 var el = this.el.createChild();
42452 var clayout = cfg.layout;
42454 clayout.items = clayout.items || [];
42455 // replace this exitems with the clayout ones..
42456 xitems = clayout.items;
42459 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
42460 cfg.background = false;
42462 var layout = new Roo.BorderLayout(el, clayout);
42464 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
42465 //console.log('adding nested layout panel ' + cfg.toSource());
42466 this.add(region, ret);
42472 // needs grid and region
42474 //var el = this.getRegion(region).el.createChild();
42475 var el = this.el.createChild();
42476 // create the grid first...
42477 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
42479 if (region == 'center' && this.active ) {
42480 cfg.background = false;
42482 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
42484 this.add(region, ret);
42485 if (cfg.background) {
42486 ret.on('activate', function(gp) {
42487 if (!gp.grid.rendered) {
42500 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
42502 // GridPanel (grid, cfg)
42505 this.beginUpdate();
42507 Roo.each(xitems, function(i) {
42517 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
42518 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
42519 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
42520 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
42523 var CP = Roo.ContentPanel;
42525 var layout = Roo.BorderLayout.create({
42529 panels: [new CP("north", "North")]
42538 panels: [new CP("west", {title: "West"})]
42547 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
42556 panels: [new CP("south", {title: "South", closable: true})]
42563 preferredTabWidth: 150,
42565 new CP("center1", {title: "Close Me", closable: true}),
42566 new CP("center2", {title: "Center Panel", closable: false})
42571 layout.getRegion("center").showPanel("center1");
42576 Roo.BorderLayout.create = function(config, targetEl){
42577 var layout = new Roo.BorderLayout(targetEl || document.body, config);
42578 layout.beginUpdate();
42579 var regions = Roo.BorderLayout.RegionFactory.validRegions;
42580 for(var j = 0, jlen = regions.length; j < jlen; j++){
42581 var lr = regions[j];
42582 if(layout.regions[lr] && config[lr].panels){
42583 var r = layout.regions[lr];
42584 var ps = config[lr].panels;
42585 layout.addTypedPanels(r, ps);
42588 layout.endUpdate();
42593 Roo.BorderLayout.RegionFactory = {
42595 validRegions : ["north","south","east","west","center"],
42598 create : function(target, mgr, config){
42599 target = target.toLowerCase();
42600 if(config.lightweight || config.basic){
42601 return new Roo.BasicLayoutRegion(mgr, config, target);
42605 return new Roo.NorthLayoutRegion(mgr, config);
42607 return new Roo.SouthLayoutRegion(mgr, config);
42609 return new Roo.EastLayoutRegion(mgr, config);
42611 return new Roo.WestLayoutRegion(mgr, config);
42613 return new Roo.CenterLayoutRegion(mgr, config);
42615 throw 'Layout region "'+target+'" not supported.';
42619 * Ext JS Library 1.1.1
42620 * Copyright(c) 2006-2007, Ext JS, LLC.
42622 * Originally Released Under LGPL - original licence link has changed is not relivant.
42625 * <script type="text/javascript">
42629 * @class Roo.BasicLayoutRegion
42630 * @extends Roo.util.Observable
42631 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
42632 * and does not have a titlebar, tabs or any other features. All it does is size and position
42633 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
42635 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
42637 this.position = pos;
42640 * @scope Roo.BasicLayoutRegion
42644 * @event beforeremove
42645 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
42646 * @param {Roo.LayoutRegion} this
42647 * @param {Roo.ContentPanel} panel The panel
42648 * @param {Object} e The cancel event object
42650 "beforeremove" : true,
42652 * @event invalidated
42653 * Fires when the layout for this region is changed.
42654 * @param {Roo.LayoutRegion} this
42656 "invalidated" : true,
42658 * @event visibilitychange
42659 * Fires when this region is shown or hidden
42660 * @param {Roo.LayoutRegion} this
42661 * @param {Boolean} visibility true or false
42663 "visibilitychange" : true,
42665 * @event paneladded
42666 * Fires when a panel is added.
42667 * @param {Roo.LayoutRegion} this
42668 * @param {Roo.ContentPanel} panel The panel
42670 "paneladded" : true,
42672 * @event panelremoved
42673 * Fires when a panel is removed.
42674 * @param {Roo.LayoutRegion} this
42675 * @param {Roo.ContentPanel} panel The panel
42677 "panelremoved" : true,
42680 * Fires when this region is collapsed.
42681 * @param {Roo.LayoutRegion} this
42683 "collapsed" : true,
42686 * Fires when this region is expanded.
42687 * @param {Roo.LayoutRegion} this
42692 * Fires when this region is slid into view.
42693 * @param {Roo.LayoutRegion} this
42695 "slideshow" : true,
42698 * Fires when this region slides out of view.
42699 * @param {Roo.LayoutRegion} this
42701 "slidehide" : true,
42703 * @event panelactivated
42704 * Fires when a panel is activated.
42705 * @param {Roo.LayoutRegion} this
42706 * @param {Roo.ContentPanel} panel The activated panel
42708 "panelactivated" : true,
42711 * Fires when the user resizes this region.
42712 * @param {Roo.LayoutRegion} this
42713 * @param {Number} newSize The new size (width for east/west, height for north/south)
42717 /** A collection of panels in this region. @type Roo.util.MixedCollection */
42718 this.panels = new Roo.util.MixedCollection();
42719 this.panels.getKey = this.getPanelId.createDelegate(this);
42721 this.activePanel = null;
42722 // ensure listeners are added...
42724 if (config.listeners || config.events) {
42725 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
42726 listeners : config.listeners || {},
42727 events : config.events || {}
42731 if(skipConfig !== true){
42732 this.applyConfig(config);
42736 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
42737 getPanelId : function(p){
42741 applyConfig : function(config){
42742 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
42743 this.config = config;
42748 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
42749 * the width, for horizontal (north, south) the height.
42750 * @param {Number} newSize The new width or height
42752 resizeTo : function(newSize){
42753 var el = this.el ? this.el :
42754 (this.activePanel ? this.activePanel.getEl() : null);
42756 switch(this.position){
42759 el.setWidth(newSize);
42760 this.fireEvent("resized", this, newSize);
42764 el.setHeight(newSize);
42765 this.fireEvent("resized", this, newSize);
42771 getBox : function(){
42772 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
42775 getMargins : function(){
42776 return this.margins;
42779 updateBox : function(box){
42781 var el = this.activePanel.getEl();
42782 el.dom.style.left = box.x + "px";
42783 el.dom.style.top = box.y + "px";
42784 this.activePanel.setSize(box.width, box.height);
42788 * Returns the container element for this region.
42789 * @return {Roo.Element}
42791 getEl : function(){
42792 return this.activePanel;
42796 * Returns true if this region is currently visible.
42797 * @return {Boolean}
42799 isVisible : function(){
42800 return this.activePanel ? true : false;
42803 setActivePanel : function(panel){
42804 panel = this.getPanel(panel);
42805 if(this.activePanel && this.activePanel != panel){
42806 this.activePanel.setActiveState(false);
42807 this.activePanel.getEl().setLeftTop(-10000,-10000);
42809 this.activePanel = panel;
42810 panel.setActiveState(true);
42812 panel.setSize(this.box.width, this.box.height);
42814 this.fireEvent("panelactivated", this, panel);
42815 this.fireEvent("invalidated");
42819 * Show the specified panel.
42820 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
42821 * @return {Roo.ContentPanel} The shown panel or null
42823 showPanel : function(panel){
42824 if(panel = this.getPanel(panel)){
42825 this.setActivePanel(panel);
42831 * Get the active panel for this region.
42832 * @return {Roo.ContentPanel} The active panel or null
42834 getActivePanel : function(){
42835 return this.activePanel;
42839 * Add the passed ContentPanel(s)
42840 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
42841 * @return {Roo.ContentPanel} The panel added (if only one was added)
42843 add : function(panel){
42844 if(arguments.length > 1){
42845 for(var i = 0, len = arguments.length; i < len; i++) {
42846 this.add(arguments[i]);
42850 if(this.hasPanel(panel)){
42851 this.showPanel(panel);
42854 var el = panel.getEl();
42855 if(el.dom.parentNode != this.mgr.el.dom){
42856 this.mgr.el.dom.appendChild(el.dom);
42858 if(panel.setRegion){
42859 panel.setRegion(this);
42861 this.panels.add(panel);
42862 el.setStyle("position", "absolute");
42863 if(!panel.background){
42864 this.setActivePanel(panel);
42865 if(this.config.initialSize && this.panels.getCount()==1){
42866 this.resizeTo(this.config.initialSize);
42869 this.fireEvent("paneladded", this, panel);
42874 * Returns true if the panel is in this region.
42875 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
42876 * @return {Boolean}
42878 hasPanel : function(panel){
42879 if(typeof panel == "object"){ // must be panel obj
42880 panel = panel.getId();
42882 return this.getPanel(panel) ? true : false;
42886 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
42887 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
42888 * @param {Boolean} preservePanel Overrides the config preservePanel option
42889 * @return {Roo.ContentPanel} The panel that was removed
42891 remove : function(panel, preservePanel){
42892 panel = this.getPanel(panel);
42897 this.fireEvent("beforeremove", this, panel, e);
42898 if(e.cancel === true){
42901 var panelId = panel.getId();
42902 this.panels.removeKey(panelId);
42907 * Returns the panel specified or null if it's not in this region.
42908 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
42909 * @return {Roo.ContentPanel}
42911 getPanel : function(id){
42912 if(typeof id == "object"){ // must be panel obj
42915 return this.panels.get(id);
42919 * Returns this regions position (north/south/east/west/center).
42922 getPosition: function(){
42923 return this.position;
42927 * Ext JS Library 1.1.1
42928 * Copyright(c) 2006-2007, Ext JS, LLC.
42930 * Originally Released Under LGPL - original licence link has changed is not relivant.
42933 * <script type="text/javascript">
42937 * @class Roo.LayoutRegion
42938 * @extends Roo.BasicLayoutRegion
42939 * This class represents a region in a layout manager.
42940 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
42941 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
42942 * @cfg {Boolean} floatable False to disable floating (defaults to true)
42943 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
42944 * @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})
42945 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
42946 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
42947 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
42948 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
42949 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
42950 * @cfg {String} title The title for the region (overrides panel titles)
42951 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
42952 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
42953 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
42954 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
42955 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
42956 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
42957 * the space available, similar to FireFox 1.5 tabs (defaults to false)
42958 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
42959 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
42960 * @cfg {Boolean} showPin True to show a pin button
42961 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
42962 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
42963 * @cfg {Boolean} disableTabTips True to disable tab tooltips
42964 * @cfg {Number} width For East/West panels
42965 * @cfg {Number} height For North/South panels
42966 * @cfg {Boolean} split To show the splitter
42968 Roo.LayoutRegion = function(mgr, config, pos){
42969 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
42970 var dh = Roo.DomHelper;
42971 /** This region's container element
42972 * @type Roo.Element */
42973 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
42974 /** This region's title element
42975 * @type Roo.Element */
42977 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
42978 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
42979 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
42981 this.titleEl.enableDisplayMode();
42982 /** This region's title text element
42983 * @type HTMLElement */
42984 this.titleTextEl = this.titleEl.dom.firstChild;
42985 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
42986 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
42987 this.closeBtn.enableDisplayMode();
42988 this.closeBtn.on("click", this.closeClicked, this);
42989 this.closeBtn.hide();
42991 this.createBody(config);
42992 this.visible = true;
42993 this.collapsed = false;
42995 if(config.hideWhenEmpty){
42997 this.on("paneladded", this.validateVisibility, this);
42998 this.on("panelremoved", this.validateVisibility, this);
43000 this.applyConfig(config);
43003 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
43005 createBody : function(){
43006 /** This region's body element
43007 * @type Roo.Element */
43008 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
43011 applyConfig : function(c){
43012 if(c.collapsible && this.position != "center" && !this.collapsedEl){
43013 var dh = Roo.DomHelper;
43014 if(c.titlebar !== false){
43015 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
43016 this.collapseBtn.on("click", this.collapse, this);
43017 this.collapseBtn.enableDisplayMode();
43019 if(c.showPin === true || this.showPin){
43020 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
43021 this.stickBtn.enableDisplayMode();
43022 this.stickBtn.on("click", this.expand, this);
43023 this.stickBtn.hide();
43026 /** This region's collapsed element
43027 * @type Roo.Element */
43028 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
43029 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
43031 if(c.floatable !== false){
43032 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
43033 this.collapsedEl.on("click", this.collapseClick, this);
43036 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
43037 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
43038 id: "message", unselectable: "on", style:{"float":"left"}});
43039 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
43041 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
43042 this.expandBtn.on("click", this.expand, this);
43044 if(this.collapseBtn){
43045 this.collapseBtn.setVisible(c.collapsible == true);
43047 this.cmargins = c.cmargins || this.cmargins ||
43048 (this.position == "west" || this.position == "east" ?
43049 {top: 0, left: 2, right:2, bottom: 0} :
43050 {top: 2, left: 0, right:0, bottom: 2});
43051 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
43052 this.bottomTabs = c.tabPosition != "top";
43053 this.autoScroll = c.autoScroll || false;
43054 if(this.autoScroll){
43055 this.bodyEl.setStyle("overflow", "auto");
43057 this.bodyEl.setStyle("overflow", "hidden");
43059 //if(c.titlebar !== false){
43060 if((!c.titlebar && !c.title) || c.titlebar === false){
43061 this.titleEl.hide();
43063 this.titleEl.show();
43065 this.titleTextEl.innerHTML = c.title;
43069 this.duration = c.duration || .30;
43070 this.slideDuration = c.slideDuration || .45;
43073 this.collapse(true);
43080 * Returns true if this region is currently visible.
43081 * @return {Boolean}
43083 isVisible : function(){
43084 return this.visible;
43088 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
43089 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
43091 setCollapsedTitle : function(title){
43092 title = title || " ";
43093 if(this.collapsedTitleTextEl){
43094 this.collapsedTitleTextEl.innerHTML = title;
43098 getBox : function(){
43100 if(!this.collapsed){
43101 b = this.el.getBox(false, true);
43103 b = this.collapsedEl.getBox(false, true);
43108 getMargins : function(){
43109 return this.collapsed ? this.cmargins : this.margins;
43112 highlight : function(){
43113 this.el.addClass("x-layout-panel-dragover");
43116 unhighlight : function(){
43117 this.el.removeClass("x-layout-panel-dragover");
43120 updateBox : function(box){
43122 if(!this.collapsed){
43123 this.el.dom.style.left = box.x + "px";
43124 this.el.dom.style.top = box.y + "px";
43125 this.updateBody(box.width, box.height);
43127 this.collapsedEl.dom.style.left = box.x + "px";
43128 this.collapsedEl.dom.style.top = box.y + "px";
43129 this.collapsedEl.setSize(box.width, box.height);
43132 this.tabs.autoSizeTabs();
43136 updateBody : function(w, h){
43138 this.el.setWidth(w);
43139 w -= this.el.getBorderWidth("rl");
43140 if(this.config.adjustments){
43141 w += this.config.adjustments[0];
43145 this.el.setHeight(h);
43146 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
43147 h -= this.el.getBorderWidth("tb");
43148 if(this.config.adjustments){
43149 h += this.config.adjustments[1];
43151 this.bodyEl.setHeight(h);
43153 h = this.tabs.syncHeight(h);
43156 if(this.panelSize){
43157 w = w !== null ? w : this.panelSize.width;
43158 h = h !== null ? h : this.panelSize.height;
43160 if(this.activePanel){
43161 var el = this.activePanel.getEl();
43162 w = w !== null ? w : el.getWidth();
43163 h = h !== null ? h : el.getHeight();
43164 this.panelSize = {width: w, height: h};
43165 this.activePanel.setSize(w, h);
43167 if(Roo.isIE && this.tabs){
43168 this.tabs.el.repaint();
43173 * Returns the container element for this region.
43174 * @return {Roo.Element}
43176 getEl : function(){
43181 * Hides this region.
43184 if(!this.collapsed){
43185 this.el.dom.style.left = "-2000px";
43188 this.collapsedEl.dom.style.left = "-2000px";
43189 this.collapsedEl.hide();
43191 this.visible = false;
43192 this.fireEvent("visibilitychange", this, false);
43196 * Shows this region if it was previously hidden.
43199 if(!this.collapsed){
43202 this.collapsedEl.show();
43204 this.visible = true;
43205 this.fireEvent("visibilitychange", this, true);
43208 closeClicked : function(){
43209 if(this.activePanel){
43210 this.remove(this.activePanel);
43214 collapseClick : function(e){
43216 e.stopPropagation();
43219 e.stopPropagation();
43225 * Collapses this region.
43226 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
43228 collapse : function(skipAnim){
43229 if(this.collapsed) return;
43230 this.collapsed = true;
43232 this.split.el.hide();
43234 if(this.config.animate && skipAnim !== true){
43235 this.fireEvent("invalidated", this);
43236 this.animateCollapse();
43238 this.el.setLocation(-20000,-20000);
43240 this.collapsedEl.show();
43241 this.fireEvent("collapsed", this);
43242 this.fireEvent("invalidated", this);
43246 animateCollapse : function(){
43251 * Expands this region if it was previously collapsed.
43252 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
43253 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
43255 expand : function(e, skipAnim){
43256 if(e) e.stopPropagation();
43257 if(!this.collapsed || this.el.hasActiveFx()) return;
43259 this.afterSlideIn();
43262 this.collapsed = false;
43263 if(this.config.animate && skipAnim !== true){
43264 this.animateExpand();
43268 this.split.el.show();
43270 this.collapsedEl.setLocation(-2000,-2000);
43271 this.collapsedEl.hide();
43272 this.fireEvent("invalidated", this);
43273 this.fireEvent("expanded", this);
43277 animateExpand : function(){
43281 initTabs : function(){
43282 this.bodyEl.setStyle("overflow", "hidden");
43283 var ts = new Roo.TabPanel(this.bodyEl.dom, {
43284 tabPosition: this.bottomTabs ? 'bottom' : 'top',
43285 disableTooltips: this.config.disableTabTips
43287 if(this.config.hideTabs){
43288 ts.stripWrap.setDisplayed(false);
43291 ts.resizeTabs = this.config.resizeTabs === true;
43292 ts.minTabWidth = this.config.minTabWidth || 40;
43293 ts.maxTabWidth = this.config.maxTabWidth || 250;
43294 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
43295 ts.monitorResize = false;
43296 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43297 ts.bodyEl.addClass('x-layout-tabs-body');
43298 this.panels.each(this.initPanelAsTab, this);
43301 initPanelAsTab : function(panel){
43302 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
43303 this.config.closeOnTab && panel.isClosable());
43304 if(panel.tabTip !== undefined){
43305 ti.setTooltip(panel.tabTip);
43307 ti.on("activate", function(){
43308 this.setActivePanel(panel);
43310 if(this.config.closeOnTab){
43311 ti.on("beforeclose", function(t, e){
43313 this.remove(panel);
43319 updatePanelTitle : function(panel, title){
43320 if(this.activePanel == panel){
43321 this.updateTitle(title);
43324 var ti = this.tabs.getTab(panel.getEl().id);
43326 if(panel.tabTip !== undefined){
43327 ti.setTooltip(panel.tabTip);
43332 updateTitle : function(title){
43333 if(this.titleTextEl && !this.config.title){
43334 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
43338 setActivePanel : function(panel){
43339 panel = this.getPanel(panel);
43340 if(this.activePanel && this.activePanel != panel){
43341 this.activePanel.setActiveState(false);
43343 this.activePanel = panel;
43344 panel.setActiveState(true);
43345 if(this.panelSize){
43346 panel.setSize(this.panelSize.width, this.panelSize.height);
43349 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
43351 this.updateTitle(panel.getTitle());
43353 this.fireEvent("invalidated", this);
43355 this.fireEvent("panelactivated", this, panel);
43359 * Shows the specified panel.
43360 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
43361 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
43363 showPanel : function(panel){
43364 if(panel = this.getPanel(panel)){
43366 var tab = this.tabs.getTab(panel.getEl().id);
43367 if(tab.isHidden()){
43368 this.tabs.unhideTab(tab.id);
43372 this.setActivePanel(panel);
43379 * Get the active panel for this region.
43380 * @return {Roo.ContentPanel} The active panel or null
43382 getActivePanel : function(){
43383 return this.activePanel;
43386 validateVisibility : function(){
43387 if(this.panels.getCount() < 1){
43388 this.updateTitle(" ");
43389 this.closeBtn.hide();
43392 if(!this.isVisible()){
43399 * Adds the passed ContentPanel(s) to this region.
43400 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
43401 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
43403 add : function(panel){
43404 if(arguments.length > 1){
43405 for(var i = 0, len = arguments.length; i < len; i++) {
43406 this.add(arguments[i]);
43410 if(this.hasPanel(panel)){
43411 this.showPanel(panel);
43414 panel.setRegion(this);
43415 this.panels.add(panel);
43416 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
43417 this.bodyEl.dom.appendChild(panel.getEl().dom);
43418 if(panel.background !== true){
43419 this.setActivePanel(panel);
43421 this.fireEvent("paneladded", this, panel);
43427 this.initPanelAsTab(panel);
43429 if(panel.background !== true){
43430 this.tabs.activate(panel.getEl().id);
43432 this.fireEvent("paneladded", this, panel);
43437 * Hides the tab for the specified panel.
43438 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43440 hidePanel : function(panel){
43441 if(this.tabs && (panel = this.getPanel(panel))){
43442 this.tabs.hideTab(panel.getEl().id);
43447 * Unhides the tab for a previously hidden panel.
43448 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43450 unhidePanel : function(panel){
43451 if(this.tabs && (panel = this.getPanel(panel))){
43452 this.tabs.unhideTab(panel.getEl().id);
43456 clearPanels : function(){
43457 while(this.panels.getCount() > 0){
43458 this.remove(this.panels.first());
43463 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
43464 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
43465 * @param {Boolean} preservePanel Overrides the config preservePanel option
43466 * @return {Roo.ContentPanel} The panel that was removed
43468 remove : function(panel, preservePanel){
43469 panel = this.getPanel(panel);
43474 this.fireEvent("beforeremove", this, panel, e);
43475 if(e.cancel === true){
43478 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
43479 var panelId = panel.getId();
43480 this.panels.removeKey(panelId);
43482 document.body.appendChild(panel.getEl().dom);
43485 this.tabs.removeTab(panel.getEl().id);
43486 }else if (!preservePanel){
43487 this.bodyEl.dom.removeChild(panel.getEl().dom);
43489 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
43490 var p = this.panels.first();
43491 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
43492 tempEl.appendChild(p.getEl().dom);
43493 this.bodyEl.update("");
43494 this.bodyEl.dom.appendChild(p.getEl().dom);
43496 this.updateTitle(p.getTitle());
43498 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
43499 this.setActivePanel(p);
43501 panel.setRegion(null);
43502 if(this.activePanel == panel){
43503 this.activePanel = null;
43505 if(this.config.autoDestroy !== false && preservePanel !== true){
43506 try{panel.destroy();}catch(e){}
43508 this.fireEvent("panelremoved", this, panel);
43513 * Returns the TabPanel component used by this region
43514 * @return {Roo.TabPanel}
43516 getTabs : function(){
43520 createTool : function(parentEl, className){
43521 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
43522 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
43523 btn.addClassOnOver("x-layout-tools-button-over");
43528 * Ext JS Library 1.1.1
43529 * Copyright(c) 2006-2007, Ext JS, LLC.
43531 * Originally Released Under LGPL - original licence link has changed is not relivant.
43534 * <script type="text/javascript">
43540 * @class Roo.SplitLayoutRegion
43541 * @extends Roo.LayoutRegion
43542 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
43544 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
43545 this.cursor = cursor;
43546 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
43549 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
43550 splitTip : "Drag to resize.",
43551 collapsibleSplitTip : "Drag to resize. Double click to hide.",
43552 useSplitTips : false,
43554 applyConfig : function(config){
43555 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
43558 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
43559 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
43560 /** The SplitBar for this region
43561 * @type Roo.SplitBar */
43562 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
43563 this.split.on("moved", this.onSplitMove, this);
43564 this.split.useShim = config.useShim === true;
43565 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
43566 if(this.useSplitTips){
43567 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
43569 if(config.collapsible){
43570 this.split.el.on("dblclick", this.collapse, this);
43573 if(typeof config.minSize != "undefined"){
43574 this.split.minSize = config.minSize;
43576 if(typeof config.maxSize != "undefined"){
43577 this.split.maxSize = config.maxSize;
43579 if(config.hideWhenEmpty || config.hidden || config.collapsed){
43580 this.hideSplitter();
43585 getHMaxSize : function(){
43586 var cmax = this.config.maxSize || 10000;
43587 var center = this.mgr.getRegion("center");
43588 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
43591 getVMaxSize : function(){
43592 var cmax = this.config.maxSize || 10000;
43593 var center = this.mgr.getRegion("center");
43594 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
43597 onSplitMove : function(split, newSize){
43598 this.fireEvent("resized", this, newSize);
43602 * Returns the {@link Roo.SplitBar} for this region.
43603 * @return {Roo.SplitBar}
43605 getSplitBar : function(){
43610 this.hideSplitter();
43611 Roo.SplitLayoutRegion.superclass.hide.call(this);
43614 hideSplitter : function(){
43616 this.split.el.setLocation(-2000,-2000);
43617 this.split.el.hide();
43623 this.split.el.show();
43625 Roo.SplitLayoutRegion.superclass.show.call(this);
43628 beforeSlide: function(){
43629 if(Roo.isGecko){// firefox overflow auto bug workaround
43630 this.bodyEl.clip();
43631 if(this.tabs) this.tabs.bodyEl.clip();
43632 if(this.activePanel){
43633 this.activePanel.getEl().clip();
43635 if(this.activePanel.beforeSlide){
43636 this.activePanel.beforeSlide();
43642 afterSlide : function(){
43643 if(Roo.isGecko){// firefox overflow auto bug workaround
43644 this.bodyEl.unclip();
43645 if(this.tabs) this.tabs.bodyEl.unclip();
43646 if(this.activePanel){
43647 this.activePanel.getEl().unclip();
43648 if(this.activePanel.afterSlide){
43649 this.activePanel.afterSlide();
43655 initAutoHide : function(){
43656 if(this.autoHide !== false){
43657 if(!this.autoHideHd){
43658 var st = new Roo.util.DelayedTask(this.slideIn, this);
43659 this.autoHideHd = {
43660 "mouseout": function(e){
43661 if(!e.within(this.el, true)){
43665 "mouseover" : function(e){
43671 this.el.on(this.autoHideHd);
43675 clearAutoHide : function(){
43676 if(this.autoHide !== false){
43677 this.el.un("mouseout", this.autoHideHd.mouseout);
43678 this.el.un("mouseover", this.autoHideHd.mouseover);
43682 clearMonitor : function(){
43683 Roo.get(document).un("click", this.slideInIf, this);
43686 // these names are backwards but not changed for compat
43687 slideOut : function(){
43688 if(this.isSlid || this.el.hasActiveFx()){
43691 this.isSlid = true;
43692 if(this.collapseBtn){
43693 this.collapseBtn.hide();
43695 this.closeBtnState = this.closeBtn.getStyle('display');
43696 this.closeBtn.hide();
43698 this.stickBtn.show();
43701 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
43702 this.beforeSlide();
43703 this.el.setStyle("z-index", 10001);
43704 this.el.slideIn(this.getSlideAnchor(), {
43705 callback: function(){
43707 this.initAutoHide();
43708 Roo.get(document).on("click", this.slideInIf, this);
43709 this.fireEvent("slideshow", this);
43716 afterSlideIn : function(){
43717 this.clearAutoHide();
43718 this.isSlid = false;
43719 this.clearMonitor();
43720 this.el.setStyle("z-index", "");
43721 if(this.collapseBtn){
43722 this.collapseBtn.show();
43724 this.closeBtn.setStyle('display', this.closeBtnState);
43726 this.stickBtn.hide();
43728 this.fireEvent("slidehide", this);
43731 slideIn : function(cb){
43732 if(!this.isSlid || this.el.hasActiveFx()){
43736 this.isSlid = false;
43737 this.beforeSlide();
43738 this.el.slideOut(this.getSlideAnchor(), {
43739 callback: function(){
43740 this.el.setLeftTop(-10000, -10000);
43742 this.afterSlideIn();
43750 slideInIf : function(e){
43751 if(!e.within(this.el)){
43756 animateCollapse : function(){
43757 this.beforeSlide();
43758 this.el.setStyle("z-index", 20000);
43759 var anchor = this.getSlideAnchor();
43760 this.el.slideOut(anchor, {
43761 callback : function(){
43762 this.el.setStyle("z-index", "");
43763 this.collapsedEl.slideIn(anchor, {duration:.3});
43765 this.el.setLocation(-10000,-10000);
43767 this.fireEvent("collapsed", this);
43774 animateExpand : function(){
43775 this.beforeSlide();
43776 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
43777 this.el.setStyle("z-index", 20000);
43778 this.collapsedEl.hide({
43781 this.el.slideIn(this.getSlideAnchor(), {
43782 callback : function(){
43783 this.el.setStyle("z-index", "");
43786 this.split.el.show();
43788 this.fireEvent("invalidated", this);
43789 this.fireEvent("expanded", this);
43817 getAnchor : function(){
43818 return this.anchors[this.position];
43821 getCollapseAnchor : function(){
43822 return this.canchors[this.position];
43825 getSlideAnchor : function(){
43826 return this.sanchors[this.position];
43829 getAlignAdj : function(){
43830 var cm = this.cmargins;
43831 switch(this.position){
43847 getExpandAdj : function(){
43848 var c = this.collapsedEl, cm = this.cmargins;
43849 switch(this.position){
43851 return [-(cm.right+c.getWidth()+cm.left), 0];
43854 return [cm.right+c.getWidth()+cm.left, 0];
43857 return [0, -(cm.top+cm.bottom+c.getHeight())];
43860 return [0, cm.top+cm.bottom+c.getHeight()];
43866 * Ext JS Library 1.1.1
43867 * Copyright(c) 2006-2007, Ext JS, LLC.
43869 * Originally Released Under LGPL - original licence link has changed is not relivant.
43872 * <script type="text/javascript">
43875 * These classes are private internal classes
43877 Roo.CenterLayoutRegion = function(mgr, config){
43878 Roo.LayoutRegion.call(this, mgr, config, "center");
43879 this.visible = true;
43880 this.minWidth = config.minWidth || 20;
43881 this.minHeight = config.minHeight || 20;
43884 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
43886 // center panel can't be hidden
43890 // center panel can't be hidden
43893 getMinWidth: function(){
43894 return this.minWidth;
43897 getMinHeight: function(){
43898 return this.minHeight;
43903 Roo.NorthLayoutRegion = function(mgr, config){
43904 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
43906 this.split.placement = Roo.SplitBar.TOP;
43907 this.split.orientation = Roo.SplitBar.VERTICAL;
43908 this.split.el.addClass("x-layout-split-v");
43910 var size = config.initialSize || config.height;
43911 if(typeof size != "undefined"){
43912 this.el.setHeight(size);
43915 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
43916 orientation: Roo.SplitBar.VERTICAL,
43917 getBox : function(){
43918 if(this.collapsed){
43919 return this.collapsedEl.getBox();
43921 var box = this.el.getBox();
43923 box.height += this.split.el.getHeight();
43928 updateBox : function(box){
43929 if(this.split && !this.collapsed){
43930 box.height -= this.split.el.getHeight();
43931 this.split.el.setLeft(box.x);
43932 this.split.el.setTop(box.y+box.height);
43933 this.split.el.setWidth(box.width);
43935 if(this.collapsed){
43936 this.updateBody(box.width, null);
43938 Roo.LayoutRegion.prototype.updateBox.call(this, box);
43942 Roo.SouthLayoutRegion = function(mgr, config){
43943 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
43945 this.split.placement = Roo.SplitBar.BOTTOM;
43946 this.split.orientation = Roo.SplitBar.VERTICAL;
43947 this.split.el.addClass("x-layout-split-v");
43949 var size = config.initialSize || config.height;
43950 if(typeof size != "undefined"){
43951 this.el.setHeight(size);
43954 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
43955 orientation: Roo.SplitBar.VERTICAL,
43956 getBox : function(){
43957 if(this.collapsed){
43958 return this.collapsedEl.getBox();
43960 var box = this.el.getBox();
43962 var sh = this.split.el.getHeight();
43969 updateBox : function(box){
43970 if(this.split && !this.collapsed){
43971 var sh = this.split.el.getHeight();
43974 this.split.el.setLeft(box.x);
43975 this.split.el.setTop(box.y-sh);
43976 this.split.el.setWidth(box.width);
43978 if(this.collapsed){
43979 this.updateBody(box.width, null);
43981 Roo.LayoutRegion.prototype.updateBox.call(this, box);
43985 Roo.EastLayoutRegion = function(mgr, config){
43986 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
43988 this.split.placement = Roo.SplitBar.RIGHT;
43989 this.split.orientation = Roo.SplitBar.HORIZONTAL;
43990 this.split.el.addClass("x-layout-split-h");
43992 var size = config.initialSize || config.width;
43993 if(typeof size != "undefined"){
43994 this.el.setWidth(size);
43997 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
43998 orientation: Roo.SplitBar.HORIZONTAL,
43999 getBox : function(){
44000 if(this.collapsed){
44001 return this.collapsedEl.getBox();
44003 var box = this.el.getBox();
44005 var sw = this.split.el.getWidth();
44012 updateBox : function(box){
44013 if(this.split && !this.collapsed){
44014 var sw = this.split.el.getWidth();
44016 this.split.el.setLeft(box.x);
44017 this.split.el.setTop(box.y);
44018 this.split.el.setHeight(box.height);
44021 if(this.collapsed){
44022 this.updateBody(null, box.height);
44024 Roo.LayoutRegion.prototype.updateBox.call(this, box);
44028 Roo.WestLayoutRegion = function(mgr, config){
44029 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
44031 this.split.placement = Roo.SplitBar.LEFT;
44032 this.split.orientation = Roo.SplitBar.HORIZONTAL;
44033 this.split.el.addClass("x-layout-split-h");
44035 var size = config.initialSize || config.width;
44036 if(typeof size != "undefined"){
44037 this.el.setWidth(size);
44040 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
44041 orientation: Roo.SplitBar.HORIZONTAL,
44042 getBox : function(){
44043 if(this.collapsed){
44044 return this.collapsedEl.getBox();
44046 var box = this.el.getBox();
44048 box.width += this.split.el.getWidth();
44053 updateBox : function(box){
44054 if(this.split && !this.collapsed){
44055 var sw = this.split.el.getWidth();
44057 this.split.el.setLeft(box.x+box.width);
44058 this.split.el.setTop(box.y);
44059 this.split.el.setHeight(box.height);
44061 if(this.collapsed){
44062 this.updateBody(null, box.height);
44064 Roo.LayoutRegion.prototype.updateBox.call(this, box);
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">
44080 * Private internal class for reading and applying state
44082 Roo.LayoutStateManager = function(layout){
44083 // default empty state
44092 Roo.LayoutStateManager.prototype = {
44093 init : function(layout, provider){
44094 this.provider = provider;
44095 var state = provider.get(layout.id+"-layout-state");
44097 var wasUpdating = layout.isUpdating();
44099 layout.beginUpdate();
44101 for(var key in state){
44102 if(typeof state[key] != "function"){
44103 var rstate = state[key];
44104 var r = layout.getRegion(key);
44107 r.resizeTo(rstate.size);
44109 if(rstate.collapsed == true){
44112 r.expand(null, true);
44118 layout.endUpdate();
44120 this.state = state;
44122 this.layout = layout;
44123 layout.on("regionresized", this.onRegionResized, this);
44124 layout.on("regioncollapsed", this.onRegionCollapsed, this);
44125 layout.on("regionexpanded", this.onRegionExpanded, this);
44128 storeState : function(){
44129 this.provider.set(this.layout.id+"-layout-state", this.state);
44132 onRegionResized : function(region, newSize){
44133 this.state[region.getPosition()].size = newSize;
44137 onRegionCollapsed : function(region){
44138 this.state[region.getPosition()].collapsed = true;
44142 onRegionExpanded : function(region){
44143 this.state[region.getPosition()].collapsed = false;
44148 * Ext JS Library 1.1.1
44149 * Copyright(c) 2006-2007, Ext JS, LLC.
44151 * Originally Released Under LGPL - original licence link has changed is not relivant.
44154 * <script type="text/javascript">
44157 * @class Roo.ContentPanel
44158 * @extends Roo.util.Observable
44159 * A basic ContentPanel element.
44160 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
44161 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
44162 * @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
44163 * @cfg {Boolean} closable True if the panel can be closed/removed
44164 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
44165 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
44166 * @cfg {Toolbar} toolbar A toolbar for this panel
44167 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
44168 * @cfg {String} title The title for this panel
44169 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
44170 * @cfg {String} url Calls {@link #setUrl} with this value
44171 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
44172 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
44174 * Create a new ContentPanel.
44175 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
44176 * @param {String/Object} config A string to set only the title or a config object
44177 * @param {String} content (optional) Set the HTML content for this panel
44178 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
44180 Roo.ContentPanel = function(el, config, content){
44184 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
44188 if (config && config.parentLayout) {
44189 el = config.parentLayout.el.createChild();
44192 if(el.autoCreate){ // xtype is available if this is called from factory
44196 this.el = Roo.get(el);
44197 if(!this.el && config && config.autoCreate){
44198 if(typeof config.autoCreate == "object"){
44199 if(!config.autoCreate.id){
44200 config.autoCreate.id = config.id||el;
44202 this.el = Roo.DomHelper.append(document.body,
44203 config.autoCreate, true);
44205 this.el = Roo.DomHelper.append(document.body,
44206 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
44209 this.closable = false;
44210 this.loaded = false;
44211 this.active = false;
44212 if(typeof config == "string"){
44213 this.title = config;
44215 Roo.apply(this, config);
44218 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
44219 this.wrapEl = this.el.wrap();
44220 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
44227 this.resizeEl = Roo.get(this.resizeEl, true);
44229 this.resizeEl = this.el;
44234 * Fires when this panel is activated.
44235 * @param {Roo.ContentPanel} this
44239 * @event deactivate
44240 * Fires when this panel is activated.
44241 * @param {Roo.ContentPanel} this
44243 "deactivate" : true,
44247 * Fires when this panel is resized if fitToFrame is true.
44248 * @param {Roo.ContentPanel} this
44249 * @param {Number} width The width after any component adjustments
44250 * @param {Number} height The height after any component adjustments
44254 if(this.autoScroll){
44255 this.resizeEl.setStyle("overflow", "auto");
44257 content = content || this.content;
44259 this.setContent(content);
44261 if(config && config.url){
44262 this.setUrl(this.url, this.params, this.loadOnce);
44267 Roo.ContentPanel.superclass.constructor.call(this);
44270 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
44272 setRegion : function(region){
44273 this.region = region;
44275 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
44277 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
44282 * Returns the toolbar for this Panel if one was configured.
44283 * @return {Roo.Toolbar}
44285 getToolbar : function(){
44286 return this.toolbar;
44289 setActiveState : function(active){
44290 this.active = active;
44292 this.fireEvent("deactivate", this);
44294 this.fireEvent("activate", this);
44298 * Updates this panel's element
44299 * @param {String} content The new content
44300 * @param {Boolean} loadScripts (optional) true to look for and process scripts
44302 setContent : function(content, loadScripts){
44303 this.el.update(content, loadScripts);
44306 ignoreResize : function(w, h){
44307 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
44310 this.lastSize = {width: w, height: h};
44315 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
44316 * @return {Roo.UpdateManager} The UpdateManager
44318 getUpdateManager : function(){
44319 return this.el.getUpdateManager();
44322 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
44323 * @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:
44326 url: "your-url.php",
44327 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
44328 callback: yourFunction,
44329 scope: yourObject, //(optional scope)
44332 text: "Loading...",
44337 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
44338 * 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.
44339 * @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}
44340 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
44341 * @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.
44342 * @return {Roo.ContentPanel} this
44345 var um = this.el.getUpdateManager();
44346 um.update.apply(um, arguments);
44352 * 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.
44353 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
44354 * @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)
44355 * @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)
44356 * @return {Roo.UpdateManager} The UpdateManager
44358 setUrl : function(url, params, loadOnce){
44359 if(this.refreshDelegate){
44360 this.removeListener("activate", this.refreshDelegate);
44362 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
44363 this.on("activate", this.refreshDelegate);
44364 return this.el.getUpdateManager();
44367 _handleRefresh : function(url, params, loadOnce){
44368 if(!loadOnce || !this.loaded){
44369 var updater = this.el.getUpdateManager();
44370 updater.update(url, params, this._setLoaded.createDelegate(this));
44374 _setLoaded : function(){
44375 this.loaded = true;
44379 * Returns this panel's id
44382 getId : function(){
44387 * Returns this panel's element - used by regiosn to add.
44388 * @return {Roo.Element}
44390 getEl : function(){
44391 return this.wrapEl || this.el;
44394 adjustForComponents : function(width, height){
44395 if(this.resizeEl != this.el){
44396 width -= this.el.getFrameWidth('lr');
44397 height -= this.el.getFrameWidth('tb');
44400 var te = this.toolbar.getEl();
44401 height -= te.getHeight();
44402 te.setWidth(width);
44404 if(this.adjustments){
44405 width += this.adjustments[0];
44406 height += this.adjustments[1];
44408 return {"width": width, "height": height};
44411 setSize : function(width, height){
44412 if(this.fitToFrame && !this.ignoreResize(width, height)){
44413 if(this.fitContainer && this.resizeEl != this.el){
44414 this.el.setSize(width, height);
44416 var size = this.adjustForComponents(width, height);
44417 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
44418 this.fireEvent('resize', this, size.width, size.height);
44423 * Returns this panel's title
44426 getTitle : function(){
44431 * Set this panel's title
44432 * @param {String} title
44434 setTitle : function(title){
44435 this.title = title;
44437 this.region.updatePanelTitle(this, title);
44442 * Returns true is this panel was configured to be closable
44443 * @return {Boolean}
44445 isClosable : function(){
44446 return this.closable;
44449 beforeSlide : function(){
44451 this.resizeEl.clip();
44454 afterSlide : function(){
44456 this.resizeEl.unclip();
44460 * Force a content refresh from the URL specified in the {@link #setUrl} method.
44461 * Will fail silently if the {@link #setUrl} method has not been called.
44462 * This does not activate the panel, just updates its content.
44464 refresh : function(){
44465 if(this.refreshDelegate){
44466 this.loaded = false;
44467 this.refreshDelegate();
44472 * Destroys this panel
44474 destroy : function(){
44475 this.el.removeAllListeners();
44476 var tempEl = document.createElement("span");
44477 tempEl.appendChild(this.el.dom);
44478 tempEl.innerHTML = "";
44484 * Adds a xtype elements to the panel - currently only supports Forms.
44494 * @param {Object} cfg Xtype definition of item to add.
44497 addxtype : function(cfg) {
44499 if (!cfg.xtype.match(/^Form$/)) {
44502 var el = this.el.createChild();
44503 this.form = new Roo.form.Form(cfg);
44505 if ( this.form.allItems.length) this.form.render(el.dom);
44512 * @class Roo.GridPanel
44513 * @extends Roo.ContentPanel
44515 * Create a new GridPanel.
44516 * @param {Roo.grid.Grid} grid The grid for this panel
44517 * @param {String/Object} config A string to set only the panel's title, or a config object
44519 Roo.GridPanel = function(grid, config){
44522 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
44523 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
44525 this.wrapper.dom.appendChild(grid.getGridEl().dom);
44527 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
44530 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
44532 // xtype created footer. - not sure if will work as we normally have to render first..
44533 if (this.footer && !this.footer.el && this.footer.xtype) {
44535 this.footer.container = this.grid.getView().getFooterPanel(true);
44536 this.footer.dataSource = this.grid.dataSource;
44537 this.footer = Roo.factory(this.footer, Roo);
44541 grid.monitorWindowResize = false; // turn off autosizing
44542 grid.autoHeight = false;
44543 grid.autoWidth = false;
44545 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
44548 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
44549 getId : function(){
44550 return this.grid.id;
44554 * Returns the grid for this panel
44555 * @return {Roo.grid.Grid}
44557 getGrid : function(){
44561 setSize : function(width, height){
44562 if(!this.ignoreResize(width, height)){
44563 var grid = this.grid;
44564 var size = this.adjustForComponents(width, height);
44565 grid.getGridEl().setSize(size.width, size.height);
44570 beforeSlide : function(){
44571 this.grid.getView().scroller.clip();
44574 afterSlide : function(){
44575 this.grid.getView().scroller.unclip();
44578 destroy : function(){
44579 this.grid.destroy();
44581 Roo.GridPanel.superclass.destroy.call(this);
44587 * @class Roo.NestedLayoutPanel
44588 * @extends Roo.ContentPanel
44590 * Create a new NestedLayoutPanel.
44593 * @param {Roo.BorderLayout} layout The layout for this panel
44594 * @param {String/Object} config A string to set only the title or a config object
44596 Roo.NestedLayoutPanel = function(layout, config)
44598 // construct with only one argument..
44599 /* FIXME - implement nicer consturctors
44600 if (layout.layout) {
44602 layout = config.layout;
44603 delete config.layout;
44605 if (layout.xtype && !layout.getEl) {
44606 // then layout needs constructing..
44607 layout = Roo.factory(layout, Roo);
44611 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
44613 layout.monitorWindowResize = false; // turn off autosizing
44614 this.layout = layout;
44615 this.layout.getEl().addClass("x-layout-nested-layout");
44621 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
44623 setSize : function(width, height){
44624 if(!this.ignoreResize(width, height)){
44625 var size = this.adjustForComponents(width, height);
44626 var el = this.layout.getEl();
44627 el.setSize(size.width, size.height);
44628 var touch = el.dom.offsetWidth;
44629 this.layout.layout();
44630 // ie requires a double layout on the first pass
44631 if(Roo.isIE && !this.initialized){
44632 this.initialized = true;
44633 this.layout.layout();
44638 // activate all subpanels if not currently active..
44640 setActiveState : function(active){
44641 this.active = active;
44643 this.fireEvent("deactivate", this);
44647 this.fireEvent("activate", this);
44648 // not sure if this should happen before or after..
44649 if (!this.layout) {
44650 return; // should not happen..
44653 for (var r in this.layout.regions) {
44654 reg = this.layout.getRegion(r);
44655 if (reg.getActivePanel()) {
44656 //reg.showPanel(reg.getActivePanel()); // force it to activate..
44657 reg.setActivePanel(reg.getActivePanel());
44660 if (!reg.panels.length) {
44663 reg.showPanel(reg.getPanel(0));
44672 * Returns the nested BorderLayout for this panel
44673 * @return {Roo.BorderLayout}
44675 getLayout : function(){
44676 return this.layout;
44680 * Adds a xtype elements to the layout of the nested panel
44684 xtype : 'ContentPanel',
44691 xtype : 'NestedLayoutPanel',
44697 items : [ ... list of content panels or nested layout panels.. ]
44701 * @param {Object} cfg Xtype definition of item to add.
44703 addxtype : function(cfg) {
44704 return this.layout.addxtype(cfg);
44709 Roo.ScrollPanel = function(el, config, content){
44710 config = config || {};
44711 config.fitToFrame = true;
44712 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
44714 this.el.dom.style.overflow = "hidden";
44715 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
44716 this.el.removeClass("x-layout-inactive-content");
44717 this.el.on("mousewheel", this.onWheel, this);
44719 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
44720 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
44721 up.unselectable(); down.unselectable();
44722 up.on("click", this.scrollUp, this);
44723 down.on("click", this.scrollDown, this);
44724 up.addClassOnOver("x-scroller-btn-over");
44725 down.addClassOnOver("x-scroller-btn-over");
44726 up.addClassOnClick("x-scroller-btn-click");
44727 down.addClassOnClick("x-scroller-btn-click");
44728 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
44730 this.resizeEl = this.el;
44731 this.el = wrap; this.up = up; this.down = down;
44734 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
44736 wheelIncrement : 5,
44737 scrollUp : function(){
44738 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
44741 scrollDown : function(){
44742 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
44745 afterScroll : function(){
44746 var el = this.resizeEl;
44747 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
44748 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44749 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
44752 setSize : function(){
44753 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
44754 this.afterScroll();
44757 onWheel : function(e){
44758 var d = e.getWheelDelta();
44759 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
44760 this.afterScroll();
44764 setContent : function(content, loadScripts){
44765 this.resizeEl.update(content, loadScripts);
44779 * @class Roo.TreePanel
44780 * @extends Roo.ContentPanel
44782 * Create a new TreePanel.
44783 * @param {String/Object} config A string to set only the panel's title, or a config object
44784 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
44786 Roo.TreePanel = function(config){
44787 var el = config.el;
44788 var tree = config.tree;
44789 delete config.tree;
44790 delete config.el; // hopefull!
44791 Roo.TreePanel.superclass.constructor.call(this, el, config);
44792 var treeEl = el.createChild();
44793 this.tree = new Roo.tree.TreePanel(treeEl , tree);
44794 //console.log(tree);
44795 this.on('activate', function()
44797 if (this.tree.rendered) {
44800 //console.log('render tree');
44801 this.tree.render();
44804 this.on('resize', function (cp, w, h) {
44805 this.tree.innerCt.setWidth(w);
44806 this.tree.innerCt.setHeight(h);
44807 this.tree.innerCt.setStyle('overflow-y', 'auto');
44814 Roo.extend(Roo.TreePanel, Roo.ContentPanel);
44828 * Ext JS Library 1.1.1
44829 * Copyright(c) 2006-2007, Ext JS, LLC.
44831 * Originally Released Under LGPL - original licence link has changed is not relivant.
44834 * <script type="text/javascript">
44839 * @class Roo.ReaderLayout
44840 * @extends Roo.BorderLayout
44841 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
44842 * center region containing two nested regions (a top one for a list view and one for item preview below),
44843 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
44844 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
44845 * expedites the setup of the overall layout and regions for this common application style.
44848 var reader = new Roo.ReaderLayout();
44849 var CP = Roo.ContentPanel; // shortcut for adding
44851 reader.beginUpdate();
44852 reader.add("north", new CP("north", "North"));
44853 reader.add("west", new CP("west", {title: "West"}));
44854 reader.add("east", new CP("east", {title: "East"}));
44856 reader.regions.listView.add(new CP("listView", "List"));
44857 reader.regions.preview.add(new CP("preview", "Preview"));
44858 reader.endUpdate();
44861 * Create a new ReaderLayout
44862 * @param {Object} config Configuration options
44863 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
44864 * document.body if omitted)
44866 Roo.ReaderLayout = function(config, renderTo){
44867 var c = config || {size:{}};
44868 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
44869 north: c.north !== false ? Roo.apply({
44873 }, c.north) : false,
44874 west: c.west !== false ? Roo.apply({
44882 margins:{left:5,right:0,bottom:5,top:5},
44883 cmargins:{left:5,right:5,bottom:5,top:5}
44884 }, c.west) : false,
44885 east: c.east !== false ? Roo.apply({
44893 margins:{left:0,right:5,bottom:5,top:5},
44894 cmargins:{left:5,right:5,bottom:5,top:5}
44895 }, c.east) : false,
44896 center: Roo.apply({
44897 tabPosition: 'top',
44901 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
44905 this.el.addClass('x-reader');
44907 this.beginUpdate();
44909 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
44910 south: c.preview !== false ? Roo.apply({
44917 cmargins:{top:5,left:0, right:0, bottom:0}
44918 }, c.preview) : false,
44919 center: Roo.apply({
44925 this.add('center', new Roo.NestedLayoutPanel(inner,
44926 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
44930 this.regions.preview = inner.getRegion('south');
44931 this.regions.listView = inner.getRegion('center');
44934 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
44936 * Ext JS Library 1.1.1
44937 * Copyright(c) 2006-2007, Ext JS, LLC.
44939 * Originally Released Under LGPL - original licence link has changed is not relivant.
44942 * <script type="text/javascript">
44946 * @class Roo.grid.Grid
44947 * @extends Roo.util.Observable
44948 * This class represents the primary interface of a component based grid control.
44949 * <br><br>Usage:<pre><code>
44950 var grid = new Roo.grid.Grid("my-container-id", {
44953 selModel: mySelectionModel,
44954 autoSizeColumns: true,
44955 monitorWindowResize: false,
44956 trackMouseOver: true
44961 * <b>Common Problems:</b><br/>
44962 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
44963 * element will correct this<br/>
44964 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
44965 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
44966 * are unpredictable.<br/>
44967 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
44968 * grid to calculate dimensions/offsets.<br/>
44970 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
44971 * The container MUST have some type of size defined for the grid to fill. The container will be
44972 * automatically set to position relative if it isn't already.
44973 * @param {Object} config A config object that sets properties on this grid.
44975 Roo.grid.Grid = function(container, config){
44976 // initialize the container
44977 this.container = Roo.get(container);
44978 this.container.update("");
44979 this.container.setStyle("overflow", "hidden");
44980 this.container.addClass('x-grid-container');
44982 this.id = this.container.id;
44984 Roo.apply(this, config);
44985 // check and correct shorthanded configs
44987 this.dataSource = this.ds;
44991 this.colModel = this.cm;
44995 this.selModel = this.sm;
44999 if (this.selModel) {
45000 this.selModel = Roo.factory(this.selModel, Roo.grid);
45001 this.sm = this.selModel;
45003 if (typeof(this.colModel.config) == 'undefined') {
45004 this.colModel = new Roo.grid.ColumnModel(this.colModel);
45005 this.cm = this.colModel;
45007 if (this.dataSource) {
45008 this.dataSource= Roo.factory(this.dataSource, Roo.data);
45009 this.ds = this.dataSource;
45016 this.container.setWidth(this.width);
45020 this.container.setHeight(this.height);
45027 * The raw click event for the entire grid.
45028 * @param {Roo.EventObject} e
45033 * The raw dblclick event for the entire grid.
45034 * @param {Roo.EventObject} e
45038 * @event contextmenu
45039 * The raw contextmenu event for the entire grid.
45040 * @param {Roo.EventObject} e
45042 "contextmenu" : true,
45045 * The raw mousedown event for the entire grid.
45046 * @param {Roo.EventObject} e
45048 "mousedown" : true,
45051 * The raw mouseup event for the entire grid.
45052 * @param {Roo.EventObject} e
45057 * The raw mouseover event for the entire grid.
45058 * @param {Roo.EventObject} e
45060 "mouseover" : true,
45063 * The raw mouseout event for the entire grid.
45064 * @param {Roo.EventObject} e
45069 * The raw keypress event for the entire grid.
45070 * @param {Roo.EventObject} e
45075 * The raw keydown event for the entire grid.
45076 * @param {Roo.EventObject} e
45084 * Fires when a cell is clicked
45085 * @param {Grid} this
45086 * @param {Number} rowIndex
45087 * @param {Number} columnIndex
45088 * @param {Roo.EventObject} e
45090 "cellclick" : true,
45092 * @event celldblclick
45093 * Fires when a cell is double clicked
45094 * @param {Grid} this
45095 * @param {Number} rowIndex
45096 * @param {Number} columnIndex
45097 * @param {Roo.EventObject} e
45099 "celldblclick" : true,
45102 * Fires when a row is clicked
45103 * @param {Grid} this
45104 * @param {Number} rowIndex
45105 * @param {Roo.EventObject} e
45109 * @event rowdblclick
45110 * Fires when a row is double clicked
45111 * @param {Grid} this
45112 * @param {Number} rowIndex
45113 * @param {Roo.EventObject} e
45115 "rowdblclick" : true,
45117 * @event headerclick
45118 * Fires when a header is clicked
45119 * @param {Grid} this
45120 * @param {Number} columnIndex
45121 * @param {Roo.EventObject} e
45123 "headerclick" : true,
45125 * @event headerdblclick
45126 * Fires when a header cell is double clicked
45127 * @param {Grid} this
45128 * @param {Number} columnIndex
45129 * @param {Roo.EventObject} e
45131 "headerdblclick" : true,
45133 * @event rowcontextmenu
45134 * Fires when a row is right clicked
45135 * @param {Grid} this
45136 * @param {Number} rowIndex
45137 * @param {Roo.EventObject} e
45139 "rowcontextmenu" : true,
45141 * @event cellcontextmenu
45142 * Fires when a cell is right clicked
45143 * @param {Grid} this
45144 * @param {Number} rowIndex
45145 * @param {Number} cellIndex
45146 * @param {Roo.EventObject} e
45148 "cellcontextmenu" : true,
45150 * @event headercontextmenu
45151 * Fires when a header is right clicked
45152 * @param {Grid} this
45153 * @param {Number} columnIndex
45154 * @param {Roo.EventObject} e
45156 "headercontextmenu" : true,
45158 * @event bodyscroll
45159 * Fires when the body element is scrolled
45160 * @param {Number} scrollLeft
45161 * @param {Number} scrollTop
45163 "bodyscroll" : true,
45165 * @event columnresize
45166 * Fires when the user resizes a column
45167 * @param {Number} columnIndex
45168 * @param {Number} newSize
45170 "columnresize" : true,
45172 * @event columnmove
45173 * Fires when the user moves a column
45174 * @param {Number} oldIndex
45175 * @param {Number} newIndex
45177 "columnmove" : true,
45180 * Fires when row(s) start being dragged
45181 * @param {Grid} this
45182 * @param {Roo.GridDD} dd The drag drop object
45183 * @param {event} e The raw browser event
45185 "startdrag" : true,
45188 * Fires when a drag operation is complete
45189 * @param {Grid} this
45190 * @param {Roo.GridDD} dd The drag drop object
45191 * @param {event} e The raw browser event
45196 * Fires when dragged row(s) are dropped on a valid DD target
45197 * @param {Grid} this
45198 * @param {Roo.GridDD} dd The drag drop object
45199 * @param {String} targetId The target drag drop object
45200 * @param {event} e The raw browser event
45205 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
45206 * @param {Grid} this
45207 * @param {Roo.GridDD} dd The drag drop object
45208 * @param {String} targetId The target drag drop object
45209 * @param {event} e The raw browser event
45214 * Fires when the dragged row(s) first cross another DD target while being dragged
45215 * @param {Grid} this
45216 * @param {Roo.GridDD} dd The drag drop object
45217 * @param {String} targetId The target drag drop object
45218 * @param {event} e The raw browser event
45220 "dragenter" : true,
45223 * Fires when the dragged row(s) leave another DD target while being dragged
45224 * @param {Grid} this
45225 * @param {Roo.GridDD} dd The drag drop object
45226 * @param {String} targetId The target drag drop object
45227 * @param {event} e The raw browser event
45232 * Fires when the grid is rendered
45233 * @param {Grid} grid
45238 Roo.grid.Grid.superclass.constructor.call(this);
45240 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
45242 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
45244 minColumnWidth : 25,
45247 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
45248 * <b>on initial render.</b> It is more efficient to explicitly size the columns
45249 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
45251 autoSizeColumns : false,
45254 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
45256 autoSizeHeaders : true,
45259 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
45261 monitorWindowResize : true,
45264 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
45265 * rows measured to get a columns size. Default is 0 (all rows).
45267 maxRowsToMeasure : 0,
45270 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
45272 trackMouseOver : true,
45275 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
45277 enableDragDrop : false,
45280 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
45282 enableColumnMove : true,
45285 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
45287 enableColumnHide : true,
45290 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
45292 enableRowHeightSync : false,
45295 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
45300 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
45302 autoHeight : false,
45305 * @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.
45307 autoExpandColumn : false,
45310 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
45313 autoExpandMin : 50,
45316 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
45318 autoExpandMax : 1000,
45321 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
45326 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
45334 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
45335 * of a fixed width. Default is false.
45338 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
45341 * Called once after all setup has been completed and the grid is ready to be rendered.
45342 * @return {Roo.grid.Grid} this
45344 render : function(){
45345 var c = this.container;
45346 // try to detect autoHeight/width mode
45347 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
45348 this.autoHeight = true;
45350 var view = this.getView();
45353 c.on("click", this.onClick, this);
45354 c.on("dblclick", this.onDblClick, this);
45355 c.on("contextmenu", this.onContextMenu, this);
45356 c.on("keydown", this.onKeyDown, this);
45358 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
45360 this.getSelectionModel().init(this);
45365 this.loadMask = new Roo.LoadMask(this.container,
45366 Roo.apply({store:this.dataSource}, this.loadMask));
45370 if (this.toolbar && this.toolbar.xtype) {
45371 this.toolbar.container = this.getView().getHeaderPanel(true);
45372 this.toolbar = new Ext.Toolbar(this.toolbar);
45374 if (this.footer && this.footer.xtype) {
45375 this.footer.dataSource = this.getDataSource();
45376 this.footer.container = this.getView().getFooterPanel(true);
45377 this.footer = Roo.factory(this.footer, Roo);
45379 this.rendered = true;
45380 this.fireEvent('render', this);
45385 * Reconfigures the grid to use a different Store and Column Model.
45386 * The View will be bound to the new objects and refreshed.
45387 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
45388 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
45390 reconfigure : function(dataSource, colModel){
45392 this.loadMask.destroy();
45393 this.loadMask = new Roo.LoadMask(this.container,
45394 Roo.apply({store:dataSource}, this.loadMask));
45396 this.view.bind(dataSource, colModel);
45397 this.dataSource = dataSource;
45398 this.colModel = colModel;
45399 this.view.refresh(true);
45403 onKeyDown : function(e){
45404 this.fireEvent("keydown", e);
45408 * Destroy this grid.
45409 * @param {Boolean} removeEl True to remove the element
45411 destroy : function(removeEl, keepListeners){
45413 this.loadMask.destroy();
45415 var c = this.container;
45416 c.removeAllListeners();
45417 this.view.destroy();
45418 this.colModel.purgeListeners();
45419 if(!keepListeners){
45420 this.purgeListeners();
45423 if(removeEl === true){
45429 processEvent : function(name, e){
45430 this.fireEvent(name, e);
45431 var t = e.getTarget();
45433 var header = v.findHeaderIndex(t);
45434 if(header !== false){
45435 this.fireEvent("header" + name, this, header, e);
45437 var row = v.findRowIndex(t);
45438 var cell = v.findCellIndex(t);
45440 this.fireEvent("row" + name, this, row, e);
45441 if(cell !== false){
45442 this.fireEvent("cell" + name, this, row, cell, e);
45449 onClick : function(e){
45450 this.processEvent("click", e);
45454 onContextMenu : function(e, t){
45455 this.processEvent("contextmenu", e);
45459 onDblClick : function(e){
45460 this.processEvent("dblclick", e);
45464 walkCells : function(row, col, step, fn, scope){
45465 var cm = this.colModel, clen = cm.getColumnCount();
45466 var ds = this.dataSource, rlen = ds.getCount(), first = true;
45478 if(fn.call(scope || this, row, col, cm) === true){
45496 if(fn.call(scope || this, row, col, cm) === true){
45508 getSelections : function(){
45509 return this.selModel.getSelections();
45513 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
45514 * but if manual update is required this method will initiate it.
45516 autoSize : function(){
45518 this.view.layout();
45519 if(this.view.adjustForScroll){
45520 this.view.adjustForScroll();
45526 * Returns the grid's underlying element.
45527 * @return {Element} The element
45529 getGridEl : function(){
45530 return this.container;
45533 // private for compatibility, overridden by editor grid
45534 stopEditing : function(){},
45537 * Returns the grid's SelectionModel.
45538 * @return {SelectionModel}
45540 getSelectionModel : function(){
45541 if(!this.selModel){
45542 this.selModel = new Roo.grid.RowSelectionModel();
45544 return this.selModel;
45548 * Returns the grid's DataSource.
45549 * @return {DataSource}
45551 getDataSource : function(){
45552 return this.dataSource;
45556 * Returns the grid's ColumnModel.
45557 * @return {ColumnModel}
45559 getColumnModel : function(){
45560 return this.colModel;
45564 * Returns the grid's GridView object.
45565 * @return {GridView}
45567 getView : function(){
45569 this.view = new Roo.grid.GridView(this.viewConfig);
45574 * Called to get grid's drag proxy text, by default returns this.ddText.
45577 getDragDropText : function(){
45578 var count = this.selModel.getCount();
45579 return String.format(this.ddText, count, count == 1 ? '' : 's');
45583 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
45584 * %0 is replaced with the number of selected rows.
45587 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
45589 * Ext JS Library 1.1.1
45590 * Copyright(c) 2006-2007, Ext JS, LLC.
45592 * Originally Released Under LGPL - original licence link has changed is not relivant.
45595 * <script type="text/javascript">
45598 Roo.grid.AbstractGridView = function(){
45602 "beforerowremoved" : true,
45603 "beforerowsinserted" : true,
45604 "beforerefresh" : true,
45605 "rowremoved" : true,
45606 "rowsinserted" : true,
45607 "rowupdated" : true,
45610 Roo.grid.AbstractGridView.superclass.constructor.call(this);
45613 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
45614 rowClass : "x-grid-row",
45615 cellClass : "x-grid-cell",
45616 tdClass : "x-grid-td",
45617 hdClass : "x-grid-hd",
45618 splitClass : "x-grid-hd-split",
45620 init: function(grid){
45622 var cid = this.grid.getGridEl().id;
45623 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
45624 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
45625 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
45626 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
45629 getColumnRenderers : function(){
45630 var renderers = [];
45631 var cm = this.grid.colModel;
45632 var colCount = cm.getColumnCount();
45633 for(var i = 0; i < colCount; i++){
45634 renderers[i] = cm.getRenderer(i);
45639 getColumnIds : function(){
45641 var cm = this.grid.colModel;
45642 var colCount = cm.getColumnCount();
45643 for(var i = 0; i < colCount; i++){
45644 ids[i] = cm.getColumnId(i);
45649 getDataIndexes : function(){
45650 if(!this.indexMap){
45651 this.indexMap = this.buildIndexMap();
45653 return this.indexMap.colToData;
45656 getColumnIndexByDataIndex : function(dataIndex){
45657 if(!this.indexMap){
45658 this.indexMap = this.buildIndexMap();
45660 return this.indexMap.dataToCol[dataIndex];
45664 * Set a css style for a column dynamically.
45665 * @param {Number} colIndex The index of the column
45666 * @param {String} name The css property name
45667 * @param {String} value The css value
45669 setCSSStyle : function(colIndex, name, value){
45670 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
45671 Roo.util.CSS.updateRule(selector, name, value);
45674 generateRules : function(cm){
45675 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
45676 Roo.util.CSS.removeStyleSheet(rulesId);
45677 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
45678 var cid = cm.getColumnId(i);
45679 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
45680 this.tdSelector, cid, " {\n}\n",
45681 this.hdSelector, cid, " {\n}\n",
45682 this.splitSelector, cid, " {\n}\n");
45684 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
45688 * Ext JS Library 1.1.1
45689 * Copyright(c) 2006-2007, Ext JS, LLC.
45691 * Originally Released Under LGPL - original licence link has changed is not relivant.
45694 * <script type="text/javascript">
45698 // This is a support class used internally by the Grid components
45699 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
45701 this.view = grid.getView();
45702 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45703 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
45705 this.setHandleElId(Roo.id(hd));
45706 this.setOuterHandleElId(Roo.id(hd2));
45708 this.scroll = false;
45710 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
45712 getDragData : function(e){
45713 var t = Roo.lib.Event.getTarget(e);
45714 var h = this.view.findHeaderCell(t);
45716 return {ddel: h.firstChild, header:h};
45721 onInitDrag : function(e){
45722 this.view.headersDisabled = true;
45723 var clone = this.dragData.ddel.cloneNode(true);
45724 clone.id = Roo.id();
45725 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
45726 this.proxy.update(clone);
45730 afterValidDrop : function(){
45732 setTimeout(function(){
45733 v.headersDisabled = false;
45737 afterInvalidDrop : function(){
45739 setTimeout(function(){
45740 v.headersDisabled = false;
45746 * Ext JS Library 1.1.1
45747 * Copyright(c) 2006-2007, Ext JS, LLC.
45749 * Originally Released Under LGPL - original licence link has changed is not relivant.
45752 * <script type="text/javascript">
45755 // This is a support class used internally by the Grid components
45756 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
45758 this.view = grid.getView();
45759 // split the proxies so they don't interfere with mouse events
45760 this.proxyTop = Roo.DomHelper.append(document.body, {
45761 cls:"col-move-top", html:" "
45763 this.proxyBottom = Roo.DomHelper.append(document.body, {
45764 cls:"col-move-bottom", html:" "
45766 this.proxyTop.hide = this.proxyBottom.hide = function(){
45767 this.setLeftTop(-100,-100);
45768 this.setStyle("visibility", "hidden");
45770 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
45771 // temporarily disabled
45772 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
45773 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
45775 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
45776 proxyOffsets : [-4, -9],
45777 fly: Roo.Element.fly,
45779 getTargetFromEvent : function(e){
45780 var t = Roo.lib.Event.getTarget(e);
45781 var cindex = this.view.findCellIndex(t);
45782 if(cindex !== false){
45783 return this.view.getHeaderCell(cindex);
45787 nextVisible : function(h){
45788 var v = this.view, cm = this.grid.colModel;
45791 if(!cm.isHidden(v.getCellIndex(h))){
45799 prevVisible : function(h){
45800 var v = this.view, cm = this.grid.colModel;
45803 if(!cm.isHidden(v.getCellIndex(h))){
45811 positionIndicator : function(h, n, e){
45812 var x = Roo.lib.Event.getPageX(e);
45813 var r = Roo.lib.Dom.getRegion(n.firstChild);
45814 var px, pt, py = r.top + this.proxyOffsets[1];
45815 if((r.right - x) <= (r.right-r.left)/2){
45816 px = r.right+this.view.borderWidth;
45822 var oldIndex = this.view.getCellIndex(h);
45823 var newIndex = this.view.getCellIndex(n);
45825 if(this.grid.colModel.isFixed(newIndex)){
45829 var locked = this.grid.colModel.isLocked(newIndex);
45834 if(oldIndex < newIndex){
45837 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
45840 px += this.proxyOffsets[0];
45841 this.proxyTop.setLeftTop(px, py);
45842 this.proxyTop.show();
45843 if(!this.bottomOffset){
45844 this.bottomOffset = this.view.mainHd.getHeight();
45846 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
45847 this.proxyBottom.show();
45851 onNodeEnter : function(n, dd, e, data){
45852 if(data.header != n){
45853 this.positionIndicator(data.header, n, e);
45857 onNodeOver : function(n, dd, e, data){
45858 var result = false;
45859 if(data.header != n){
45860 result = this.positionIndicator(data.header, n, e);
45863 this.proxyTop.hide();
45864 this.proxyBottom.hide();
45866 return result ? this.dropAllowed : this.dropNotAllowed;
45869 onNodeOut : function(n, dd, e, data){
45870 this.proxyTop.hide();
45871 this.proxyBottom.hide();
45874 onNodeDrop : function(n, dd, e, data){
45875 var h = data.header;
45877 var cm = this.grid.colModel;
45878 var x = Roo.lib.Event.getPageX(e);
45879 var r = Roo.lib.Dom.getRegion(n.firstChild);
45880 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
45881 var oldIndex = this.view.getCellIndex(h);
45882 var newIndex = this.view.getCellIndex(n);
45883 var locked = cm.isLocked(newIndex);
45887 if(oldIndex < newIndex){
45890 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
45893 cm.setLocked(oldIndex, locked, true);
45894 cm.moveColumn(oldIndex, newIndex);
45895 this.grid.fireEvent("columnmove", oldIndex, newIndex);
45903 * Ext JS Library 1.1.1
45904 * Copyright(c) 2006-2007, Ext JS, LLC.
45906 * Originally Released Under LGPL - original licence link has changed is not relivant.
45909 * <script type="text/javascript">
45913 * @class Roo.grid.GridView
45914 * @extends Roo.util.Observable
45917 * @param {Object} config
45919 Roo.grid.GridView = function(config){
45920 Roo.grid.GridView.superclass.constructor.call(this);
45923 Roo.apply(this, config);
45926 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
45929 * Override this function to apply custom css classes to rows during rendering
45930 * @param {Record} record The record
45931 * @param {Number} index
45932 * @method getRowClass
45934 rowClass : "x-grid-row",
45936 cellClass : "x-grid-col",
45938 tdClass : "x-grid-td",
45940 hdClass : "x-grid-hd",
45942 splitClass : "x-grid-split",
45944 sortClasses : ["sort-asc", "sort-desc"],
45946 enableMoveAnim : false,
45950 dh : Roo.DomHelper,
45952 fly : Roo.Element.fly,
45954 css : Roo.util.CSS,
45960 scrollIncrement : 22,
45962 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
45964 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
45966 bind : function(ds, cm){
45968 this.ds.un("load", this.onLoad, this);
45969 this.ds.un("datachanged", this.onDataChange, this);
45970 this.ds.un("add", this.onAdd, this);
45971 this.ds.un("remove", this.onRemove, this);
45972 this.ds.un("update", this.onUpdate, this);
45973 this.ds.un("clear", this.onClear, this);
45976 ds.on("load", this.onLoad, this);
45977 ds.on("datachanged", this.onDataChange, this);
45978 ds.on("add", this.onAdd, this);
45979 ds.on("remove", this.onRemove, this);
45980 ds.on("update", this.onUpdate, this);
45981 ds.on("clear", this.onClear, this);
45986 this.cm.un("widthchange", this.onColWidthChange, this);
45987 this.cm.un("headerchange", this.onHeaderChange, this);
45988 this.cm.un("hiddenchange", this.onHiddenChange, this);
45989 this.cm.un("columnmoved", this.onColumnMove, this);
45990 this.cm.un("columnlockchange", this.onColumnLock, this);
45993 this.generateRules(cm);
45994 cm.on("widthchange", this.onColWidthChange, this);
45995 cm.on("headerchange", this.onHeaderChange, this);
45996 cm.on("hiddenchange", this.onHiddenChange, this);
45997 cm.on("columnmoved", this.onColumnMove, this);
45998 cm.on("columnlockchange", this.onColumnLock, this);
46003 init: function(grid){
46004 Roo.grid.GridView.superclass.init.call(this, grid);
46006 this.bind(grid.dataSource, grid.colModel);
46008 grid.on("headerclick", this.handleHeaderClick, this);
46010 if(grid.trackMouseOver){
46011 grid.on("mouseover", this.onRowOver, this);
46012 grid.on("mouseout", this.onRowOut, this);
46014 grid.cancelTextSelection = function(){};
46015 this.gridId = grid.id;
46017 var tpls = this.templates || {};
46020 tpls.master = new Roo.Template(
46021 '<div class="x-grid" hidefocus="true">',
46022 '<div class="x-grid-topbar"></div>',
46023 '<div class="x-grid-scroller"><div></div></div>',
46024 '<div class="x-grid-locked">',
46025 '<div class="x-grid-header">{lockedHeader}</div>',
46026 '<div class="x-grid-body">{lockedBody}</div>',
46028 '<div class="x-grid-viewport">',
46029 '<div class="x-grid-header">{header}</div>',
46030 '<div class="x-grid-body">{body}</div>',
46032 '<div class="x-grid-bottombar"></div>',
46033 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
46034 '<div class="x-grid-resize-proxy"> </div>',
46037 tpls.master.disableformats = true;
46041 tpls.header = new Roo.Template(
46042 '<table border="0" cellspacing="0" cellpadding="0">',
46043 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
46046 tpls.header.disableformats = true;
46048 tpls.header.compile();
46051 tpls.hcell = new Roo.Template(
46052 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
46053 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
46056 tpls.hcell.disableFormats = true;
46058 tpls.hcell.compile();
46061 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
46062 tpls.hsplit.disableFormats = true;
46064 tpls.hsplit.compile();
46067 tpls.body = new Roo.Template(
46068 '<table border="0" cellspacing="0" cellpadding="0">',
46069 "<tbody>{rows}</tbody>",
46072 tpls.body.disableFormats = true;
46074 tpls.body.compile();
46077 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
46078 tpls.row.disableFormats = true;
46080 tpls.row.compile();
46083 tpls.cell = new Roo.Template(
46084 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
46085 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
46088 tpls.cell.disableFormats = true;
46090 tpls.cell.compile();
46092 this.templates = tpls;
46095 // remap these for backwards compat
46096 onColWidthChange : function(){
46097 this.updateColumns.apply(this, arguments);
46099 onHeaderChange : function(){
46100 this.updateHeaders.apply(this, arguments);
46102 onHiddenChange : function(){
46103 this.handleHiddenChange.apply(this, arguments);
46105 onColumnMove : function(){
46106 this.handleColumnMove.apply(this, arguments);
46108 onColumnLock : function(){
46109 this.handleLockChange.apply(this, arguments);
46112 onDataChange : function(){
46114 this.updateHeaderSortState();
46117 onClear : function(){
46121 onUpdate : function(ds, record){
46122 this.refreshRow(record);
46125 refreshRow : function(record){
46126 var ds = this.ds, index;
46127 if(typeof record == 'number'){
46129 record = ds.getAt(index);
46131 index = ds.indexOf(record);
46133 this.insertRows(ds, index, index, true);
46134 this.onRemove(ds, record, index+1, true);
46135 this.syncRowHeights(index, index);
46137 this.fireEvent("rowupdated", this, index, record);
46140 onAdd : function(ds, records, index){
46141 this.insertRows(ds, index, index + (records.length-1));
46144 onRemove : function(ds, record, index, isUpdate){
46145 if(isUpdate !== true){
46146 this.fireEvent("beforerowremoved", this, index, record);
46148 var bt = this.getBodyTable(), lt = this.getLockedTable();
46149 if(bt.rows[index]){
46150 bt.firstChild.removeChild(bt.rows[index]);
46152 if(lt.rows[index]){
46153 lt.firstChild.removeChild(lt.rows[index]);
46155 if(isUpdate !== true){
46156 this.stripeRows(index);
46157 this.syncRowHeights(index, index);
46159 this.fireEvent("rowremoved", this, index, record);
46163 onLoad : function(){
46164 this.scrollToTop();
46168 * Scrolls the grid to the top
46170 scrollToTop : function(){
46172 this.scroller.dom.scrollTop = 0;
46178 * Gets a panel in the header of the grid that can be used for toolbars etc.
46179 * After modifying the contents of this panel a call to grid.autoSize() may be
46180 * required to register any changes in size.
46181 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
46182 * @return Roo.Element
46184 getHeaderPanel : function(doShow){
46186 this.headerPanel.show();
46188 return this.headerPanel;
46192 * Gets a panel in the footer of the grid that can be used for toolbars etc.
46193 * After modifying the contents of this panel a call to grid.autoSize() may be
46194 * required to register any changes in size.
46195 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
46196 * @return Roo.Element
46198 getFooterPanel : function(doShow){
46200 this.footerPanel.show();
46202 return this.footerPanel;
46205 initElements : function(){
46206 var E = Roo.Element;
46207 var el = this.grid.getGridEl().dom.firstChild;
46208 var cs = el.childNodes;
46210 this.el = new E(el);
46211 this.headerPanel = new E(el.firstChild);
46212 this.headerPanel.enableDisplayMode("block");
46214 this.scroller = new E(cs[1]);
46215 this.scrollSizer = new E(this.scroller.dom.firstChild);
46217 this.lockedWrap = new E(cs[2]);
46218 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
46219 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
46221 this.mainWrap = new E(cs[3]);
46222 this.mainHd = new E(this.mainWrap.dom.firstChild);
46223 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
46225 this.footerPanel = new E(cs[4]);
46226 this.footerPanel.enableDisplayMode("block");
46228 this.focusEl = new E(cs[5]);
46229 this.focusEl.swallowEvent("click", true);
46230 this.resizeProxy = new E(cs[6]);
46232 this.headerSelector = String.format(
46233 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
46234 this.lockedHd.id, this.mainHd.id
46237 this.splitterSelector = String.format(
46238 '#{0} div.x-grid-split, #{1} div.x-grid-split',
46239 this.lockedHd.id, this.mainHd.id
46243 getHeaderCell : function(index){
46244 return Roo.DomQuery.select(this.headerSelector)[index];
46247 getHeaderCellMeasure : function(index){
46248 return this.getHeaderCell(index).firstChild;
46251 getHeaderCellText : function(index){
46252 return this.getHeaderCell(index).firstChild.firstChild;
46255 getLockedTable : function(){
46256 return this.lockedBody.dom.firstChild;
46259 getBodyTable : function(){
46260 return this.mainBody.dom.firstChild;
46263 getLockedRow : function(index){
46264 return this.getLockedTable().rows[index];
46267 getRow : function(index){
46268 return this.getBodyTable().rows[index];
46271 getRowComposite : function(index){
46273 this.rowEl = new Roo.CompositeElementLite();
46275 var els = [], lrow, mrow;
46276 if(lrow = this.getLockedRow(index)){
46279 if(mrow = this.getRow(index)){
46282 this.rowEl.elements = els;
46286 getCell : function(rowIndex, colIndex){
46287 var locked = this.cm.getLockedCount();
46289 if(colIndex < locked){
46290 source = this.lockedBody.dom.firstChild;
46292 source = this.mainBody.dom.firstChild;
46293 colIndex -= locked;
46295 return source.rows[rowIndex].childNodes[colIndex];
46298 getCellText : function(rowIndex, colIndex){
46299 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
46302 getCellBox : function(cell){
46303 var b = this.fly(cell).getBox();
46304 if(Roo.isOpera){ // opera fails to report the Y
46305 b.y = cell.offsetTop + this.mainBody.getY();
46310 getCellIndex : function(cell){
46311 var id = String(cell.className).match(this.cellRE);
46313 return parseInt(id[1], 10);
46318 findHeaderIndex : function(n){
46319 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46320 return r ? this.getCellIndex(r) : false;
46323 findHeaderCell : function(n){
46324 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
46325 return r ? r : false;
46328 findRowIndex : function(n){
46332 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
46333 return r ? r.rowIndex : false;
46336 findCellIndex : function(node){
46337 var stop = this.el.dom;
46338 while(node && node != stop){
46339 if(this.findRE.test(node.className)){
46340 return this.getCellIndex(node);
46342 node = node.parentNode;
46347 getColumnId : function(index){
46348 return this.cm.getColumnId(index);
46351 getSplitters : function(){
46352 if(this.splitterSelector){
46353 return Roo.DomQuery.select(this.splitterSelector);
46359 getSplitter : function(index){
46360 return this.getSplitters()[index];
46363 onRowOver : function(e, t){
46365 if((row = this.findRowIndex(t)) !== false){
46366 this.getRowComposite(row).addClass("x-grid-row-over");
46370 onRowOut : function(e, t){
46372 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
46373 this.getRowComposite(row).removeClass("x-grid-row-over");
46377 renderHeaders : function(){
46379 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
46380 var cb = [], lb = [], sb = [], lsb = [], p = {};
46381 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46382 p.cellId = "x-grid-hd-0-" + i;
46383 p.splitId = "x-grid-csplit-0-" + i;
46384 p.id = cm.getColumnId(i);
46385 p.title = cm.getColumnTooltip(i) || "";
46386 p.value = cm.getColumnHeader(i) || "";
46387 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
46388 if(!cm.isLocked(i)){
46389 cb[cb.length] = ct.apply(p);
46390 sb[sb.length] = st.apply(p);
46392 lb[lb.length] = ct.apply(p);
46393 lsb[lsb.length] = st.apply(p);
46396 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
46397 ht.apply({cells: cb.join(""), splits:sb.join("")})];
46400 updateHeaders : function(){
46401 var html = this.renderHeaders();
46402 this.lockedHd.update(html[0]);
46403 this.mainHd.update(html[1]);
46407 * Focuses the specified row.
46408 * @param {Number} row The row index
46410 focusRow : function(row){
46411 var x = this.scroller.dom.scrollLeft;
46412 this.focusCell(row, 0, false);
46413 this.scroller.dom.scrollLeft = x;
46417 * Focuses the specified cell.
46418 * @param {Number} row The row index
46419 * @param {Number} col The column index
46420 * @param {Boolean} hscroll false to disable horizontal scrolling
46422 focusCell : function(row, col, hscroll){
46423 var el = this.ensureVisible(row, col, hscroll);
46424 this.focusEl.alignTo(el, "tl-tl");
46426 this.focusEl.focus();
46428 this.focusEl.focus.defer(1, this.focusEl);
46433 * Scrolls the specified cell into view
46434 * @param {Number} row The row index
46435 * @param {Number} col The column index
46436 * @param {Boolean} hscroll false to disable horizontal scrolling
46438 ensureVisible : function(row, col, hscroll){
46439 if(typeof row != "number"){
46440 row = row.rowIndex;
46442 if(row < 0 && row >= this.ds.getCount()){
46445 col = (col !== undefined ? col : 0);
46446 var cm = this.grid.colModel;
46447 while(cm.isHidden(col)){
46451 var el = this.getCell(row, col);
46455 var c = this.scroller.dom;
46457 var ctop = parseInt(el.offsetTop, 10);
46458 var cleft = parseInt(el.offsetLeft, 10);
46459 var cbot = ctop + el.offsetHeight;
46460 var cright = cleft + el.offsetWidth;
46462 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
46463 var stop = parseInt(c.scrollTop, 10);
46464 var sleft = parseInt(c.scrollLeft, 10);
46465 var sbot = stop + ch;
46466 var sright = sleft + c.clientWidth;
46469 c.scrollTop = ctop;
46470 }else if(cbot > sbot){
46471 c.scrollTop = cbot-ch;
46474 if(hscroll !== false){
46476 c.scrollLeft = cleft;
46477 }else if(cright > sright){
46478 c.scrollLeft = cright-c.clientWidth;
46484 updateColumns : function(){
46485 this.grid.stopEditing();
46486 var cm = this.grid.colModel, colIds = this.getColumnIds();
46487 //var totalWidth = cm.getTotalWidth();
46489 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46490 //if(cm.isHidden(i)) continue;
46491 var w = cm.getColumnWidth(i);
46492 this.css.updateRule(this.colSelector+colIds[i], "width", (w - this.borderWidth) + "px");
46493 this.css.updateRule(this.hdSelector+colIds[i], "width", (w - this.borderWidth) + "px");
46495 this.updateSplitters();
46498 generateRules : function(cm){
46499 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
46500 Roo.util.CSS.removeStyleSheet(rulesId);
46501 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46502 var cid = cm.getColumnId(i);
46504 if(cm.config[i].align){
46505 align = 'text-align:'+cm.config[i].align+';';
46508 if(cm.isHidden(i)){
46509 hidden = 'display:none;';
46511 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
46513 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
46514 this.hdSelector, cid, " {\n", align, width, "}\n",
46515 this.tdSelector, cid, " {\n",hidden,"\n}\n",
46516 this.splitSelector, cid, " {\n", hidden , "\n}\n");
46518 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
46521 updateSplitters : function(){
46522 var cm = this.cm, s = this.getSplitters();
46523 if(s){ // splitters not created yet
46524 var pos = 0, locked = true;
46525 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
46526 if(cm.isHidden(i)) continue;
46527 var w = cm.getColumnWidth(i);
46528 if(!cm.isLocked(i) && locked){
46533 s[i].style.left = (pos-this.splitOffset) + "px";
46538 handleHiddenChange : function(colModel, colIndex, hidden){
46540 this.hideColumn(colIndex);
46542 this.unhideColumn(colIndex);
46546 hideColumn : function(colIndex){
46547 var cid = this.getColumnId(colIndex);
46548 this.css.updateRule(this.tdSelector+cid, "display", "none");
46549 this.css.updateRule(this.splitSelector+cid, "display", "none");
46551 this.updateHeaders();
46553 this.updateSplitters();
46557 unhideColumn : function(colIndex){
46558 var cid = this.getColumnId(colIndex);
46559 this.css.updateRule(this.tdSelector+cid, "display", "");
46560 this.css.updateRule(this.splitSelector+cid, "display", "");
46563 this.updateHeaders();
46565 this.updateSplitters();
46569 insertRows : function(dm, firstRow, lastRow, isUpdate){
46570 if(firstRow == 0 && lastRow == dm.getCount()-1){
46574 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
46576 var s = this.getScrollState();
46577 var markup = this.renderRows(firstRow, lastRow);
46578 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
46579 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
46580 this.restoreScroll(s);
46582 this.fireEvent("rowsinserted", this, firstRow, lastRow);
46583 this.syncRowHeights(firstRow, lastRow);
46584 this.stripeRows(firstRow);
46590 bufferRows : function(markup, target, index){
46591 var before = null, trows = target.rows, tbody = target.tBodies[0];
46592 if(index < trows.length){
46593 before = trows[index];
46595 var b = document.createElement("div");
46596 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
46597 var rows = b.firstChild.rows;
46598 for(var i = 0, len = rows.length; i < len; i++){
46600 tbody.insertBefore(rows[0], before);
46602 tbody.appendChild(rows[0]);
46609 deleteRows : function(dm, firstRow, lastRow){
46610 if(dm.getRowCount()<1){
46611 this.fireEvent("beforerefresh", this);
46612 this.mainBody.update("");
46613 this.lockedBody.update("");
46614 this.fireEvent("refresh", this);
46616 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
46617 var bt = this.getBodyTable();
46618 var tbody = bt.firstChild;
46619 var rows = bt.rows;
46620 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
46621 tbody.removeChild(rows[firstRow]);
46623 this.stripeRows(firstRow);
46624 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
46628 updateRows : function(dataSource, firstRow, lastRow){
46629 var s = this.getScrollState();
46631 this.restoreScroll(s);
46634 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
46638 this.updateHeaderSortState();
46641 getScrollState : function(){
46642 var sb = this.scroller.dom;
46643 return {left: sb.scrollLeft, top: sb.scrollTop};
46646 stripeRows : function(startRow){
46647 if(!this.grid.stripeRows || this.ds.getCount() < 1){
46650 startRow = startRow || 0;
46651 var rows = this.getBodyTable().rows;
46652 var lrows = this.getLockedTable().rows;
46653 var cls = ' x-grid-row-alt ';
46654 for(var i = startRow, len = rows.length; i < len; i++){
46655 var row = rows[i], lrow = lrows[i];
46656 var isAlt = ((i+1) % 2 == 0);
46657 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
46658 if(isAlt == hasAlt){
46662 row.className += " x-grid-row-alt";
46664 row.className = row.className.replace("x-grid-row-alt", "");
46667 lrow.className = row.className;
46672 restoreScroll : function(state){
46673 var sb = this.scroller.dom;
46674 sb.scrollLeft = state.left;
46675 sb.scrollTop = state.top;
46679 syncScroll : function(){
46680 var sb = this.scroller.dom;
46681 var sh = this.mainHd.dom;
46682 var bs = this.mainBody.dom;
46683 var lv = this.lockedBody.dom;
46684 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
46685 lv.scrollTop = bs.scrollTop = sb.scrollTop;
46688 handleScroll : function(e){
46690 var sb = this.scroller.dom;
46691 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
46695 handleWheel : function(e){
46696 var d = e.getWheelDelta();
46697 this.scroller.dom.scrollTop -= d*22;
46698 // set this here to prevent jumpy scrolling on large tables
46699 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
46703 renderRows : function(startRow, endRow){
46704 // pull in all the crap needed to render rows
46705 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
46706 var colCount = cm.getColumnCount();
46708 if(ds.getCount() < 1){
46712 // build a map for all the columns
46714 for(var i = 0; i < colCount; i++){
46715 var name = cm.getDataIndex(i);
46717 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
46718 renderer : cm.getRenderer(i),
46719 id : cm.getColumnId(i),
46720 locked : cm.isLocked(i)
46724 startRow = startRow || 0;
46725 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
46727 // records to render
46728 var rs = ds.getRange(startRow, endRow);
46730 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
46733 // As much as I hate to duplicate code, this was branched because FireFox really hates
46734 // [].join("") on strings. The performance difference was substantial enough to
46735 // branch this function
46736 doRender : Roo.isGecko ?
46737 function(cs, rs, ds, startRow, colCount, stripe){
46738 var ts = this.templates, ct = ts.cell, rt = ts.row;
46740 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
46741 for(var j = 0, len = rs.length; j < len; j++){
46742 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
46743 for(var i = 0; i < colCount; i++){
46745 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
46747 p.css = p.attr = "";
46748 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
46749 if(p.value == undefined || p.value === "") p.value = " ";
46750 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
46751 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
46753 var markup = ct.apply(p);
46761 if(stripe && ((rowIndex+1) % 2 == 0)){
46762 alt[0] = "x-grid-row-alt";
46765 alt[1] = " x-grid-dirty-row";
46768 if(this.getRowClass){
46769 alt[2] = this.getRowClass(r, rowIndex);
46771 rp.alt = alt.join(" ");
46772 lbuf+= rt.apply(rp);
46774 buf+= rt.apply(rp);
46776 return [lbuf, buf];
46778 function(cs, rs, ds, startRow, colCount, stripe){
46779 var ts = this.templates, ct = ts.cell, rt = ts.row;
46781 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
46782 for(var j = 0, len = rs.length; j < len; j++){
46783 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
46784 for(var i = 0; i < colCount; i++){
46786 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
46788 p.css = p.attr = "";
46789 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
46790 if(p.value == undefined || p.value === "") p.value = " ";
46791 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
46792 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
46794 var markup = ct.apply(p);
46796 cb[cb.length] = markup;
46798 lcb[lcb.length] = markup;
46802 if(stripe && ((rowIndex+1) % 2 == 0)){
46803 alt[0] = "x-grid-row-alt";
46806 alt[1] = " x-grid-dirty-row";
46809 if(this.getRowClass){
46810 alt[2] = this.getRowClass(r, rowIndex);
46812 rp.alt = alt.join(" ");
46813 rp.cells = lcb.join("");
46814 lbuf[lbuf.length] = rt.apply(rp);
46815 rp.cells = cb.join("");
46816 buf[buf.length] = rt.apply(rp);
46818 return [lbuf.join(""), buf.join("")];
46821 renderBody : function(){
46822 var markup = this.renderRows();
46823 var bt = this.templates.body;
46824 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
46828 * Refreshes the grid
46829 * @param {Boolean} headersToo
46831 refresh : function(headersToo){
46832 this.fireEvent("beforerefresh", this);
46833 this.grid.stopEditing();
46834 var result = this.renderBody();
46835 this.lockedBody.update(result[0]);
46836 this.mainBody.update(result[1]);
46837 if(headersToo === true){
46838 this.updateHeaders();
46839 this.updateColumns();
46840 this.updateSplitters();
46841 this.updateHeaderSortState();
46843 this.syncRowHeights();
46845 this.fireEvent("refresh", this);
46848 handleColumnMove : function(cm, oldIndex, newIndex){
46849 this.indexMap = null;
46850 var s = this.getScrollState();
46851 this.refresh(true);
46852 this.restoreScroll(s);
46853 this.afterMove(newIndex);
46856 afterMove : function(colIndex){
46857 if(this.enableMoveAnim && Roo.enableFx){
46858 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
46862 updateCell : function(dm, rowIndex, dataIndex){
46863 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
46864 if(typeof colIndex == "undefined"){ // not present in grid
46867 var cm = this.grid.colModel;
46868 var cell = this.getCell(rowIndex, colIndex);
46869 var cellText = this.getCellText(rowIndex, colIndex);
46872 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
46873 id : cm.getColumnId(colIndex),
46874 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
46876 var renderer = cm.getRenderer(colIndex);
46877 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
46878 if(typeof val == "undefined" || val === "") val = " ";
46879 cellText.innerHTML = val;
46880 cell.className = this.cellClass + " " + p.cellId + " " + p.css;
46881 this.syncRowHeights(rowIndex, rowIndex);
46884 calcColumnWidth : function(colIndex, maxRowsToMeasure){
46886 if(this.grid.autoSizeHeaders){
46887 var h = this.getHeaderCellMeasure(colIndex);
46888 maxWidth = Math.max(maxWidth, h.scrollWidth);
46891 if(this.cm.isLocked(colIndex)){
46892 tb = this.getLockedTable();
46895 tb = this.getBodyTable();
46896 index = colIndex - this.cm.getLockedCount();
46899 var rows = tb.rows;
46900 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
46901 for(var i = 0; i < stopIndex; i++){
46902 var cell = rows[i].childNodes[index].firstChild;
46903 maxWidth = Math.max(maxWidth, cell.scrollWidth);
46906 return maxWidth + /*margin for error in IE*/ 5;
46909 * Autofit a column to its content.
46910 * @param {Number} colIndex
46911 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
46913 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
46914 if(this.cm.isHidden(colIndex)){
46915 return; // can't calc a hidden column
46918 var cid = this.cm.getColumnId(colIndex);
46919 this.css.updateRule(this.colSelector + cid, "width", this.grid.minColumnWidth + "px");
46920 if(this.grid.autoSizeHeaders){
46921 this.css.updateRule(this.hdSelector + cid, "width", this.grid.minColumnWidth + "px");
46924 var newWidth = this.calcColumnWidth(colIndex);
46925 this.cm.setColumnWidth(colIndex,
46926 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
46927 if(!suppressEvent){
46928 this.grid.fireEvent("columnresize", colIndex, newWidth);
46933 * Autofits all columns to their content and then expands to fit any extra space in the grid
46935 autoSizeColumns : function(){
46936 var cm = this.grid.colModel;
46937 var colCount = cm.getColumnCount();
46938 for(var i = 0; i < colCount; i++){
46939 this.autoSizeColumn(i, true, true);
46941 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
46944 this.updateColumns();
46950 * Autofits all columns to the grid's width proportionate with their current size
46951 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
46953 fitColumns : function(reserveScrollSpace){
46954 var cm = this.grid.colModel;
46955 var colCount = cm.getColumnCount();
46959 for (i = 0; i < colCount; i++){
46960 if(!cm.isHidden(i) && !cm.isFixed(i)){
46961 w = cm.getColumnWidth(i);
46967 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
46968 if(reserveScrollSpace){
46971 var frac = (avail - cm.getTotalWidth())/width;
46972 while (cols.length){
46975 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
46977 this.updateColumns();
46981 onRowSelect : function(rowIndex){
46982 var row = this.getRowComposite(rowIndex);
46983 row.addClass("x-grid-row-selected");
46986 onRowDeselect : function(rowIndex){
46987 var row = this.getRowComposite(rowIndex);
46988 row.removeClass("x-grid-row-selected");
46991 onCellSelect : function(row, col){
46992 var cell = this.getCell(row, col);
46994 Roo.fly(cell).addClass("x-grid-cell-selected");
46998 onCellDeselect : function(row, col){
46999 var cell = this.getCell(row, col);
47001 Roo.fly(cell).removeClass("x-grid-cell-selected");
47005 updateHeaderSortState : function(){
47006 var state = this.ds.getSortState();
47010 this.sortState = state;
47011 var sortColumn = this.cm.findColumnIndex(state.field);
47012 if(sortColumn != -1){
47013 var sortDir = state.direction;
47014 var sc = this.sortClasses;
47015 var hds = this.el.select(this.headerSelector).removeClass(sc);
47016 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
47020 handleHeaderClick : function(g, index){
47021 if(this.headersDisabled){
47024 var dm = g.dataSource, cm = g.colModel;
47025 if(!cm.isSortable(index)){
47029 dm.sort(cm.getDataIndex(index));
47033 destroy : function(){
47035 this.colMenu.removeAll();
47036 Roo.menu.MenuMgr.unregister(this.colMenu);
47037 this.colMenu.getEl().remove();
47038 delete this.colMenu;
47041 this.hmenu.removeAll();
47042 Roo.menu.MenuMgr.unregister(this.hmenu);
47043 this.hmenu.getEl().remove();
47046 if(this.grid.enableColumnMove){
47047 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47049 for(var dd in dds){
47050 if(!dds[dd].config.isTarget && dds[dd].dragElId){
47051 var elid = dds[dd].dragElId;
47053 Roo.get(elid).remove();
47054 } else if(dds[dd].config.isTarget){
47055 dds[dd].proxyTop.remove();
47056 dds[dd].proxyBottom.remove();
47059 if(Roo.dd.DDM.locationCache[dd]){
47060 delete Roo.dd.DDM.locationCache[dd];
47063 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
47066 Roo.util.CSS.removeStyleSheet(this.grid.id + '-cssrules');
47067 this.bind(null, null);
47068 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
47071 handleLockChange : function(){
47072 this.refresh(true);
47075 onDenyColumnLock : function(){
47079 onDenyColumnHide : function(){
47083 handleHdMenuClick : function(item){
47084 var index = this.hdCtxIndex;
47085 var cm = this.cm, ds = this.ds;
47088 ds.sort(cm.getDataIndex(index), "ASC");
47091 ds.sort(cm.getDataIndex(index), "DESC");
47094 var lc = cm.getLockedCount();
47095 if(cm.getColumnCount(true) <= lc+1){
47096 this.onDenyColumnLock();
47100 cm.setLocked(index, true, true);
47101 cm.moveColumn(index, lc);
47102 this.grid.fireEvent("columnmove", index, lc);
47104 cm.setLocked(index, true);
47108 var lc = cm.getLockedCount();
47109 if((lc-1) != index){
47110 cm.setLocked(index, false, true);
47111 cm.moveColumn(index, lc-1);
47112 this.grid.fireEvent("columnmove", index, lc-1);
47114 cm.setLocked(index, false);
47118 index = cm.getIndexById(item.id.substr(4));
47120 if(item.checked && cm.getColumnCount(true) <= 1){
47121 this.onDenyColumnHide();
47124 cm.setHidden(index, item.checked);
47130 beforeColMenuShow : function(){
47131 var cm = this.cm, colCount = cm.getColumnCount();
47132 this.colMenu.removeAll();
47133 for(var i = 0; i < colCount; i++){
47134 this.colMenu.add(new Roo.menu.CheckItem({
47135 id: "col-"+cm.getColumnId(i),
47136 text: cm.getColumnHeader(i),
47137 checked: !cm.isHidden(i),
47143 handleHdCtx : function(g, index, e){
47145 var hd = this.getHeaderCell(index);
47146 this.hdCtxIndex = index;
47147 var ms = this.hmenu.items, cm = this.cm;
47148 ms.get("asc").setDisabled(!cm.isSortable(index));
47149 ms.get("desc").setDisabled(!cm.isSortable(index));
47150 if(this.grid.enableColLock !== false){
47151 ms.get("lock").setDisabled(cm.isLocked(index));
47152 ms.get("unlock").setDisabled(!cm.isLocked(index));
47154 this.hmenu.show(hd, "tl-bl");
47157 handleHdOver : function(e){
47158 var hd = this.findHeaderCell(e.getTarget());
47159 if(hd && !this.headersDisabled){
47160 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
47161 this.fly(hd).addClass("x-grid-hd-over");
47166 handleHdOut : function(e){
47167 var hd = this.findHeaderCell(e.getTarget());
47169 this.fly(hd).removeClass("x-grid-hd-over");
47173 handleSplitDblClick : function(e, t){
47174 var i = this.getCellIndex(t);
47175 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
47176 this.autoSizeColumn(i, true);
47181 render : function(){
47184 var colCount = cm.getColumnCount();
47186 if(this.grid.monitorWindowResize === true){
47187 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
47189 var header = this.renderHeaders();
47190 var body = this.templates.body.apply({rows:""});
47191 var html = this.templates.master.apply({
47194 lockedHeader: header[0],
47198 //this.updateColumns();
47200 this.grid.getGridEl().dom.innerHTML = html;
47202 this.initElements();
47204 this.scroller.on("scroll", this.handleScroll, this);
47205 this.lockedBody.on("mousewheel", this.handleWheel, this);
47206 this.mainBody.on("mousewheel", this.handleWheel, this);
47208 this.mainHd.on("mouseover", this.handleHdOver, this);
47209 this.mainHd.on("mouseout", this.handleHdOut, this);
47210 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
47211 {delegate: "."+this.splitClass});
47213 this.lockedHd.on("mouseover", this.handleHdOver, this);
47214 this.lockedHd.on("mouseout", this.handleHdOut, this);
47215 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
47216 {delegate: "."+this.splitClass});
47218 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
47219 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47222 this.updateSplitters();
47224 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
47225 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47226 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
47229 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
47230 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
47232 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
47233 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
47235 if(this.grid.enableColLock !== false){
47236 this.hmenu.add('-',
47237 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
47238 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
47241 if(this.grid.enableColumnHide !== false){
47243 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
47244 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
47245 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
47247 this.hmenu.add('-',
47248 {id:"columns", text: this.columnsText, menu: this.colMenu}
47251 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
47253 this.grid.on("headercontextmenu", this.handleHdCtx, this);
47256 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
47257 this.dd = new Roo.grid.GridDragZone(this.grid, {
47258 ddGroup : this.grid.ddGroup || 'GridDD'
47263 for(var i = 0; i < colCount; i++){
47264 if(cm.isHidden(i)){
47265 this.hideColumn(i);
47267 if(cm.config[i].align){
47268 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
47269 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
47273 this.updateHeaderSortState();
47275 this.beforeInitialResize();
47278 // two part rendering gives faster view to the user
47279 this.renderPhase2.defer(1, this);
47282 renderPhase2 : function(){
47283 // render the rows now
47285 if(this.grid.autoSizeColumns){
47286 this.autoSizeColumns();
47290 beforeInitialResize : function(){
47294 onColumnSplitterMoved : function(i, w){
47295 this.userResized = true;
47296 var cm = this.grid.colModel;
47297 cm.setColumnWidth(i, w, true);
47298 var cid = cm.getColumnId(i);
47299 this.css.updateRule(this.colSelector + cid, "width", (w-this.borderWidth) + "px");
47300 this.css.updateRule(this.hdSelector + cid, "width", (w-this.borderWidth) + "px");
47301 this.updateSplitters();
47303 this.grid.fireEvent("columnresize", i, w);
47306 syncRowHeights : function(startIndex, endIndex){
47307 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
47308 startIndex = startIndex || 0;
47309 var mrows = this.getBodyTable().rows;
47310 var lrows = this.getLockedTable().rows;
47311 var len = mrows.length-1;
47312 endIndex = Math.min(endIndex || len, len);
47313 for(var i = startIndex; i <= endIndex; i++){
47314 var m = mrows[i], l = lrows[i];
47315 var h = Math.max(m.offsetHeight, l.offsetHeight);
47316 m.style.height = l.style.height = h + "px";
47321 layout : function(initialRender, is2ndPass){
47323 var auto = g.autoHeight;
47324 var scrollOffset = 16;
47325 var c = g.getGridEl(), cm = this.cm,
47326 expandCol = g.autoExpandColumn,
47328 //c.beginMeasure();
47330 if(!c.dom.offsetWidth){ // display:none?
47332 this.lockedWrap.show();
47333 this.mainWrap.show();
47338 var hasLock = this.cm.isLocked(0);
47340 var tbh = this.headerPanel.getHeight();
47341 var bbh = this.footerPanel.getHeight();
47344 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
47345 var newHeight = ch + c.getBorderWidth("tb");
47347 newHeight = Math.min(g.maxHeight, newHeight);
47349 c.setHeight(newHeight);
47353 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
47356 var s = this.scroller;
47358 var csize = c.getSize(true);
47360 this.el.setSize(csize.width, csize.height);
47362 this.headerPanel.setWidth(csize.width);
47363 this.footerPanel.setWidth(csize.width);
47365 var hdHeight = this.mainHd.getHeight();
47366 var vw = csize.width;
47367 var vh = csize.height - (tbh + bbh);
47371 var bt = this.getBodyTable();
47372 var ltWidth = hasLock ?
47373 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
47375 var scrollHeight = bt.offsetHeight;
47376 var scrollWidth = ltWidth + bt.offsetWidth;
47377 var vscroll = false, hscroll = false;
47379 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
47381 var lw = this.lockedWrap, mw = this.mainWrap;
47382 var lb = this.lockedBody, mb = this.mainBody;
47384 setTimeout(function(){
47385 var t = s.dom.offsetTop;
47386 var w = s.dom.clientWidth,
47387 h = s.dom.clientHeight;
47390 lw.setSize(ltWidth, h);
47392 mw.setLeftTop(ltWidth, t);
47393 mw.setSize(w-ltWidth, h);
47395 lb.setHeight(h-hdHeight);
47396 mb.setHeight(h-hdHeight);
47398 if(is2ndPass !== true && !gv.userResized && expandCol){
47399 // high speed resize without full column calculation
47401 var ci = cm.getIndexById(expandCol);
47403 ci = cm.findColumnIndex(expandCol);
47405 ci = Math.max(0, ci); // make sure it's got at least the first col.
47406 var expandId = cm.getColumnId(ci);
47407 var tw = cm.getTotalWidth(false);
47408 var currentWidth = cm.getColumnWidth(ci);
47409 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
47410 if(currentWidth != cw){
47411 cm.setColumnWidth(ci, cw, true);
47412 gv.css.updateRule(gv.colSelector+expandId, "width", (cw - gv.borderWidth) + "px");
47413 gv.css.updateRule(gv.hdSelector+expandId, "width", (cw - gv.borderWidth) + "px");
47414 gv.updateSplitters();
47415 gv.layout(false, true);
47427 onWindowResize : function(){
47428 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
47434 appendFooter : function(parentEl){
47438 sortAscText : "Sort Ascending",
47439 sortDescText : "Sort Descending",
47440 lockText : "Lock Column",
47441 unlockText : "Unlock Column",
47442 columnsText : "Columns"
47446 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
47447 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
47448 this.proxy.el.addClass('x-grid3-col-dd');
47451 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
47452 handleMouseDown : function(e){
47456 callHandleMouseDown : function(e){
47457 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
47462 * Ext JS Library 1.1.1
47463 * Copyright(c) 2006-2007, Ext JS, LLC.
47465 * Originally Released Under LGPL - original licence link has changed is not relivant.
47468 * <script type="text/javascript">
47472 // This is a support class used internally by the Grid components
47473 Roo.grid.SplitDragZone = function(grid, hd, hd2){
47475 this.view = grid.getView();
47476 this.proxy = this.view.resizeProxy;
47477 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
47478 "gridSplitters" + this.grid.getGridEl().id, {
47479 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
47481 this.setHandleElId(Roo.id(hd));
47482 this.setOuterHandleElId(Roo.id(hd2));
47483 this.scroll = false;
47485 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
47486 fly: Roo.Element.fly,
47488 b4StartDrag : function(x, y){
47489 this.view.headersDisabled = true;
47490 this.proxy.setHeight(this.view.mainWrap.getHeight());
47491 var w = this.cm.getColumnWidth(this.cellIndex);
47492 var minw = Math.max(w-this.grid.minColumnWidth, 0);
47493 this.resetConstraints();
47494 this.setXConstraint(minw, 1000);
47495 this.setYConstraint(0, 0);
47496 this.minX = x - minw;
47497 this.maxX = x + 1000;
47499 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
47503 handleMouseDown : function(e){
47504 ev = Roo.EventObject.setEvent(e);
47505 var t = this.fly(ev.getTarget());
47506 if(t.hasClass("x-grid-split")){
47507 this.cellIndex = this.view.getCellIndex(t.dom);
47508 this.split = t.dom;
47509 this.cm = this.grid.colModel;
47510 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
47511 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
47516 endDrag : function(e){
47517 this.view.headersDisabled = false;
47518 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
47519 var diff = endX - this.startPos;
47520 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
47523 autoOffset : function(){
47524 this.setDelta(0,0);
47528 * Ext JS Library 1.1.1
47529 * Copyright(c) 2006-2007, Ext JS, LLC.
47531 * Originally Released Under LGPL - original licence link has changed is not relivant.
47534 * <script type="text/javascript">
47538 // This is a support class used internally by the Grid components
47539 Roo.grid.GridDragZone = function(grid, config){
47540 this.view = grid.getView();
47541 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
47542 if(this.view.lockedBody){
47543 this.setHandleElId(Roo.id(this.view.mainBody.dom));
47544 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
47546 this.scroll = false;
47548 this.ddel = document.createElement('div');
47549 this.ddel.className = 'x-grid-dd-wrap';
47552 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
47553 ddGroup : "GridDD",
47555 getDragData : function(e){
47556 var t = Roo.lib.Event.getTarget(e);
47557 var rowIndex = this.view.findRowIndex(t);
47558 if(rowIndex !== false){
47559 var sm = this.grid.selModel;
47560 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
47561 // sm.mouseDown(e, t);
47563 if (e.hasModifier()){
47564 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
47566 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
47571 onInitDrag : function(e){
47572 var data = this.dragData;
47573 this.ddel.innerHTML = this.grid.getDragDropText();
47574 this.proxy.update(this.ddel);
47575 // fire start drag?
47578 afterRepair : function(){
47579 this.dragging = false;
47582 getRepairXY : function(e, data){
47586 onEndDrag : function(data, e){
47590 onValidDrop : function(dd, e, id){
47595 beforeInvalidDrop : function(e, id){
47600 * Ext JS Library 1.1.1
47601 * Copyright(c) 2006-2007, Ext JS, LLC.
47603 * Originally Released Under LGPL - original licence link has changed is not relivant.
47606 * <script type="text/javascript">
47611 * @class Roo.grid.ColumnModel
47612 * @extends Roo.util.Observable
47613 * This is the default implementation of a ColumnModel used by the Grid. It defines
47614 * the columns in the grid.
47617 var colModel = new Roo.grid.ColumnModel([
47618 {header: "Ticker", width: 60, sortable: true, locked: true},
47619 {header: "Company Name", width: 150, sortable: true},
47620 {header: "Market Cap.", width: 100, sortable: true},
47621 {header: "$ Sales", width: 100, sortable: true, renderer: money},
47622 {header: "Employees", width: 100, sortable: true, resizable: false}
47627 * The config options listed for this class are options which may appear in each
47628 * individual column definition.
47629 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
47631 * @param {Object} config An Array of column config objects. See this class's
47632 * config objects for details.
47634 Roo.grid.ColumnModel = function(config){
47636 * The config passed into the constructor
47638 this.config = config;
47641 // if no id, create one
47642 // if the column does not have a dataIndex mapping,
47643 // map it to the order it is in the config
47644 for(var i = 0, len = config.length; i < len; i++){
47646 if(typeof c.dataIndex == "undefined"){
47649 if(typeof c.renderer == "string"){
47650 c.renderer = Roo.util.Format[c.renderer];
47652 if(typeof c.id == "undefined"){
47655 if(c.editor && c.editor.xtype){
47656 c.editor = Roo.factory(c.editor, Roo.grid);
47658 if(c.editor && c.editor.isFormField){
47659 c.editor = new Roo.grid.GridEditor(c.editor);
47661 this.lookup[c.id] = c;
47665 * The width of columns which have no width specified (defaults to 100)
47668 this.defaultWidth = 100;
47671 * Default sortable of columns which have no sortable specified (defaults to false)
47674 this.defaultSortable = false;
47678 * @event widthchange
47679 * Fires when the width of a column changes.
47680 * @param {ColumnModel} this
47681 * @param {Number} columnIndex The column index
47682 * @param {Number} newWidth The new width
47684 "widthchange": true,
47686 * @event headerchange
47687 * Fires when the text of a header changes.
47688 * @param {ColumnModel} this
47689 * @param {Number} columnIndex The column index
47690 * @param {Number} newText The new header text
47692 "headerchange": true,
47694 * @event hiddenchange
47695 * Fires when a column is hidden or "unhidden".
47696 * @param {ColumnModel} this
47697 * @param {Number} columnIndex The column index
47698 * @param {Boolean} hidden true if hidden, false otherwise
47700 "hiddenchange": true,
47702 * @event columnmoved
47703 * Fires when a column is moved.
47704 * @param {ColumnModel} this
47705 * @param {Number} oldIndex
47706 * @param {Number} newIndex
47708 "columnmoved" : true,
47710 * @event columlockchange
47711 * Fires when a column's locked state is changed
47712 * @param {ColumnModel} this
47713 * @param {Number} colIndex
47714 * @param {Boolean} locked true if locked
47716 "columnlockchange" : true
47718 Roo.grid.ColumnModel.superclass.constructor.call(this);
47720 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
47722 * @cfg {String} header The header text to display in the Grid view.
47725 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
47726 * {@link Roo.data.Record} definition from which to draw the column's value. If not
47727 * specified, the column's index is used as an index into the Record's data Array.
47730 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
47731 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
47734 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
47735 * Defaults to the value of the {@link #defaultSortable} property.
47736 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
47739 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
47742 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
47745 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
47748 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
47751 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
47752 * given the cell's data value. See {@link #setRenderer}. If not specified, the
47753 * default renderer uses the raw data value.
47756 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
47759 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
47763 * Returns the id of the column at the specified index.
47764 * @param {Number} index The column index
47765 * @return {String} the id
47767 getColumnId : function(index){
47768 return this.config[index].id;
47772 * Returns the column for a specified id.
47773 * @param {String} id The column id
47774 * @return {Object} the column
47776 getColumnById : function(id){
47777 return this.lookup[id];
47781 * Returns the index for a specified column id.
47782 * @param {String} id The column id
47783 * @return {Number} the index, or -1 if not found
47785 getIndexById : function(id){
47786 for(var i = 0, len = this.config.length; i < len; i++){
47787 if(this.config[i].id == id){
47794 * Returns the index for a specified column dataIndex.
47795 * @param {String} dataIndex The column dataIndex
47796 * @return {Number} the index, or -1 if not found
47799 findColumnIndex : function(dataIndex){
47800 for(var i = 0, len = this.config.length; i < len; i++){
47801 if(this.config[i].dataIndex == dataIndex){
47809 moveColumn : function(oldIndex, newIndex){
47810 var c = this.config[oldIndex];
47811 this.config.splice(oldIndex, 1);
47812 this.config.splice(newIndex, 0, c);
47813 this.dataMap = null;
47814 this.fireEvent("columnmoved", this, oldIndex, newIndex);
47817 isLocked : function(colIndex){
47818 return this.config[colIndex].locked === true;
47821 setLocked : function(colIndex, value, suppressEvent){
47822 if(this.isLocked(colIndex) == value){
47825 this.config[colIndex].locked = value;
47826 if(!suppressEvent){
47827 this.fireEvent("columnlockchange", this, colIndex, value);
47831 getTotalLockedWidth : function(){
47832 var totalWidth = 0;
47833 for(var i = 0; i < this.config.length; i++){
47834 if(this.isLocked(i) && !this.isHidden(i)){
47835 this.totalWidth += this.getColumnWidth(i);
47841 getLockedCount : function(){
47842 for(var i = 0, len = this.config.length; i < len; i++){
47843 if(!this.isLocked(i)){
47850 * Returns the number of columns.
47853 getColumnCount : function(visibleOnly){
47854 if(visibleOnly === true){
47856 for(var i = 0, len = this.config.length; i < len; i++){
47857 if(!this.isHidden(i)){
47863 return this.config.length;
47867 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
47868 * @param {Function} fn
47869 * @param {Object} scope (optional)
47870 * @return {Array} result
47872 getColumnsBy : function(fn, scope){
47874 for(var i = 0, len = this.config.length; i < len; i++){
47875 var c = this.config[i];
47876 if(fn.call(scope||this, c, i) === true){
47884 * Returns true if the specified column is sortable.
47885 * @param {Number} col The column index
47886 * @return {Boolean}
47888 isSortable : function(col){
47889 if(typeof this.config[col].sortable == "undefined"){
47890 return this.defaultSortable;
47892 return this.config[col].sortable;
47896 * Returns the rendering (formatting) function defined for the column.
47897 * @param {Number} col The column index.
47898 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
47900 getRenderer : function(col){
47901 if(!this.config[col].renderer){
47902 return Roo.grid.ColumnModel.defaultRenderer;
47904 return this.config[col].renderer;
47908 * Sets the rendering (formatting) function for a column.
47909 * @param {Number} col The column index
47910 * @param {Function} fn The function to use to process the cell's raw data
47911 * to return HTML markup for the grid view. The render function is called with
47912 * the following parameters:<ul>
47913 * <li>Data value.</li>
47914 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
47915 * <li>css A CSS style string to apply to the table cell.</li>
47916 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
47917 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
47918 * <li>Row index</li>
47919 * <li>Column index</li>
47920 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
47922 setRenderer : function(col, fn){
47923 this.config[col].renderer = fn;
47927 * Returns the width for the specified column.
47928 * @param {Number} col The column index
47931 getColumnWidth : function(col){
47932 return this.config[col].width || this.defaultWidth;
47936 * Sets the width for a column.
47937 * @param {Number} col The column index
47938 * @param {Number} width The new width
47940 setColumnWidth : function(col, width, suppressEvent){
47941 this.config[col].width = width;
47942 this.totalWidth = null;
47943 if(!suppressEvent){
47944 this.fireEvent("widthchange", this, col, width);
47949 * Returns the total width of all columns.
47950 * @param {Boolean} includeHidden True to include hidden column widths
47953 getTotalWidth : function(includeHidden){
47954 if(!this.totalWidth){
47955 this.totalWidth = 0;
47956 for(var i = 0, len = this.config.length; i < len; i++){
47957 if(includeHidden || !this.isHidden(i)){
47958 this.totalWidth += this.getColumnWidth(i);
47962 return this.totalWidth;
47966 * Returns the header for the specified column.
47967 * @param {Number} col The column index
47970 getColumnHeader : function(col){
47971 return this.config[col].header;
47975 * Sets the header for a column.
47976 * @param {Number} col The column index
47977 * @param {String} header The new header
47979 setColumnHeader : function(col, header){
47980 this.config[col].header = header;
47981 this.fireEvent("headerchange", this, col, header);
47985 * Returns the tooltip for the specified column.
47986 * @param {Number} col The column index
47989 getColumnTooltip : function(col){
47990 return this.config[col].tooltip;
47993 * Sets the tooltip for a column.
47994 * @param {Number} col The column index
47995 * @param {String} tooltip The new tooltip
47997 setColumnTooltip : function(col, tooltip){
47998 this.config[col].tooltip = tooltip;
48002 * Returns the dataIndex for the specified column.
48003 * @param {Number} col The column index
48006 getDataIndex : function(col){
48007 return this.config[col].dataIndex;
48011 * Sets the dataIndex for a column.
48012 * @param {Number} col The column index
48013 * @param {Number} dataIndex The new dataIndex
48015 setDataIndex : function(col, dataIndex){
48016 this.config[col].dataIndex = dataIndex;
48022 * Returns true if the cell is editable.
48023 * @param {Number} colIndex The column index
48024 * @param {Number} rowIndex The row index
48025 * @return {Boolean}
48027 isCellEditable : function(colIndex, rowIndex){
48028 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
48032 * Returns the editor defined for the cell/column.
48033 * return false or null to disable editing.
48034 * @param {Number} colIndex The column index
48035 * @param {Number} rowIndex The row index
48038 getCellEditor : function(colIndex, rowIndex){
48039 return this.config[colIndex].editor;
48043 * Sets if a column is editable.
48044 * @param {Number} col The column index
48045 * @param {Boolean} editable True if the column is editable
48047 setEditable : function(col, editable){
48048 this.config[col].editable = editable;
48053 * Returns true if the column is hidden.
48054 * @param {Number} colIndex The column index
48055 * @return {Boolean}
48057 isHidden : function(colIndex){
48058 return this.config[colIndex].hidden;
48063 * Returns true if the column width cannot be changed
48065 isFixed : function(colIndex){
48066 return this.config[colIndex].fixed;
48070 * Returns true if the column can be resized
48071 * @return {Boolean}
48073 isResizable : function(colIndex){
48074 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
48077 * Sets if a column is hidden.
48078 * @param {Number} colIndex The column index
48079 * @param {Boolean} hidden True if the column is hidden
48081 setHidden : function(colIndex, hidden){
48082 this.config[colIndex].hidden = hidden;
48083 this.totalWidth = null;
48084 this.fireEvent("hiddenchange", this, colIndex, hidden);
48088 * Sets the editor for a column.
48089 * @param {Number} col The column index
48090 * @param {Object} editor The editor object
48092 setEditor : function(col, editor){
48093 this.config[col].editor = editor;
48097 Roo.grid.ColumnModel.defaultRenderer = function(value){
48098 if(typeof value == "string" && value.length < 1){
48104 // Alias for backwards compatibility
48105 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
48108 * Ext JS Library 1.1.1
48109 * Copyright(c) 2006-2007, Ext JS, LLC.
48111 * Originally Released Under LGPL - original licence link has changed is not relivant.
48114 * <script type="text/javascript">
48118 * @class Roo.grid.AbstractSelectionModel
48119 * @extends Roo.util.Observable
48120 * Abstract base class for grid SelectionModels. It provides the interface that should be
48121 * implemented by descendant classes. This class should not be directly instantiated.
48124 Roo.grid.AbstractSelectionModel = function(){
48125 this.locked = false;
48126 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
48129 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
48130 /** @ignore Called by the grid automatically. Do not call directly. */
48131 init : function(grid){
48137 * Locks the selections.
48140 this.locked = true;
48144 * Unlocks the selections.
48146 unlock : function(){
48147 this.locked = false;
48151 * Returns true if the selections are locked.
48152 * @return {Boolean}
48154 isLocked : function(){
48155 return this.locked;
48159 * Ext JS Library 1.1.1
48160 * Copyright(c) 2006-2007, Ext JS, LLC.
48162 * Originally Released Under LGPL - original licence link has changed is not relivant.
48165 * <script type="text/javascript">
48168 * @extends Roo.grid.AbstractSelectionModel
48169 * @class Roo.grid.RowSelectionModel
48170 * The default SelectionModel used by {@link Roo.grid.Grid}.
48171 * It supports multiple selections and keyboard selection/navigation.
48173 * @param {Object} config
48175 Roo.grid.RowSelectionModel = function(config){
48176 Roo.apply(this, config);
48177 this.selections = new Roo.util.MixedCollection(false, function(o){
48182 this.lastActive = false;
48186 * @event selectionchange
48187 * Fires when the selection changes
48188 * @param {SelectionModel} this
48190 "selectionchange" : true,
48192 * @event afterselectionchange
48193 * Fires after the selection changes (eg. by key press or clicking)
48194 * @param {SelectionModel} this
48196 "afterselectionchange" : true,
48198 * @event beforerowselect
48199 * Fires when a row is selected being selected, return false to cancel.
48200 * @param {SelectionModel} this
48201 * @param {Number} rowIndex The selected index
48202 * @param {Boolean} keepExisting False if other selections will be cleared
48204 "beforerowselect" : true,
48207 * Fires when a row is selected.
48208 * @param {SelectionModel} this
48209 * @param {Number} rowIndex The selected index
48210 * @param {Roo.data.Record} r The record
48212 "rowselect" : true,
48214 * @event rowdeselect
48215 * Fires when a row is deselected.
48216 * @param {SelectionModel} this
48217 * @param {Number} rowIndex The selected index
48219 "rowdeselect" : true
48221 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
48222 this.locked = false;
48225 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
48227 * @cfg {Boolean} singleSelect
48228 * True to allow selection of only one row at a time (defaults to false)
48230 singleSelect : false,
48233 initEvents : function(){
48235 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
48236 this.grid.on("mousedown", this.handleMouseDown, this);
48237 }else{ // allow click to work like normal
48238 this.grid.on("rowclick", this.handleDragableRowClick, this);
48241 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
48242 "up" : function(e){
48244 this.selectPrevious(e.shiftKey);
48245 }else if(this.last !== false && this.lastActive !== false){
48246 var last = this.last;
48247 this.selectRange(this.last, this.lastActive-1);
48248 this.grid.getView().focusRow(this.lastActive);
48249 if(last !== false){
48253 this.selectFirstRow();
48255 this.fireEvent("afterselectionchange", this);
48257 "down" : function(e){
48259 this.selectNext(e.shiftKey);
48260 }else if(this.last !== false && this.lastActive !== false){
48261 var last = this.last;
48262 this.selectRange(this.last, this.lastActive+1);
48263 this.grid.getView().focusRow(this.lastActive);
48264 if(last !== false){
48268 this.selectFirstRow();
48270 this.fireEvent("afterselectionchange", this);
48275 var view = this.grid.view;
48276 view.on("refresh", this.onRefresh, this);
48277 view.on("rowupdated", this.onRowUpdated, this);
48278 view.on("rowremoved", this.onRemove, this);
48282 onRefresh : function(){
48283 var ds = this.grid.dataSource, i, v = this.grid.view;
48284 var s = this.selections;
48285 s.each(function(r){
48286 if((i = ds.indexOfId(r.id)) != -1){
48295 onRemove : function(v, index, r){
48296 this.selections.remove(r);
48300 onRowUpdated : function(v, index, r){
48301 if(this.isSelected(r)){
48302 v.onRowSelect(index);
48308 * @param {Array} records The records to select
48309 * @param {Boolean} keepExisting (optional) True to keep existing selections
48311 selectRecords : function(records, keepExisting){
48313 this.clearSelections();
48315 var ds = this.grid.dataSource;
48316 for(var i = 0, len = records.length; i < len; i++){
48317 this.selectRow(ds.indexOf(records[i]), true);
48322 * Gets the number of selected rows.
48325 getCount : function(){
48326 return this.selections.length;
48330 * Selects the first row in the grid.
48332 selectFirstRow : function(){
48337 * Select the last row.
48338 * @param {Boolean} keepExisting (optional) True to keep existing selections
48340 selectLastRow : function(keepExisting){
48341 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
48345 * Selects the row immediately following the last selected row.
48346 * @param {Boolean} keepExisting (optional) True to keep existing selections
48348 selectNext : function(keepExisting){
48349 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
48350 this.selectRow(this.last+1, keepExisting);
48351 this.grid.getView().focusRow(this.last);
48356 * Selects the row that precedes the last selected row.
48357 * @param {Boolean} keepExisting (optional) True to keep existing selections
48359 selectPrevious : function(keepExisting){
48361 this.selectRow(this.last-1, keepExisting);
48362 this.grid.getView().focusRow(this.last);
48367 * Returns the selected records
48368 * @return {Array} Array of selected records
48370 getSelections : function(){
48371 return [].concat(this.selections.items);
48375 * Returns the first selected record.
48378 getSelected : function(){
48379 return this.selections.itemAt(0);
48384 * Clears all selections.
48386 clearSelections : function(fast){
48387 if(this.locked) return;
48389 var ds = this.grid.dataSource;
48390 var s = this.selections;
48391 s.each(function(r){
48392 this.deselectRow(ds.indexOfId(r.id));
48396 this.selections.clear();
48403 * Selects all rows.
48405 selectAll : function(){
48406 if(this.locked) return;
48407 this.selections.clear();
48408 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
48409 this.selectRow(i, true);
48414 * Returns True if there is a selection.
48415 * @return {Boolean}
48417 hasSelection : function(){
48418 return this.selections.length > 0;
48422 * Returns True if the specified row is selected.
48423 * @param {Number/Record} record The record or index of the record to check
48424 * @return {Boolean}
48426 isSelected : function(index){
48427 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
48428 return (r && this.selections.key(r.id) ? true : false);
48432 * Returns True if the specified record id is selected.
48433 * @param {String} id The id of record to check
48434 * @return {Boolean}
48436 isIdSelected : function(id){
48437 return (this.selections.key(id) ? true : false);
48441 handleMouseDown : function(e, t){
48442 var view = this.grid.getView(), rowIndex;
48443 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
48446 if(e.shiftKey && this.last !== false){
48447 var last = this.last;
48448 this.selectRange(last, rowIndex, e.ctrlKey);
48449 this.last = last; // reset the last
48450 view.focusRow(rowIndex);
48452 var isSelected = this.isSelected(rowIndex);
48453 if(e.button !== 0 && isSelected){
48454 view.focusRow(rowIndex);
48455 }else if(e.ctrlKey && isSelected){
48456 this.deselectRow(rowIndex);
48457 }else if(!isSelected){
48458 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
48459 view.focusRow(rowIndex);
48462 this.fireEvent("afterselectionchange", this);
48465 handleDragableRowClick : function(grid, rowIndex, e)
48467 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
48468 this.selectRow(rowIndex, false);
48469 grid.view.focusRow(rowIndex);
48470 this.fireEvent("afterselectionchange", this);
48475 * Selects multiple rows.
48476 * @param {Array} rows Array of the indexes of the row to select
48477 * @param {Boolean} keepExisting (optional) True to keep existing selections
48479 selectRows : function(rows, keepExisting){
48481 this.clearSelections();
48483 for(var i = 0, len = rows.length; i < len; i++){
48484 this.selectRow(rows[i], true);
48489 * Selects a range of rows. All rows in between startRow and endRow are also selected.
48490 * @param {Number} startRow The index of the first row in the range
48491 * @param {Number} endRow The index of the last row in the range
48492 * @param {Boolean} keepExisting (optional) True to retain existing selections
48494 selectRange : function(startRow, endRow, keepExisting){
48495 if(this.locked) return;
48497 this.clearSelections();
48499 if(startRow <= endRow){
48500 for(var i = startRow; i <= endRow; i++){
48501 this.selectRow(i, true);
48504 for(var i = startRow; i >= endRow; i--){
48505 this.selectRow(i, true);
48511 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
48512 * @param {Number} startRow The index of the first row in the range
48513 * @param {Number} endRow The index of the last row in the range
48515 deselectRange : function(startRow, endRow, preventViewNotify){
48516 if(this.locked) return;
48517 for(var i = startRow; i <= endRow; i++){
48518 this.deselectRow(i, preventViewNotify);
48524 * @param {Number} row The index of the row to select
48525 * @param {Boolean} keepExisting (optional) True to keep existing selections
48527 selectRow : function(index, keepExisting, preventViewNotify){
48528 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
48529 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
48530 if(!keepExisting || this.singleSelect){
48531 this.clearSelections();
48533 var r = this.grid.dataSource.getAt(index);
48534 this.selections.add(r);
48535 this.last = this.lastActive = index;
48536 if(!preventViewNotify){
48537 this.grid.getView().onRowSelect(index);
48539 this.fireEvent("rowselect", this, index, r);
48540 this.fireEvent("selectionchange", this);
48546 * @param {Number} row The index of the row to deselect
48548 deselectRow : function(index, preventViewNotify){
48549 if(this.locked) return;
48550 if(this.last == index){
48553 if(this.lastActive == index){
48554 this.lastActive = false;
48556 var r = this.grid.dataSource.getAt(index);
48557 this.selections.remove(r);
48558 if(!preventViewNotify){
48559 this.grid.getView().onRowDeselect(index);
48561 this.fireEvent("rowdeselect", this, index);
48562 this.fireEvent("selectionchange", this);
48566 restoreLast : function(){
48568 this.last = this._last;
48573 acceptsNav : function(row, col, cm){
48574 return !cm.isHidden(col) && cm.isCellEditable(col, row);
48578 onEditorKey : function(field, e){
48579 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
48584 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
48586 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
48588 }else if(k == e.ENTER && !e.ctrlKey){
48592 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
48594 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
48596 }else if(k == e.ESC){
48600 g.startEditing(newCell[0], newCell[1]);
48605 * Ext JS Library 1.1.1
48606 * Copyright(c) 2006-2007, Ext JS, LLC.
48608 * Originally Released Under LGPL - original licence link has changed is not relivant.
48611 * <script type="text/javascript">
48614 * @class Roo.grid.CellSelectionModel
48615 * @extends Roo.grid.AbstractSelectionModel
48616 * This class provides the basic implementation for cell selection in a grid.
48618 * @param {Object} config The object containing the configuration of this model.
48620 Roo.grid.CellSelectionModel = function(config){
48621 Roo.apply(this, config);
48623 this.selection = null;
48627 * @event beforerowselect
48628 * Fires before a cell is selected.
48629 * @param {SelectionModel} this
48630 * @param {Number} rowIndex The selected row index
48631 * @param {Number} colIndex The selected cell index
48633 "beforecellselect" : true,
48635 * @event cellselect
48636 * Fires when a cell is selected.
48637 * @param {SelectionModel} this
48638 * @param {Number} rowIndex The selected row index
48639 * @param {Number} colIndex The selected cell index
48641 "cellselect" : true,
48643 * @event selectionchange
48644 * Fires when the active selection changes.
48645 * @param {SelectionModel} this
48646 * @param {Object} selection null for no selection or an object (o) with two properties
48648 <li>o.record: the record object for the row the selection is in</li>
48649 <li>o.cell: An array of [rowIndex, columnIndex]</li>
48652 "selectionchange" : true
48654 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
48657 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
48660 initEvents : function(){
48661 this.grid.on("mousedown", this.handleMouseDown, this);
48662 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
48663 var view = this.grid.view;
48664 view.on("refresh", this.onViewChange, this);
48665 view.on("rowupdated", this.onRowUpdated, this);
48666 view.on("beforerowremoved", this.clearSelections, this);
48667 view.on("beforerowsinserted", this.clearSelections, this);
48668 if(this.grid.isEditor){
48669 this.grid.on("beforeedit", this.beforeEdit, this);
48674 beforeEdit : function(e){
48675 this.select(e.row, e.column, false, true, e.record);
48679 onRowUpdated : function(v, index, r){
48680 if(this.selection && this.selection.record == r){
48681 v.onCellSelect(index, this.selection.cell[1]);
48686 onViewChange : function(){
48687 this.clearSelections(true);
48691 * Returns the currently selected cell,.
48692 * @return {Array} The selected cell (row, column) or null if none selected.
48694 getSelectedCell : function(){
48695 return this.selection ? this.selection.cell : null;
48699 * Clears all selections.
48700 * @param {Boolean} true to prevent the gridview from being notified about the change.
48702 clearSelections : function(preventNotify){
48703 var s = this.selection;
48705 if(preventNotify !== true){
48706 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
48708 this.selection = null;
48709 this.fireEvent("selectionchange", this, null);
48714 * Returns true if there is a selection.
48715 * @return {Boolean}
48717 hasSelection : function(){
48718 return this.selection ? true : false;
48722 handleMouseDown : function(e, t){
48723 var v = this.grid.getView();
48724 if(this.isLocked()){
48727 var row = v.findRowIndex(t);
48728 var cell = v.findCellIndex(t);
48729 if(row !== false && cell !== false){
48730 this.select(row, cell);
48736 * @param {Number} rowIndex
48737 * @param {Number} collIndex
48739 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
48740 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
48741 this.clearSelections();
48742 r = r || this.grid.dataSource.getAt(rowIndex);
48745 cell : [rowIndex, colIndex]
48747 if(!preventViewNotify){
48748 var v = this.grid.getView();
48749 v.onCellSelect(rowIndex, colIndex);
48750 if(preventFocus !== true){
48751 v.focusCell(rowIndex, colIndex);
48754 this.fireEvent("cellselect", this, rowIndex, colIndex);
48755 this.fireEvent("selectionchange", this, this.selection);
48760 isSelectable : function(rowIndex, colIndex, cm){
48761 return !cm.isHidden(colIndex);
48765 handleKeyDown : function(e){
48766 if(!e.isNavKeyPress()){
48769 var g = this.grid, s = this.selection;
48772 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
48774 this.select(cell[0], cell[1]);
48779 var walk = function(row, col, step){
48780 return g.walkCells(row, col, step, sm.isSelectable, sm);
48782 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
48788 newCell = walk(r, c-1, -1);
48790 newCell = walk(r, c+1, 1);
48794 newCell = walk(r+1, c, 1);
48797 newCell = walk(r-1, c, -1);
48800 newCell = walk(r, c+1, 1);
48803 newCell = walk(r, c-1, -1);
48806 if(g.isEditor && !g.editing){
48807 g.startEditing(r, c);
48814 this.select(newCell[0], newCell[1]);
48819 acceptsNav : function(row, col, cm){
48820 return !cm.isHidden(col) && cm.isCellEditable(col, row);
48823 onEditorKey : function(field, e){
48824 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
48827 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
48829 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
48832 }else if(k == e.ENTER && !e.ctrlKey){
48835 }else if(k == e.ESC){
48839 g.startEditing(newCell[0], newCell[1]);
48844 * Ext JS Library 1.1.1
48845 * Copyright(c) 2006-2007, Ext JS, LLC.
48847 * Originally Released Under LGPL - original licence link has changed is not relivant.
48850 * <script type="text/javascript">
48854 * @class Roo.grid.EditorGrid
48855 * @extends Roo.grid.Grid
48856 * Class for creating and editable grid.
48857 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
48858 * The container MUST have some type of size defined for the grid to fill. The container will be
48859 * automatically set to position relative if it isn't already.
48860 * @param {Object} dataSource The data model to bind to
48861 * @param {Object} colModel The column model with info about this grid's columns
48863 Roo.grid.EditorGrid = function(container, config){
48864 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
48865 this.getGridEl().addClass("xedit-grid");
48867 if(!this.selModel){
48868 this.selModel = new Roo.grid.CellSelectionModel();
48871 this.activeEditor = null;
48875 * @event beforeedit
48876 * Fires before cell editing is triggered. The edit event object has the following properties <br />
48877 * <ul style="padding:5px;padding-left:16px;">
48878 * <li>grid - This grid</li>
48879 * <li>record - The record being edited</li>
48880 * <li>field - The field name being edited</li>
48881 * <li>value - The value for the field being edited.</li>
48882 * <li>row - The grid row index</li>
48883 * <li>column - The grid column index</li>
48884 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
48886 * @param {Object} e An edit event (see above for description)
48888 "beforeedit" : true,
48891 * Fires after a cell is edited. <br />
48892 * <ul style="padding:5px;padding-left:16px;">
48893 * <li>grid - This grid</li>
48894 * <li>record - The record being edited</li>
48895 * <li>field - The field name being edited</li>
48896 * <li>value - The value being set</li>
48897 * <li>originalValue - The original value for the field, before the edit.</li>
48898 * <li>row - The grid row index</li>
48899 * <li>column - The grid column index</li>
48901 * @param {Object} e An edit event (see above for description)
48903 "afteredit" : true,
48905 * @event validateedit
48906 * Fires after a cell is edited, but before the value is set in the record.
48907 * You can use this to modify the value being set in the field, Return false
48908 * to cancel the change. The edit event object has the following properties <br />
48909 * <ul style="padding:5px;padding-left:16px;">
48910 * <li>editor - This editor</li>
48911 * <li>grid - This grid</li>
48912 * <li>record - The record being edited</li>
48913 * <li>field - The field name being edited</li>
48914 * <li>value - The value being set</li>
48915 * <li>originalValue - The original value for the field, before the edit.</li>
48916 * <li>row - The grid row index</li>
48917 * <li>column - The grid column index</li>
48918 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
48920 * @param {Object} e An edit event (see above for description)
48922 "validateedit" : true
48924 this.on("bodyscroll", this.stopEditing, this);
48925 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
48928 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
48930 * @cfg {Number} clicksToEdit
48931 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
48938 trackMouseOver: false, // causes very odd FF errors
48940 onCellDblClick : function(g, row, col){
48941 this.startEditing(row, col);
48944 onEditComplete : function(ed, value, startValue){
48945 this.editing = false;
48946 this.activeEditor = null;
48947 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
48949 var field = this.colModel.getDataIndex(ed.col);
48954 originalValue: startValue,
48961 if(String(value) !== String(startValue)){
48963 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
48964 r.set(field, e.value);
48965 delete e.cancel; //?? why!!!
48966 this.fireEvent("afteredit", e);
48969 this.fireEvent("afteredit", e); // always fir it!
48971 this.view.focusCell(ed.row, ed.col);
48975 * Starts editing the specified for the specified row/column
48976 * @param {Number} rowIndex
48977 * @param {Number} colIndex
48979 startEditing : function(row, col){
48980 this.stopEditing();
48981 if(this.colModel.isCellEditable(col, row)){
48982 this.view.ensureVisible(row, col, true);
48983 var r = this.dataSource.getAt(row);
48984 var field = this.colModel.getDataIndex(col);
48989 value: r.data[field],
48994 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
48995 this.editing = true;
48996 var ed = this.colModel.getCellEditor(col, row);
49001 ed.render(ed.parentEl || document.body);
49003 (function(){ // complex but required for focus issues in safari, ie and opera
49007 ed.on("complete", this.onEditComplete, this, {single: true});
49008 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
49009 this.activeEditor = ed;
49010 var v = r.data[field];
49011 ed.startEdit(this.view.getCell(row, col), v);
49012 }).defer(50, this);
49018 * Stops any active editing
49020 stopEditing : function(){
49021 if(this.activeEditor){
49022 this.activeEditor.completeEdit();
49024 this.activeEditor = null;
49028 * Ext JS Library 1.1.1
49029 * Copyright(c) 2006-2007, Ext JS, LLC.
49031 * Originally Released Under LGPL - original licence link has changed is not relivant.
49034 * <script type="text/javascript">
49037 // private - not really -- you end up using it !
49038 // This is a support class used internally by the Grid components
49041 * @class Roo.grid.GridEditor
49042 * @extends Roo.Editor
49043 * Class for creating and editable grid elements.
49044 * @param {Object} config any settings (must include field)
49046 Roo.grid.GridEditor = function(field, config){
49047 if (!config && field.field) {
49049 field = Roo.factory(config.field, Roo.form);
49051 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
49052 field.monitorTab = false;
49055 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
49058 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
49061 alignment: "tl-tl",
49064 cls: "x-small-editor x-grid-editor",
49069 * Ext JS Library 1.1.1
49070 * Copyright(c) 2006-2007, Ext JS, LLC.
49072 * Originally Released Under LGPL - original licence link has changed is not relivant.
49075 * <script type="text/javascript">
49080 Roo.grid.PropertyRecord = Roo.data.Record.create([
49081 {name:'name',type:'string'}, 'value'
49085 Roo.grid.PropertyStore = function(grid, source){
49087 this.store = new Roo.data.Store({
49088 recordType : Roo.grid.PropertyRecord
49090 this.store.on('update', this.onUpdate, this);
49092 this.setSource(source);
49094 Roo.grid.PropertyStore.superclass.constructor.call(this);
49099 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
49100 setSource : function(o){
49102 this.store.removeAll();
49105 if(this.isEditableValue(o[k])){
49106 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
49109 this.store.loadRecords({records: data}, {}, true);
49112 onUpdate : function(ds, record, type){
49113 if(type == Roo.data.Record.EDIT){
49114 var v = record.data['value'];
49115 var oldValue = record.modified['value'];
49116 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
49117 this.source[record.id] = v;
49119 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
49126 getProperty : function(row){
49127 return this.store.getAt(row);
49130 isEditableValue: function(val){
49131 if(val && val instanceof Date){
49133 }else if(typeof val == 'object' || typeof val == 'function'){
49139 setValue : function(prop, value){
49140 this.source[prop] = value;
49141 this.store.getById(prop).set('value', value);
49144 getSource : function(){
49145 return this.source;
49149 Roo.grid.PropertyColumnModel = function(grid, store){
49152 g.PropertyColumnModel.superclass.constructor.call(this, [
49153 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
49154 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
49156 this.store = store;
49157 this.bselect = Roo.DomHelper.append(document.body, {
49158 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
49159 {tag: 'option', value: 'true', html: 'true'},
49160 {tag: 'option', value: 'false', html: 'false'}
49163 Roo.id(this.bselect);
49166 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
49167 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
49168 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
49169 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
49170 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
49172 this.renderCellDelegate = this.renderCell.createDelegate(this);
49173 this.renderPropDelegate = this.renderProp.createDelegate(this);
49176 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
49180 valueText : 'Value',
49182 dateFormat : 'm/j/Y',
49185 renderDate : function(dateVal){
49186 return dateVal.dateFormat(this.dateFormat);
49189 renderBool : function(bVal){
49190 return bVal ? 'true' : 'false';
49193 isCellEditable : function(colIndex, rowIndex){
49194 return colIndex == 1;
49197 getRenderer : function(col){
49199 this.renderCellDelegate : this.renderPropDelegate;
49202 renderProp : function(v){
49203 return this.getPropertyName(v);
49206 renderCell : function(val){
49208 if(val instanceof Date){
49209 rv = this.renderDate(val);
49210 }else if(typeof val == 'boolean'){
49211 rv = this.renderBool(val);
49213 return Roo.util.Format.htmlEncode(rv);
49216 getPropertyName : function(name){
49217 var pn = this.grid.propertyNames;
49218 return pn && pn[name] ? pn[name] : name;
49221 getCellEditor : function(colIndex, rowIndex){
49222 var p = this.store.getProperty(rowIndex);
49223 var n = p.data['name'], val = p.data['value'];
49225 if(typeof(this.grid.customEditors[n]) == 'string'){
49226 return this.editors[this.grid.customEditors[n]];
49228 if(typeof(this.grid.customEditors[n]) != 'undefined'){
49229 return this.grid.customEditors[n];
49231 if(val instanceof Date){
49232 return this.editors['date'];
49233 }else if(typeof val == 'number'){
49234 return this.editors['number'];
49235 }else if(typeof val == 'boolean'){
49236 return this.editors['boolean'];
49238 return this.editors['string'];
49244 * @class Roo.grid.PropertyGrid
49245 * @extends Roo.grid.EditorGrid
49246 * This class represents the interface of a component based property grid control.
49247 * <br><br>Usage:<pre><code>
49248 var grid = new Roo.grid.PropertyGrid("my-container-id", {
49256 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49257 * The container MUST have some type of size defined for the grid to fill. The container will be
49258 * automatically set to position relative if it isn't already.
49259 * @param {Object} config A config object that sets properties on this grid.
49261 Roo.grid.PropertyGrid = function(container, config){
49262 config = config || {};
49263 var store = new Roo.grid.PropertyStore(this);
49264 this.store = store;
49265 var cm = new Roo.grid.PropertyColumnModel(this, store);
49266 store.store.sort('name', 'ASC');
49267 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
49270 enableColLock:false,
49271 enableColumnMove:false,
49273 trackMouseOver: false,
49276 this.getGridEl().addClass('x-props-grid');
49277 this.lastEditRow = null;
49278 this.on('columnresize', this.onColumnResize, this);
49281 * @event beforepropertychange
49282 * Fires before a property changes (return false to stop?)
49283 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
49284 * @param {String} id Record Id
49285 * @param {String} newval New Value
49286 * @param {String} oldval Old Value
49288 "beforepropertychange": true,
49290 * @event propertychange
49291 * Fires after a property changes
49292 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
49293 * @param {String} id Record Id
49294 * @param {String} newval New Value
49295 * @param {String} oldval Old Value
49297 "propertychange": true
49299 this.customEditors = this.customEditors || {};
49301 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
49304 * @cfg {Object} customEditors map of colnames=> custom editors.
49305 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
49306 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
49307 * false disables editing of the field.
49311 * @cfg {Object} propertyNames map of property Names to their displayed value
49314 render : function(){
49315 Roo.grid.PropertyGrid.superclass.render.call(this);
49316 this.autoSize.defer(100, this);
49319 autoSize : function(){
49320 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
49322 this.view.fitColumns();
49326 onColumnResize : function(){
49327 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
49331 * Sets the data for the Grid
49332 * accepts a Key => Value object of all the elements avaiable.
49333 * @param {Object} data to appear in grid.
49335 setSource : function(source){
49336 this.store.setSource(source);
49340 * Gets all the data from the grid.
49341 * @return {Object} data data stored in grid
49343 getSource : function(){
49344 return this.store.getSource();
49348 * Ext JS Library 1.1.1
49349 * Copyright(c) 2006-2007, Ext JS, LLC.
49351 * Originally Released Under LGPL - original licence link has changed is not relivant.
49354 * <script type="text/javascript">
49358 * @class Roo.LoadMask
49359 * A simple utility class for generically masking elements while loading data. If the element being masked has
49360 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
49361 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
49362 * element's UpdateManager load indicator and will be destroyed after the initial load.
49364 * Create a new LoadMask
49365 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
49366 * @param {Object} config The config object
49368 Roo.LoadMask = function(el, config){
49369 this.el = Roo.get(el);
49370 Roo.apply(this, config);
49372 this.store.on('beforeload', this.onBeforeLoad, this);
49373 this.store.on('load', this.onLoad, this);
49374 this.store.on('loadexception', this.onLoad, this);
49375 this.removeMask = false;
49377 var um = this.el.getUpdateManager();
49378 um.showLoadIndicator = false; // disable the default indicator
49379 um.on('beforeupdate', this.onBeforeLoad, this);
49380 um.on('update', this.onLoad, this);
49381 um.on('failure', this.onLoad, this);
49382 this.removeMask = true;
49386 Roo.LoadMask.prototype = {
49388 * @cfg {Boolean} removeMask
49389 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
49390 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
49393 * @cfg {String} msg
49394 * The text to display in a centered loading message box (defaults to 'Loading...')
49396 msg : 'Loading...',
49398 * @cfg {String} msgCls
49399 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
49401 msgCls : 'x-mask-loading',
49404 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
49410 * Disables the mask to prevent it from being displayed
49412 disable : function(){
49413 this.disabled = true;
49417 * Enables the mask so that it can be displayed
49419 enable : function(){
49420 this.disabled = false;
49424 onLoad : function(){
49425 this.el.unmask(this.removeMask);
49429 onBeforeLoad : function(){
49430 if(!this.disabled){
49431 this.el.mask(this.msg, this.msgCls);
49436 destroy : function(){
49438 this.store.un('beforeload', this.onBeforeLoad, this);
49439 this.store.un('load', this.onLoad, this);
49440 this.store.un('loadexception', this.onLoad, this);
49442 var um = this.el.getUpdateManager();
49443 um.un('beforeupdate', this.onBeforeLoad, this);
49444 um.un('update', this.onLoad, this);
49445 um.un('failure', this.onLoad, this);
49450 * Ext JS Library 1.1.1
49451 * Copyright(c) 2006-2007, Ext JS, LLC.
49453 * Originally Released Under LGPL - original licence link has changed is not relivant.
49456 * <script type="text/javascript">
49458 Roo.XTemplate = function(){
49459 Roo.XTemplate.superclass.constructor.apply(this, arguments);
49462 s = ['<tpl>', s, '</tpl>'].join('');
49464 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
49466 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
49467 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
49468 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
49472 while(m = s.match(re)){
49473 var m2 = m[0].match(nameRe);
49474 var m3 = m[0].match(ifRe);
49475 var m4 = m[0].match(execRe);
49476 var exp = null, fn = null, exec = null;
49477 var name = m2 && m2[1] ? m2[1] : '';
49479 exp = m3 && m3[1] ? m3[1] : null;
49481 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
49485 exp = m4 && m4[1] ? m4[1] : null;
49487 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
49492 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
49493 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
49494 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
49504 s = s.replace(m[0], '{xtpl'+ id + '}');
49507 for(var i = tpls.length-1; i >= 0; --i){
49508 this.compileTpl(tpls[i]);
49510 this.master = tpls[tpls.length-1];
49513 Roo.extend(Roo.XTemplate, Roo.Template, {
49515 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
49517 applySubTemplate : function(id, values, parent){
49518 var t = this.tpls[id];
49519 if(t.test && !t.test.call(this, values, parent)){
49522 if(t.exec && t.exec.call(this, values, parent)){
49525 var vs = t.target ? t.target.call(this, values, parent) : values;
49526 parent = t.target ? values : parent;
49527 if(t.target && vs instanceof Array){
49529 for(var i = 0, len = vs.length; i < len; i++){
49530 buf[buf.length] = t.compiled.call(this, vs[i], parent);
49532 return buf.join('');
49534 return t.compiled.call(this, vs, parent);
49537 compileTpl : function(tpl){
49538 var fm = Roo.util.Format;
49539 var useF = this.disableFormats !== true;
49540 var sep = Roo.isGecko ? "+" : ",";
49541 var fn = function(m, name, format, args){
49542 if(name.substr(0, 4) == 'xtpl'){
49543 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
49546 if(name.indexOf('.') != -1){
49549 v = "values['" + name + "']";
49551 if(format && useF){
49552 args = args ? ',' + args : "";
49553 if(format.substr(0, 5) != "this."){
49554 format = "fm." + format + '(';
49556 format = 'this.call("'+ format.substr(5) + '", ';
49560 args= ''; format = "("+v+" === undefined ? '' : ";
49562 return "'"+ sep + format + v + args + ")"+sep+"'";
49565 // branched to use + in gecko and [].join() in others
49567 body = "tpl.compiled = function(values, parent){ return '" +
49568 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
49571 body = ["tpl.compiled = function(values, parent){ return ['"];
49572 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
49573 body.push("'].join('');};");
49574 body = body.join('');
49576 /** eval:var:zzzzzzz */
49581 applyTemplate : function(values){
49582 return this.master.compiled.call(this, values, {});
49586 apply : function(){
49587 return this.applyTemplate.apply(this, arguments);
49590 compile : function(){return this;}
49593 Roo.XTemplate.from = function(el){
49594 el = Roo.getDom(el);
49595 return new Roo.XTemplate(el.value || el.innerHTML);